---
title: 小型 OLED 顯示裝置的原理與應用—PART 2
description: "**作者：Bird** 上篇文章[【Maker 電子學】小型 OLED 顯示裝置…"
url: "https://makerpro.cc/docs/principle-and-application-about-oled-part2/"
updated: "2025-05-09"
category: OLED
---

# 小型 OLED 顯示裝置的原理與應用—PART 2

**作者：Bird**

上篇文章[【Maker 電子學】小型 OLED 顯示裝置的原理與應用 — PART 1](https://makerpro.cc/2020/09/principle-and-application-about-oled-part1/)，我們從小型顯示裝置的老祖宗 LCD 開始，聊了用 SSD1306 OLED 控制 IC 驅動的小型 OLED 面板。這一回我們將繼續這個主題，要告訴讀者們如何將它連上 Arduino、Node MCU 等快速開發平台，並用軟體驅動它來顯示你想要的內容。

### **準備材料**

這次的實驗會用到兩個模組：Node MCU 以及 I^2C（以下寫作 I2C） 版本的 128x32 SSD1306 OLED 模組，這兩個模組現在都非常容易取得，價格也不貴，是做實驗的好幫手。

 ![](https://makerpro.cc/wp-content/uploads/2020/09/1601144071174.jpg)

（圖片來源：Bird 提供）

我們之所以選用以 ESP8266 爲核心的 NodeMCU，而不用標準的 Arduino 板子，是因爲 SD1366 只支援 3.3V 的邏輯準位，而標準的 Arduino 板子如 UNO 等，則是 5V 邏輯準位的系統。

ESP8266 是功能非常強大的 Wi-Fi SoC，不過我們這次只會把它當作 Arduino 的平台來使用，不會使用到任何其它的功能，因此讀者如果要用其它的 Arduino 平台如 Pro Micro 也可以，但要注意必須使用 3.3V 邏輯準位的版本，否則可能會導致 OLED 模組的損壞。

### **連接**

拜 SSD1306 簡潔的設計和完整性所賜，它可以很簡單地用 I2C 來控制，因此我們只要在這兩張板子之間連接 4 條線，分別是 VCC、GND、SCL、SDA。

ESP8266 並沒有硬體 I2C 界面，當它用 Arduino 開發時，I2C 是用軟體在 GPIO 上模擬出來的，因此理論上 NodeMCU 的任何兩支 GPIO 都可以拿來當 I2C 使用，只要在軟體啟動 I2C 界面時指定就好。如果沒有特別指定，預設的 I2C 接腳在 GPIO4 和 GPIO5，其中 GPIO4 是 SDA、GPIO5 是 SCL，我們就遵照這個慣例來連接。

 ![](https://makerpro.cc/wp-content/uploads/2020/09/1601144360845.jpg)

（圖片來源：Bird 提供）

我建議有焊接能力的讀者可以拿起烙鐵來，直接用鍍銀 OK 線或彩虹排線，焊 4 根線將它們連接起來，不必再用麵包板或杜邦跳線（通常確實而可靠的訊號連接是避免實驗失敗的重要因素，而品質不良的麪包板或是杜邦跳線，往往是不可靠連接的罪魁禍首）。

這裡要特別注意的是，NodeMCU 板子上標示的接腳編號如 D0、D1、D2 等，跟我們使用 Arduino 來驅動 NodeMCU 時的 GPIO 編號並不一致。事實上 NodeMCU 這個名字指的是另一個不同於 Arduino 的軟體開發平台，它使用一種叫「Lua」的程式語言來開發，但因爲 Arduino 實在太受歡迎、可攜性又高，因此大部分的人在 NodeMCU 板子上仍然使用 Arduino 做爲開發工具。 NodeMCU 板子上的接腳編號是在 NodeMCU 開發平台中的編號，它與 Arduino 的接腳編號對應關係列在上面那張圖中。

 ![](https://makerpro.cc/wp-content/uploads/2020/09/1601144551916.jpg)

（圖片來源：Bird 提供）

將兩張板子連接好之後，我們就可以寫程式來驅動它了。

### **站在巨人的肩膀上**

接下來我們會示範使用 Arduino 上的 library 來驅動這個 OLED 顯示器。

我們先到 Adruino IDE 的 Library Manager 中搜尋並新增這兩個 library：「Adadruit_SSD1306」以及 「Adafruit_GFX_Library」。熟悉 Arduino 的讀者對 Adafruit 這家公司應該不會太陌生，這是一間位於紐約的開源硬體公司，供應各種 maker 需要的模組、電子零件，也提供許多開發工具和開源的 library，我們這次使用的這兩個 library 就是由 Adafruit 提供的。

 ![](https://makerpro.cc/wp-content/uploads/2020/09/1601144661324.jpg)

（圖片來源：Bird 提供）

Adadruit_SSD1306 是用來驅動 SSD1306 的底層 library，它支援 I2C 和 SPI 界面與 SSD1306 通訊，並提供了控制 SSD1306 的基本功能如 register 和 frame buffer 讀寫等。而 Adafruit_GFX_Library 則是在顯示裝置上繪圖的核心 library，它提供了如顯示文字、劃線、幾何圖形等功能。

第一件事，我們要在程式碼中 include 所有需要的 library：

#include // I2C library
 #include // Adafruit graphics library
 #include // Adafruit SSD1306 library

除了上面介紹的兩個 library 外，我們還需要一個叫 Wire 的 library，這是 Adruino 標準的 I2C 通訊 library，不過我們不會直接使用它，當我們告訴 Adafruit_SSD1306 我們要用 I2C 當作與 SSD1306 通訊的界面之後，Adafruit_SSd1306 會自動去呼叫 Wire 相關的功能。

整個 Adafruit_SSd1306 中只有一個 class，就叫做 ，Adafruit_SSd1306。這個 class 有 6 個 constructor （其中 2 個已經不再使用），16 個 member function。其中 I2C 界面用的 constructor 長這個樣子：

 Adafruit_SSD1306::Adafruit_SSD1306 (
 uint8_t w,
 uint8_t h,
 TwoWire * twi = &amp;Wire,
 int8_t rst_pin = -1,
 uint32_t clkDuring = 400000UL,
 uint32_t clkAfter = 100000UL
 )

當我們建立 OLED 顯示器物件時，需要傳 5 個參數給它，分別是：顯示器的水平方向點數、垂直方向點數、指向 I2C 通訊界面的指標、reset 接腳的 GPIO 編號與 SSD1306 通訊時的 I2C bus 速度以及與 SSD1306 通訊完了之後的 I2C bus 速度。

於是在 setup() 和 main() 之前，我們要先用上面這個 constructor 建立一個叫做 my_display 的物件，用來代表 OLED 顯示器：

 Adafruit_SSD1306 my_display(128, 32, &amp;Wire, -1, 400, 100);

由於我們手上的 OLED 模組並沒有外接的 reset 接腳，因此 reset 接腳那一個參數填 -1，代表我們不去控制 reset 訊號。

接下來，在 setup() 中要執行的第一個指令，就是 Adafruit_SSD1306::begin() 這個 member function，它負責設定跟 SSD1306 有關的幾個重要參數，並初始化 SSD1306。這個 member function 需要 4 個參數：

 bool Adafruit_SSD1306::begin(
 uint8_t vcs = SSD1306_SWITCHCAPVCC,
 uint8_t addr = 0,
 bool reset = true,
 bool periphBegin = true
 )

第一個參數是設定 SSD1306 供應 OLED 面板電源的方式。SSD1306 需要一個 7~15V 的 VCC 電壓，用來驅動 OLED 面板，而 SSD1306 內建了 charge pump 升壓電路，可以由 3.3V 的邏輯電源產生 7.5V 的 VCC。在大部分的狀況下，我們都會建議使用這個內部的升壓電路來產生面板的電源，只有在很少的設計中我們會需要使用外部供應的 VCC。第一個參數設成 SSD1306_SWITCHCAPVCC 代表使用內建的升壓電路，設成 SSD1306_EXTERNALVCC 代表使用外部供應的 VCC 電源。

第二個參數是設定 SSD1306 的 I2C slave address（最近聽說 slave 這個字爭議很大啊！），SSD1306 可以用一根 pin 選擇 0x3c 或 0x3d 這兩個 I2C address，不過大部分的模組都沒有把這個接腳拉出來讓使用者選擇，因此 99% 的狀況下就只能用 0x3c 這個位址。填 0 就代表使用預設的 0x3c 這個位址。

第三個參數代表要不要驅動 reset pin，第四個參數代表要不要去呼叫 I2C library（也就是 Wire）的初始化 function。

於是這個指令寫起來就是這樣：

 my_display.begin(SSD1306_SWITCHCAPVCC, 0, false, true);

### **初試啼聲**

執行完這一行，SSD1306 就會被初始化，並開始驅動 OLED 面板，如果沒有意外，OLED 面板就會亮起來了，像這樣：

 ![](https://makerpro.cc/wp-content/uploads/2020/09/1601145289372.jpg)

（圖片來源：Bird 提供）

亮是亮了，但怎麼顯示了一些看起來亂七八糟的雜點呢？

不然你期望它顯示什麼？我們又沒告訴它要畫什麼，它當然就自由發揮啦！SSD1306 內部有一塊叫做 frame buffer 的記憶體，是用來儲存要顯示的內容的。而我們看到的這些雜點，就是供電後，這塊記憶體裡隨機的內容。

因此我們要把它清掉：

 my_display.clearDisplay();

但如果只加上這一行，畫面還是不會變。我們還需要這個指令：

 my_display.display();

GFX 這個繪圖 library 的運作方式是這樣：所有的繪圖動作都是先在 Arduino 系統內一塊記憶體 buffer 中操作。當你下達 .display() 時，它才會把記憶體中畫完的 buffer 透過通訊界面一次送到 SSD1306 的 frame buffer 中，讓 OLED 上的顯示更新。因此當我們執行 .clearDisplay() 時，它是先清掉中 buffer 的內容，等到我們執行 .display() 時，這個被清掉的內容才更新到 SSD1306 上。

### **Hello World！**

把顯示器上的雜點清乾淨之後，讓我們來寫幾個字吧！

GFX library 繼承了 Arduino 系統的 print() 和 println() 兩個 class，因此雖然它沒有這個 member function，我們也可以用 print() 和 println() 在顯示器上面寫字。不過在此之前，我們得先設定要顯示的字的顏色、大小、和位置：

 my_display.setTextSize(1);
 my_display.setCursor(0,0);
 my_display.setTextColor(1);

最後就可以用 print() 來顯示字串：

 my_display.print("Hello World!");

最後別忘了要把內容更新到顯示器上：

 my_display.display();

於是就完成了我們在 OLED 顯示器上的 Hello World！

 ![](https://makerpro.cc/wp-content/uploads/2020/09/1601145537585.jpg)

（圖片來源：Bird 提供）

GFX library 還有非常非常多的功能，它可以畫線、畫圓、畫矩形、填色，也可以使用不同的字型顯示文字。Adafruit 提供了非常完整的文件和範例程式，有興趣的讀者可以搜尋相關的資料，所有 library 的原始碼在 GitHub 上也看得到。

### **小結**

這一次我們將 SSD1306 的 OLED 顯示器模組和 NodeMCU 連接起來，並用了 Adafruit 在 Arduino 上提供的 library，示範了一個非常簡單的例子：在 128x32 的 OLED 顯示器上寫出 “Hello World!”。下一回，我們要更深入地探討 SSD1306 內部運作的方式，讀者們便可以更深入地了解到 Adafruit 所提供的 library 幫我們做了什麼事。

這一次完整的程式碼附於文末：

 #include &lt;Wire.h&gt; // I2C library
 #include &lt;Adafruit_GFX.h&gt; // Adafruit graphics library
 #include &lt;Adafruit_SSD1306.h&gt; // Adafruit SSD1306 library for OLED panel

 Adafruit_SSD1306 my_display(128, 32, &amp;Wire, -1, 400, 100);

 void setup() {
 my_display.begin(SSD1306_SWITCHCAPVCC, 0, false, true);
 my_display.clearDisplay();

 my_display.setTextSize(2);
 my_display.setCursor(0,0);
 my_display.setTextColor(1);
 my_display.print("Hello World!");
 my_display.display();
 }

 void loop() {

 }

（責任編輯：賴佩萱）
