Arduino/ESP 程式執行期間要顯示訊息,開發測試期間時可用 Serial.print() 走 USB 線傳回電腦端。實務執行時不可能永遠連著電腦只為了收訊息,一般會外接個小螢幕,古早時代最常用的是照片裡的 1602 液晶螢幕:

thumbnail

內建 I2C 模組的版本只要接四條電線就能動,但它最多只能顯示兩行 16 共 32 個字元,呈現資訊量有限,加上只能顯示英數字符號無法繪圖(即便可以,解析度也低到慘不忍睹),不算好用。

時代在進步,現在可以很容易找到下面這種解析度 128x64 的 OLED 顯示器(SSD1306),價格親民,網拍上 85 元可以買到。一樣內建 I2C 介面四線搞定,預設 6x8 字型一個畫面可以塞進 21x8 = 168 個英數字及符號,配合程式庫還支援各式繪圖功能,頗為實用:

thumbnail

要驅動 SSD1306 必須靠程式庫,大家最常用的非 Adafruit_SSD1306 莫屬,它提供一整套標準繪圖函數(drawLine()、fillRect()... 等一應俱全),還支援 print()、println() 會依字串長度、字型大小拆行,遇到 \n 也會換行,非常方便。但有個缺點 - Adafuit_SSD1306 在列印到螢幕下緣時不會自動往上捲,而是忽略不顯示。

「列印文字超出螢幕範圍要自動往上捲」對一般人來說是天經地義的要求,但在 Arduino/ESP 的世界裡未必。受限於記憶體、運算能力,程式庫通常力求精簡,只放最必要的功能。對寫慣 C#、JavaScript 等高階語言的我來說,改寫 Arduino/ESP 程式帶來最大的衝擊 - 像是養尊處優的城市佬從大都市搬進超級原始的鄉間。以前打開水龍頭就有水、開燈就有光,生活所需隨手可得;現在則得去河邊提水,想省力得自己挖井,吃頓飯要先砍柴生火,生活艱困 N 倍。

我非常想用 OLED 取代 Serial.print(),希望能做到無腦列印偵錯訊息時超出螢幕會自動上捲,但 Adafruit_SSD1306 不支援。試著找替代方案,找到一些網友分享的實作,但就可靠度及功能性,Adafruit 的版本還是讓人較有信心。難道沒有人想過在 Adafruit_SSD1306 加入自動上捲功能?其實有,甚至好幾位網友已發了 PR:Added scrolling capabilityadded scrollUP() to automatically scroll a display when println() is usedAdded autoscrolling,不過可能因為存在版本衝突或其他原因沒被接受。原本想直接改用網友的修改版,但大多有動到另一個專案 Adafruit_GFX,我嫌幅度偏大。我自己的修改哲學通常會避免異動既有邏輯,以微創手術為目標,還會盡可能外加不修改維持相容性。評估之後,我也 Fork 了一份,試著寫了自己理想的版本 - https://github.com/darkthread/Adafruit_SSD1306

我沒有修改核心讓 print()、println() 就地支援自動上捲,而是另外定義 void ttyPrint(String text) 及 void ttyPrintln(String text) 額外提供自動上捲版本的字串列印,print()、println() 原本支援傳入各種資料型別,要全部實作工程太大,我偷懶把參數型別限縮到 String 一種,如有需要, 將數字、bool 先轉成 String 即可,不算複雜。

寫了一小段程式實測:

#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_I2CDevice.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_ADDRESS 0x3C 
Adafruit_SSD1306 display(128, 64, &Wire, -1);

void setup()
{
  Serial.begin(115200);
  while (!Serial) { }
  //Wire.setPins(26, 27); //for ESPro Matrix board

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS))
  {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;)
      ; // Don't proceed, loop forever
  }

  // Clear the buffer
  display.display();
  delay(2500);
  display.setTextColor(WHITE, BLACK);
  display.setCursor(0, 56);
  display.ttyPrintln();
  delay(1000);
  for (int i = 0; i < 256; i++) {
    display.ttyPrint(" " + String(i));
    display.display();
    delay(20);
  }
  display.ttyPrintln();
  display.display();
}
int count = 1;
void loop()
{
  display.ttyPrintln("line - " + String(count++));
  display.display();
  delay(500);
}

執行效果如下,未來要連續輸出文字到 OLED,用 ttyPrintln() 會方便很多。

程式都寫好了,就順手分享給有需求的朋友。如果你是用 VSCode + PlatformIO 開發,只需修改 platformio.ini 將 adafruit/Adafruit SSD1306@^2.4.4 換成 https://github.com/darkthread/Adafruit_SSD1306 ,馬上多出 ttyPrint() 及 ttyPrintln() 可用:

程式今天剛寫好,我初步測試沒什麼問題,就當成開放公測好了,大家使用上如發現異常請再回報給我。

Adding TTY style auto scrollup version of print and println to Adafruit_SSD1306 library.


Comments

Be the first to post a comment

Post a comment