[第六課] OLED顯示原理 (I2C)

人生很窄,得失只在方寸間;人生很寬,成敗猶在千里外。~魯迅

話說,嵌入式系統的設計,貴在精巧且反應敏捷;我們再複習一下,Seeeduino XIAO這主控板可支援一組 SPI D2 D8 D9 D10 (連接NFC ReWriter模組)、一組 I2C D4 D5 (連接OLED顯示器模組與RTC)、與一組 UART D6 D7 (連接DFPlayer Mini模組);雖然對目前的應用可說是剛剛好,但也沒有多餘的輸入端子來做互動,必須仰仗NFC標籤的感應來操控。所以這組OLED顯示器就有舉足輕重的溝通角色,負責顯示本機狀態、目前時間、播放模式與音軌的目錄與曲目編號...等。

在引用連接時,除使用 u8g2lib 外,也要啟動 I2C 的通訊:

#include <U8g2lib.h>
#ifdef U8X8_HAVE_HW_I2C
  #include <Wire.h>
#endif

/* OLED Display via I2C*/
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
  
然後,在 setup() 時,啟用:

u8g2.begin();  
u8g2.enableUTF8Print(); 


OLED顯示器 其實是點陣式,有 128 x 64 點的解析度。也就是說,你看到的英文文字,其實是一點一點『畫』上去的;而每個圖案或文字都是由不同尺寸的字型庫所描述那『一點一點』的內容。就舉上面的例子,這個名為 u8g2_font_open_iconic_app_4x_t 的字型檔,是存放 32x32 點的圖案的點陣資料,其字型編碼自#64開始;我們會用到時鐘的圖示,取用方法如下:

case TIME:
      u8g2.setFont(u8g2_font_open_iconic_app_4x_t);
      u8g2.drawGlyph(x, y, 69);
      break;

因為時鐘圖示的字型編碼是 #69 (從頭算來第6個),所以就表示在螢幕座標 (x,y) 的位置,使用drawGlyph 畫上該圖像。如下圖所示,這 (x,y) 就是 (0,48);有關顯示的程式在 <Display.ino>,主要有兩種顯示的繪圖模式:一是『圖文混合』,另一是『多行文字』顯示。


先來看圖文混合模式,將螢幕分成上 (st)、中 (sr)、下 (ss) 三個區域,上與下為訊息標題與提示,均使用 u8g2_font_ncenB08_tr 的字型 (12x11);而中間區域依照訊息的種類(kind),會有不同的切割與規畫;如果以通用的 0xFF 型為例:前 32x32 作為圖像顯示,之後為通用的本文顯示:可以是曲目資訊、時間等。此例的下面還列出其他 0x010x020xF1 的三種模式,請自行參考。

來看一下 draw 的程式碼:

void draw(uint8_t symbol, byte kind)
{
    u8g2.firstPage();
    do {
      drawSTATE(symbol, kind);
      u8g2.setFont(u8g2_font_ncenB08_tr);
      u8g2.setCursor(0, 12);
      u8g2.print(st);
      u8g2.setCursor(0, 62);
      u8g2.print(ss);
      //drawScrollString(offset, s);
    } while ( u8g2.nextPage() );
    delay(20);
}

中間區域的顯示由 drawSTATE(symbol, kind) 負責。

剛才提到還有一種『多行文字』顯示的方式,其原理就是把中間的區域,再分割成三行文字顯示一樣是取用和上、下區相同的字型:

void drawTXT(String sl1, String sl2, String sl3)
{
    u8g2.firstPage();
    do {
      u8g2.setFont(u8g2_font_ncenB08_tr);
      u8g2.setCursor(0, 12);
      u8g2.print(st);
      u8g2.setCursor(0, 24);
      u8g2.print(sl1);
      u8g2.setCursor(0, 36);
      u8g2.print(sl2);
      u8g2.setCursor(0, 48);
      u8g2.print(sl3);
      u8g2.setCursor(0, 62);
      u8g2.print(ss);
    } while ( u8g2.nextPage() );
}

最後,要提醒一下,考慮到人類視覺暫留的時間,更新完螢幕的顯示後,別忘了Delay至少300ms的時間:

draw(TRK, 0x01); //以0x01類顯示“TRK"曲目資訊。
delay(2000); //因為歌曲已經開始播放,此處暫停兩秒無妨。

下回見。 

留言

熱門文章