玩轉u8g2 OLED庫,一篇就夠

文章目錄

1.前言

    最近博主聽到QQ羣裏面問得比較多的問題:
    “博哥,有玩過OLED嗎?”
    “博哥,有試過在ESP8266上調成功過SSD1306嗎?”
    “博哥,OLED上顯示天氣信息怎麼弄?”
    …
    諸如此類的問題,在博主看來,無非都是對OLED庫用法的不熟悉甚至不瞭解。Arduino OLED庫衆多,博主也曾經介紹過一款 《博哥OLED系列》- 玩轉SSD1306-12864 OLED Adafruit_GFX 和 Adafruit_SSD1306庫。但是,博主今天要介紹的是目前Arduino平臺上使用最廣泛的OLED庫 —— U8G2庫,也是很多初學者容易懵逼的一個第三方庫。目前在github上超過1K star,1800次commit,可以說維護熱度很高,讀者大可放心使用。
    至於這個庫爲什麼這麼火爆,請讀者認真看完本博文自行評價,博主只能說功能真的很好很強大!!!!
    那麼,博主首先立個flag,閱讀完本篇博文的最終效果——讀者以後在Arduino平臺上開發OLED項目的時候,可以考慮U8G2庫,並且知道U8G2庫的具體用法,甚至可以能夠當做工具書來翻閱。
    進入正文之前,博主要給讀者灌輸兩個個非常重要的知識點:

  • 其一 像素點點陣
OLED其實就是一個M x n 的像素點陣,想顯示什麼就得把具體位置的像素點亮起來。對於每一個像素點,有可能是1點亮,也有可能是0點亮;
  • 其二 座標系

image

    在座標系中,左上角是原點,向右是X軸,向下是Y軸。

    希望讀者能仔細理解這兩個知識點。

2.U8g2簡介

2.1 U8g2是什麼

    U8g2是嵌入式設備的單色圖形庫,一句話簡單明瞭。主要應用於嵌入式設備,包括我們常見的單片機;

2.2 U8g2支持的顯示控制器

    U8g2支持單色OLED和LCD,包括以下控制器:SSD1305,SSD1306,SSD1309,SSD1322,SSD1325,SSD1327,SSD1329,SSD1606,SSD1607,SH1106,SH1107,SH1108,SH1122,T6963,RA8835,LC7981,PCD8544,PCF8812,HX1230 ,UC1601,UC1604,UC1608,UC1610,UC1611,UC1701,ST7565,ST7567,ST7588,ST75256,NT7534,IST3020,ST7920,LD7032,KS0108,SED1520,SBN1661,IL3820,MAX7219(有關完整列表,請參見 此處)。
    可以說,基本上主流的顯示控制器都支持,比如我們常見的SSD1306 12864,讀者在使用該庫之前請查閱自己的OLED顯示控制器是否處於支持列表中

2.2 U8g2支持的Arduino主板

    可以說基本上所有Arduino API的主板都得到U8g2的支持。包括:

  • Aruino Zero,Uno,Mega,Due,101,MKR Zero以及所有其他Arduino官方主板
  • 基於Arduino平臺的STM32
  • 基於Arduino平臺的ESP8266和ESP32
  • 甚至其他不知名的基於Arduino平臺的開發板

    所以說,讀者完全不用擔心兼容性問題,放心使用。

2.3 U8g2如何在Arduino平臺上安裝

    Arduino庫U8g2可以從Arduino IDE的庫管理器安裝,讀者在庫管理器搜索“U8g2”關鍵字就可以下載安裝:

image

    下載完畢,測試一下庫是否安裝成功:

#include <U8g2lib.h>
void setup() {
  // put your setup code here, to run once:
}

void loop() {
  // put your main code here, to run repeatedly:
}

    編譯成功,證明你本地已經加載了U8G2庫。

2.4 U8g2的優勢

    爲什麼要運用U8g2庫?也就是說U8g2庫能帶給我們什麼樣的開發便利。在博主看來,主要考慮幾個方面:

  • U8g2庫平臺支持性好,基本上支持絕大部分Arduino開發板,特別也博主比較喜歡的ESP8266;
  • U8g2庫顯示控制器支持性好,基本上市面上的OLED都完美支持;
  • U8g2庫 API衆多,特別支持了中文,支持了不同字體,這是一個對於開發者倆說不小的福利。

    以下是官方提供的一些U8G2庫測試圖,博主挑選了幾張常見的以及附上U8G2庫的配置(讀者可以先不用理會配置,等看完博文再次閱讀就會了解含義):

  • ESP32 and SSD1306 OLED
    image
U8G2_SSD1306_128X64_NONAME_1_SW_I2C u8g2(U8G2_R2, /* clock=*/ 16, /* data=*/ 17, /* reset=*/ U8X8_PIN_NONE);   // ESP32 Thing, pure SW emulated I2C
U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R2, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ 16, /* data=*/ 17);   // ESP32 Thing, HW I2C with pin remapping
  • MAX7219 32x8 LED Matrix
    image
U8G2_MAX7219_32X8_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 11, /* data=*/ 12, /* cs=*/ 10, /* dc=*/ U8X8_PIN_NONE, /* reset=*/ U8X8_PIN_NONE);
  • SSD1305 128x32
    image
U8G2_SSD1305_128X32_NONAME_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
  • SSD1306 128x32
    image
U8X8_SSD1306_128X32_UNIVISION_SW_I2C u8x8(/* clock=A5*/ 19, /* data=A4*/ 18);
  • PCD8544 84x48 (Nokia 5110) LCD
    image
U8G2_PCD8544_84X48_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);	// Nokia 5110 Display
  • ST7920 128x64 LCD in 8080 parallel mode
    image
U8G2_ST7920_128X64_1_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18 /* A4 */, /*cs=*/ U8X8_PIN_NONE, /*dc/rs=*/ 17 /* A3 */, /*reset=*/ 15 /* A1 */);	// Remember to set R/W to 0 

    這只是一些常見的顯示器,可以說,已經足夠覆蓋到我們常見的範圍了。

3.U8g2庫詳解

3.1 U8g2庫百度腦圖

老規則,先上一個圖:
image

方法可以分爲四大類:

  • 基本函數
  • 繪製相關函數
  • 顯示配置相關函數
  • 緩存相關函數

3.2 U8g2庫函數詳解

3.2.1 基本函數

3.2.1.1 u8g2.begin() —— 構造U8G2

函數說明:

/**
 * 初始化U8g2庫
 * @Note 關聯方法 initDisplay clearDisplay setPowerSave
 */
bool U8G2::begin(void)

源碼說明:

bool begin(void) {
/* note: call to u8x8_utf8_init is not required here, this is done in the setup procedures before */
   initDisplay(); //初始化顯示器
   clearDisplay();  // 重置清屏
   setPowerSave(0); //喚醒屏幕
   return 1;
}

3.2.1.2 u8g2.beginSimple() —— 構造U8G2

函數說明:

/**
 * 簡單初始化U8g2庫
 * @Note 關聯方法 beginSimple
 */
void U8G2::beginSimple(void);

源碼說明:

void beginSimple(void) {
/* does not clear the display and does not wake up the display */
/* user is responsible for calling clearDisplay() and setPowerSave(0) */
   initDisplay();//初始化顯示器
}

注意點:

  • 讀者可以看到和begin()函數的區別,需要用戶自行控制初始化過程,給了一定的自由度,不過博主建議大家還是直接用begin函數吧。

3.2.1.3 u8g2.initDisplay() —— 初始化顯示控制器

函數說明:

/**
 * 初始化顯示控制器
 */
void U8G2::initDisplay(void)

注意點:

  • 這個方法不需要我們單獨調用,會在begin函數主動調用一次,我們主要理解即可,會在裏面針對具體的OLED進行配置;

3.2.1.4 u8g2.clearDisplay() —— 清除屏幕內容

函數說明:

/**
 * 清除屏幕
 */
void U8G2::clearDisplay(void)

注意點:

  • 這個方法不需要我們單獨調用,會在begin函數主動調用一次,我們主要理解即可;
  • 不要在 firstPage 和 nextPage 函數之間調用該方法;

3.2.1.5 u8g2.setPowerSave() —— 是否開啓省電模式

函數說明:

/**
 * 清除顯示緩衝區
 * @param is_enable
 *        1 表示啓用顯示器的省電模式,屏幕上看不到任何東西
 *        0 表示禁用省電模式
 */
void U8G2::setPowerSave(uint8_t is_enable)

注意點:

  • 不管是啓用還是禁用,顯示器需要的內存消耗是不會變的,說到底就是爲了關閉屏幕,做到省電;
  • 所以這裏就可以理解爲什麼初始化需要 setPowerSave(0);

3.2.1.6 u8g2.clear() —— 清除操作

函數說明:

/**
 * 清除屏幕顯示,清除緩衝區,光標回到左上角原點位置(0,0)
 * @Note 關聯方法 home clearDisplay clearBuffer
 */
void U8G2::clear(void)

源碼說明:

void clear(void) { 
   home(); //回到原點
   clearDisplay(); //清除屏幕上的顯示
   clearBuffer();  //清除緩衝區
}

3.2.1.7 u8g2.clearBuffer() —— 清除緩衝區

函數說明:

/**
 * 清除內存中數據緩衝區
 */
void U8G2::clearBuffer(void)

注意點:

  • 一般這個函數是與sendBuffer函數配對使用,通常用法如下:
void loop(void) {
  u8g2.clearBuffer();
  // ... write something to the buffer 
  u8g2.sendBuffer();
  delay(1000);
}

3.2.1.8 u8g2.disableUTF8Print() —— 禁用 UTF8打印

函數說明:

/**
 * 禁用Arduino平臺下支持輸出UTF8字符集,默認是開啓
 */
void U8G2::disableUTF8Print(void)

3.2.1.9 u8g2.enableUTF8Print() —— 啓用 UTF8打印

函數說明:

/**
 * 開啓Arduino平臺下支持輸出UTF8字符集
 */
void U8G2::enableUTF8Print(void)

注意點:

  • 我們的中文字符就是UTF8;
  • 常見例子
void setup(void) {
  u8g2.begin();
  u8g2.enableUTF8Print();		// enable UTF8 support for the Arduino print() function
}
void loop(void) {
  u8g2.setFont(u8g2_font_unifont_t_chinese2);  // use chinese2 for all the glyphs of "你好世界"
  u8g2.firstPage();
  do {
    u8g2.setCursor(0, 40);
    u8g2.print("你好世界");		// Chinese "Hello World" 
  } while ( u8g2.nextPage() );
  delay(1000);
}

3.2.1.10 u8g2.home() —— 重置顯示光標的位置

函數說明:

/**
 * 重置顯示光標的位置,回到原點(0,0)
 * @Note 關聯方法 print clear
 */
void U8G2::home(void)

3.2.2 繪製相關函數

3.2.2.1 u8g2.drawBox() —— 畫實心方形

函數說明:

/**
 * 畫實心方形,左上角座標爲(x,y),寬度爲w,高度爲h
 * @param x 左上角的x座標
 * @param y 左上角的y座標
 * @param w 方形的寬度
 * @param h 方形的高度
 * @Note 關聯方法 drawFrame setDrawColor
 */
void U8G2::drawBox(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h)

注意點:

  • 如果支持繪製顏色(也就是不是單色顯示器),那麼由setDrawColor設置;

示例:

u8g2.drawBox(3,7,25,15);

image

3.2.2.2 u8g2.drawCircle() —— 畫空心圓

函數說明:

/**
 * 畫空心圓,圓心座標爲(x0,y0),半徑爲rad
 * @param x0 圓點的x座標
 * @param y0 圓點的y座標
 * @param rad 圓形的半徑
 * @param opt 圓形選項
 *        U8G_DRAW_ALL 整個圓
 *        U8G2_DRAW_UPPER_RIGHT 右上部分的圓弧
 *        U8G2_DRAW_UPPER_LEFT  左上部分的圓弧
 *        U8G2_DRAW_LOWER_LEFT  左下部分的圓弧
 *        U8G2_DRAW_LOWER_RIGHT 右下部分的圓弧
 *        選項可以通過 | 操作符來組合
 * @Note 關聯方法 drawDisc setDrawColor
 */
void U8G2::drawCircle(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rad, uint8_t opt = U8G2_DRAW_ALL)

注意點:

  • 如果支持繪製顏色(也就是不是單色顯示器),那麼由setDrawColor設置;
  • 直徑等於2rad + 1;

示例:

u8g2.drawCircle(20, 25, 10, U8G2_DRAW_ALL);

image

3.2.2.3 u8g2.drawDisc() —— 畫實心圓

函數說明:

/**
 * 畫實心圓,圓心座標爲(x0,y0),半徑爲rad
 * @param x0 圓點的x座標
 * @param y0 圓點的y座標
 * @param rad 圓形的半徑
 * @param opt 圓形選項
 *        U8G_DRAW_ALL 整個圓
 *        U8G2_DRAW_UPPER_RIGHT 右上部分的圓弧
 *        U8G2_DRAW_UPPER_LEFT  左上部分的圓弧
 *        U8G2_DRAW_LOWER_LEFT  左下部分的圓弧
 *        U8G2_DRAW_LOWER_RIGHT 右下部分的圓弧
 *       選項可以通過 | 操作符來組合
 * @Note 關聯方法 drawCircle setDrawColor
 */
void U8G2::drawDisc(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rad, uint8_t opt = U8G_DRAW_ALL)

注意點:

  • 如果支持繪製顏色(也就是不是單色顯示器),那麼由setDrawColor設置;
  • 直徑等於2rad + 1;

3.2.2.4 u8g2.drawEllipse() —— 畫空心橢圓

函數說明:

/**
 * 畫空心橢圓,圓心座標爲(x0,y0),半徑爲rad
 * @param x0 圓點的x座標
 * @param y0 圓點的y座標
 * @param rx 橢圓形水平x方向的半徑
 * @param ry 橢圓形豎直y方向的半徑
 * @param opt 圓形選項
 *        U8G_DRAW_ALL 整個橢圓
 *        U8G2_DRAW_UPPER_RIGHT 右上部分的圓弧
 *        U8G2_DRAW_UPPER_LEFT  左上部分的圓弧
 *        U8G2_DRAW_LOWER_LEFT  左下部分的圓弧
 *        U8G2_DRAW_LOWER_RIGHT 右下部分的圓弧
 *        選項可以通過 | 操作符來組合
 * @Note 關聯方法 drawCircle
 */
void U8G2::drawEllipse(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rx, u8g2_uint_t ry, uint8_t opt)

注意點:

  • rx*ry 在8位模式的u8g2必須小於512(博主暫且沒有理解);

示例:

u8g2.drawEllipse(20, 25, 15, 10, U8G2_DRAW_ALL);

image

3.2.2.5 u8g2.drawFilledEllipse() —— 畫實心橢圓

函數說明:

/**
 * 畫實心橢圓,圓心座標爲(x0,y0),半徑爲rad
 * @param x0 圓點的x座標
 * @param y0 圓點的y座標
 * @param rx 橢圓形水平x方向的半徑
 * @param ry 橢圓形豎直y方向的半徑
 * @param opt 圓形選項
 *        U8G_DRAW_ALL 整個橢圓
 *        U8G2_DRAW_UPPER_RIGHT 右上部分的圓弧
 *        U8G2_DRAW_UPPER_LEFT  左上部分的圓弧
 *        U8G2_DRAW_LOWER_LEFT  左下部分的圓弧
 *        U8G2_DRAW_LOWER_RIGHT 右下部分的圓弧
 *        選項可以通過 | 操作符來組合
 * @Note 關聯方法 drawCircle
 */
void U8G2::drawFilledEllipse(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rx, u8g2_uint_t ry, uint8_t opt)

注意點:

  • rx*ry 在8位模式的u8g2必須小於512(博主暫且沒有理解);

3.2.2.6 u8g2.drawFrame() —— 畫空心方形

函數說明:

/**
 * 畫空心方形,左上角座標爲(x,y),寬度爲w,高度爲h
 * @param x 左上角的x座標
 * @param y 左上角的y座標
 * @param w 方形的寬度
 * @param h 方形的高度
 * @Note 關聯方法 setDrawColor
 */
void U8G2::drawFrame(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h)

注意點:

  • 如果支持繪製顏色(也就是不是單色顯示器),那麼由setDrawColor設置;

示例:

u8g2.drawFrame(3,7,25,15);

image

3.2.2.7 u8g2.drawGlyph() —— 繪製字體字集的符號

函數說明:

/**
 * 繪製字體字集裏面定義的符號
 * @param x 左上角的x座標
 * @param y 左上角的y座標
 * @param encoding 字符的unicode值
 * @Note 關聯方法 setFont
 */
void U8G2::drawGlyph(u8g2_uint_t x, u8g2_uint_t y, uint16_t encoding)

注意點:

  • U8g2支持16位以內的unicode字符集,也就是說encoding的範圍爲0-65535,drawGlyph方法只能繪製存在於所使用的字體字集中的unicode值;
  • 這個繪製方法依賴於當前的字體模式和繪製顏色;

3.2.2.8 u8g2.drawHLine() —— 繪製水平線

函數說明:

/**
 * 繪製水平線
 * @param x 左上角的x座標
 * @param y 左上角的y座標
 * @param w 水平線的長度
 * @Note 關聯方法 setDrawColor
 */
 void U8G2::drawHLine(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w)

注意點:

  • 如果支持繪製顏色(也就是不是單色顯示器),那麼由setDrawColor設置;

3.2.2.9 u8g2.drawLine() —— 兩點之間繪製線

函數說明:

/**
 * 繪製線,從座標(x0,y0) 到(x1,y1)
 * @param x0 端點0的x座標
 * @param y0 端點0的y座標
 * @param x1 端點1的x座標
 * @param y1 端點1的y座標
 * @Note 關聯方法 setDrawColor
 */
 void U8G2::drawLine(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t x1, u8g2_uint_t y1)

注意點:

  • 如果支持繪製顏色(也就是不是單色顯示器),那麼由setDrawColor設置;

示例:

u8g2.drawLine(20, 5, 5, 32);

image

3.2.2.10 u8g2.drawPixel() —— 繪製像素點

函數說明:

/**
 * 繪製像素點,座標(x,y)
 * @param x 像素點的x座標
 * @param y 像素點的y座標
 * @Note 關聯方法 setDrawColor
 */
void U8G2::drawPixel(u8g2_uint_t x, u8g2_uint_t y)

注意點:

  • 如果支持繪製顏色(也就是不是單色顯示器),那麼由setDrawColor設置;
  • 你會發現很多繪製方法的底層都是調用drawPixel,畢竟像素屬於最小顆粒度;
  • 我們可以利用這個繪製方法自定義自己的圖形顯示;

3.2.2.11 u8g2.drawRBox() —— 繪製圓角實心方形

函數說明:

/**
 * 繪製圓角實心方形,左上角座標爲(x,y),寬度爲w,高度爲h,圓角半徑爲r
 * @param x 左上角的x座標
 * @param y 左上角的y座標
 * @param w 方形的寬度
 * @param h 方形的高度
 * @param r 圓角半徑
 */
void U8G2::drawRBox(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h, u8g2_uint_t r)

注意點:

  • 如果支持繪製顏色(也就是不是單色顯示器),那麼由setDrawColor設置;
  • 要求,w >= 2*(r+1) 並且 h >= 2*(r+1),這是顯而易見的限制;

3.2.2.12 u8g2.drawRFrame() —— 繪製圓角空心方形

函數說明:

/**
 * 繪製圓角空心方形,左上角座標爲(x,y),寬度爲w,高度爲h,圓角半徑爲r
 * @param x 左上角的x座標
 * @param y 左上角的y座標
 * @param w 方形的寬度
 * @param h 方形的高度
 * @param r 圓角半徑
 */
void U8G2::drawRFrame(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h, u8g2_uint_t r)

注意點:

  • 如果支持繪製顏色(也就是不是單色顯示器),那麼由setDrawColor設置;
  • 要求,w >= 2*(r+1) 並且 h >= 2*(r+1),這是顯而易見的限制

示例:

u8g2.drawRFrame(20,15,30,22,7);

image

3.2.2.13 u8g2.drawStr() —— 繪製字符串

函數說明:

/**
 * 繪製字符串
 * @param x 左上角的x座標
 * @param y 左上角的y座標
 * @param s 繪製字符串內容
 * @return 字符串的長度
 */
u8g2_uint_t U8g2::drawStr(u8g2_uint_t x, u8g2_uint_t y, const char *s) 

注意點:

  • 需要先設置字體,調用setFont方法;
  • 這個方法不能繪製encoding超過256的,超過256需要用drawUTF8或者drawGlyph;說白了就是一般用來顯示英文字符;
  • x,y屬於字符串左下角的座標;

示例:

u8g2.setFont(u8g2_font_ncenB14_tr);
u8g2.drawStr(0,15,"Hello World!");

image

3.2.2.14 u8g2.drawTriangle() —— 繪製實心三角形

函數說明:

/**
 * 繪製實心三角形,定點座標分別爲(x0,y0),(x1,y1),(x2,y2)
 */
void U8G2::drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2) 

示例:

u8g2.drawTriangle(20,5, 27,50, 5,32);

image

3.2.2.15 u8g2.drawUTF8() —— 繪製UTF8編碼的字符

函數說明:

/**
 * 繪製UTF8編碼的字符串
 * @param x 字符串在屏幕上的左下角x座標
 * @param y 字符串在屏幕上的左下角y座標
 * @param s 需要繪製的UTF-8編碼字符串
 * @return 返回字符串的長度
 */
u8g2_uint_t U8g2::drawUTF8(u8g2_uint_t x, u8g2_uint_t y, const char *s)

注意點:

  • 使用該方法,有兩個前提。首先是你的編譯器需要支持UTF-8編碼,對於絕大部分Arduino板子已經支持;其次,顯示的字符串需要存爲“UTF-8”編碼,Arduino IDE上默認支持;
  • 該方法需要依賴於fontMode(setFont)以及drawing Color,也就是說如果你傳進來的字符串編碼必須在font定義裏面;

示例:

u8g2.setFont(u8g2_font_unifont_t_symbols);
u8g2.drawUTF8(5, 20, "Snowman: ☃");

image

3.2.2.16 u8g2.drawVLine() —— 繪製豎直線

函數說明:

/**
 * 繪製豎直線
 * @param x 左上角座標x
 * @param y 左上角座標y
 * @param h 高度
 */
void U8G2::drawVLine(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t h) 

3.2.2.17 u8g2.drawXBM()/drawXBMP() —— 繪製圖像

函數說明:

/**
 * 繪製圖像
 * @param x 左上角座標x
 * @param y 左上角座標y
 * @param w 圖形寬度
 * @param h 圖形高度
 * @param bitmap 圖形內容
 * @Note 關聯方法 setBitmapMode
 */
void U8G2::drawXBM(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h, const uint8_t *bitmap)
void U8G2::drawXBMP(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h, const uint8_t *bitmap) 

注意點:

  • drawXBM和drawXBMP區別在於 XBMP支持PROGMEM;

3.2.2.18 u8g2.firstPage()/nextPage() —— 繪製命令

函數說明:

/**
 * 繪製圖像
 */
void U8G2::firstPage(void)
uint8_t U8G2::nextPage(void)

注意點:

  • firstPage方法會把當前頁碼位置變成0;
  • 修改內容處於firstPage和nextPage之間,每次都是重新渲染所有內容;

優勢點:

  • 該方法消耗的ram空間,比sendBuffer消耗的ram空間要少;

示例:

  u8g2.firstPage();
  do {
    /* all graphics commands have to appear within the loop body. */    
    u8g2.setFont(u8g2_font_ncenB14_tr);
    u8g2.drawStr(0,20,"Hello World!");
  } while ( u8g2.nextPage() );

庫源碼解析:

void u8g2_FirstPage(u8g2_t *u8g2)
{
  if ( u8g2->is_auto_page_clear )
  {
    //清除緩衝區
    u8g2_ClearBuffer(u8g2);
  }
  //設置當前緩衝區的Tile Row 一個Tile等於8個像素點的高度
  u8g2_SetBufferCurrTileRow(u8g2, 0);
}

uint8_t u8g2_NextPage(u8g2_t *u8g2)
{
  uint8_t row;
  u8g2_send_buffer(u8g2);
  row = u8g2->tile_curr_row;
  row += u8g2->tile_buf_height;
  if ( row >= u8g2_GetU8x8(u8g2)->display_info->tile_height )
  {
    //如果row已經到達最後一行,觸發refreshDisplay調用,表示整個頁面已經刷完了
    u8x8_RefreshDisplay( u8g2_GetU8x8(u8g2) );
    return 0;
  }
  if ( u8g2->is_auto_page_clear )
  {
     //清除緩衝區
    u8g2_ClearBuffer(u8g2);
  }
  //不斷更新TileRow 這是非常關鍵的一步
  u8g2_SetBufferCurrTileRow(u8g2, row);
  return 1;
}

3.2.2.19 u8g2.print() —— 繪製內容

函數說明:

/**
 * 繪製內容
 * @Note 關聯方法  setFont setCursor enableUTF8Print
 */
void U8G2::print(...)

示例:

u8g2.setFont(u8g2_font_ncenB14_tr);
u8g2.setCursor(0, 15);
u8g2.print("Hello World!");

image

3.2.2.20 u8g2.sendBuffer() —— 繪製緩衝區的內容

函數說明:

/**
 * 繪製緩衝區的內容
 * @Note 關聯方法  clearBuffer
 */
void U8G2::sendBuffer(void)

注意點:

  • sendBuffer的RAM佔用空間大,需要結合構造器的buffer選項(請繼續往下看,先有個概念)使用;
  • 不管是fistPage、nextPage還是sendBuffer,都涉及到一個叫做 current page position的概念;

庫源碼解析:

void u8g2_SendBuffer(u8g2_t *u8g2)
{
  u8g2_send_buffer(u8g2);
  u8x8_RefreshDisplay( u8g2_GetU8x8(u8g2) );  
}

static void u8g2_send_tile_row(u8g2_t *u8g2, uint8_t src_tile_row, uint8_t dest_tile_row)
{
  uint8_t *ptr;
  uint16_t offset;
  uint8_t w;
  
  w = u8g2_GetU8x8(u8g2)->display_info->tile_width;
  offset = src_tile_row;
  ptr = u8g2->tile_buf_ptr;
  offset *= w;
  offset *= 8;
  ptr += offset;
  u8x8_DrawTile(u8g2_GetU8x8(u8g2), 0, dest_tile_row, w, ptr);
}

/* 
  write the buffer to the display RAM. 
  For most displays, this will make the content visible to the user.
  Some displays (like the SSD1606) require a u8x8_RefreshDisplay()
*/
static void u8g2_send_buffer(u8g2_t *u8g2) U8X8_NOINLINE;
static void u8g2_send_buffer(u8g2_t *u8g2)
{
  uint8_t src_row;
  uint8_t src_max;
  uint8_t dest_row;
  uint8_t dest_max;

  src_row = 0;
  src_max = u8g2->tile_buf_height;
  dest_row = u8g2->tile_curr_row;
  dest_max = u8g2_GetU8x8(u8g2)->display_info->tile_height;
  
  do
  {
    u8g2_send_tile_row(u8g2, src_row, dest_row);
    src_row++;
    dest_row++;
  } while( src_row < src_max && dest_row < dest_max );
}

示例:

void loop(void) {
  u8g2.clearBuffer();
  // ... write something to the buffer 
  u8g2.sendBuffer();
  delay(1000);

3.2.3 顯示配置相關函數

3.2.3.1 u8g2.getAscent() —— 獲取基準線以上的高度

函數說明:

/**
 * 獲取基準線以上的高度
 * @return 返回高度值
 * @Note 關聯方法  setFont getDescent setFontRefHeightAll
 */
int8_t U8G2::getAscent(void)

注意點:

  • 跟字體有關(setFont);

示例:
下面例子,ascent是18

image

3.2.3.2 u8g2.getDescent() —— 獲取基準線以下的高度

函數說明:

/**
 * 獲取基準線以下的高度
 * @return 返回高度值
 * @Note 關聯方法  setFont setFontRefHeightAll
 */
int8_t U8G2::getDescent(void)

注意點:

  • 跟字體有關(setFont);

示例:
下面例子,descent是-5

image

3.2.3.3 u8g2.getDisplayHeight() —— 獲取顯示器的高度

函數說明:

/**
 * 獲取顯示器的高度
 * @return 返回高度值
 */
u8g2_uint_t getDisplayHeight(void)

3.2.3.4 u8g2.getDisplayWidth() —— 獲取顯示器的寬度

函數說明:

/**
 * 獲取顯示器的寬度
 * @return 返回寬度值
 */
u8g2_uint_t getDisplayWidth(void)

3.2.3.5 u8g2.getMaxCharHeight() —— 獲取當前字體裏的最大字符的高度

函數說明:

/**
 * 獲取當前字體裏的最大字符的高度
 * @return 返回高度值
 * @Note 關聯方法 setFont
 */
u8g2_uint_t getMaxCharHeight(void)

注意點:

  • 每一個字符在font字集中都是一個位圖,位圖有高度和寬度;

3.2.3.6 u8g2.getMaxCharWidth() —— 獲取當前字體裏的最大字符的寬度

函數說明:

/**
 * 獲取當前字體裏的最大字符的寬度
 * @return 返回寬度值
 * @Note 關聯方法 setFont
 */
u8g2_uint_t getMaxCharWidth(void)

注意點:

  • 每一個字符在font字集中都是一個位圖,位圖有高度和寬度;

3.2.3.7 u8g2.getStrWidth() —— 獲取字符串的像素寬度

函數說明:

/**
 * 獲取字符串的像素寬度
 * @param s 繪製字符串
 * @return 返回字符串的像素寬度值
 * @Note 關聯方法 setFont drawStr
 */
u8g2_uint_t U8G2::getStrWidth(const char *s)

注意點:

  • 像素寬度和當前font字體有關;

3.2.3.8 u8g2.getUTF8Width() —— 獲取UTF-8字符串的像素寬度

函數說明:

/**
 * 獲取UTF-8字符串的像素寬度
 * @param s 繪製字符串
 * @return 返回字符串的像素寬度值
 * @Note 關聯方法 setFont drawStr
 */
u8g2_uint_t U8G2::getUTF8Width(const char *s)

注意點:

  • 像素寬度和當前font字體有關;

3.2.3.9 u8g2.setAutoPageClear() —— 設置自動清除緩衝區

函數說明:

/**
 * 是否自動清除緩衝區
 * @param mode 0 表示關閉
 *             1 表示開啓,默認是開啓
 */
void U8G2::setAutoPageClear(uint8_t mode)

注意點:

  • 該方法用於 firstPage 和 nextPage(看上面的源碼解析);
  • 建議該方法保持默認就好,如果用戶禁止了,那麼需要自己維護緩衝區的狀態或者手動調用clearBuffer;

3.2.3.10 u8g2.setBitmapMode() —— 設置位圖模式

函數說明:

/**
 * 設置位圖模式(定義drawXBM方法是否繪製背景顏色)
 * @param is_transparent
 *         0 繪製背景顏色,不透明,默認是該值
 *         1 不繪製背景顏色,透明
 * @Note 關聯方法 drawXBM
 */
void U8G2::setBitmapMode(uint8_t is_transparent)

示例:

u8g2.setDrawColor(1);
u8g2.setBitmapMode(0);
u8g2.drawXBM(4,3, u8g2_logo_97x51_width, u8g2_logo_97x51_height,  u8g2_logo_97x51_bits);
u8g2.drawXBM(12,11, u8g2_logo_97x51_width, u8g2_logo_97x51_height,  u8g2_logo_97x51_bits);

image

u8g2.setDrawColor(1);
u8g2.setBitmapMode(1);
u8g2.drawXBM(4,3, u8g2_logo_97x51_width, u8g2_logo_97x51_height,  u8g2_logo_97x51_bits);
u8g2.drawXBM(12,11, u8g2_logo_97x51_width, u8g2_logo_97x51_height,  u8g2_logo_97x51_bits);

image

3.2.3.11 u8g2.setBusClock() —— 設置總線時鐘

函數說明:

/**
 * 設置總線時鐘(I2C SPI)
 * @param mode clock_speed 總線時鐘頻率(Hz)
 * @Note 關聯方法 begin
 */
void U8G2::setBusClock(uint32_t clock_speed);

注意點:

  • 僅僅Arduino平臺支持;
  • 必須在u8g2.begin() 或者 u8g2.initDisplay()之前調用;

3.2.3.12 u8g2.setClipWindow() —— 設置採集窗口大小

函數說明:

/**
 * 設置採集窗口,窗口範圍從左上角(x0,y0)到右下角(x1,y1)
 * 也就是我們繪製的內容只能在規範範圍內顯示
 * @param x0 左上角x座標
 * @param y0 左上角y座標
 * @param x1 右上角x座標
 * @param y1 右上角y座標
 * @Note 關聯方法 begin
 */
void U8G2::setClipWindow(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t x1, u8g2_uint_t y1 );

注意點:

  • 可以通過 setMaxClipWindow 去掉該限制
void U8G2::setMaxClipWindow(void)

示例:

u8g2.setClipWindow(10, 10, 85, 30);
u8g2.setDrawColor(1);
u8g2.drawStr(3, 32, "U8g2");

image

3.2.3.13 u8g2.setCursor() —— 設置繪製光標位置

函數說明:

/**
 * 設置繪製光標位置(x,y)
 * @Note 關聯方法 print
 */
void U8G2::setCursor(u8g2_uint_t x, u8g2_uint_t y)

示例:

u8g2.setFont(u8g2_font_ncenB14_tr);
u8g2.setCursor(0, 15);
u8g2.print("Hello World!");

image

3.2.3.14 u8g2.setDisplayRotation() —— 設置顯示器的旋轉角度

函數說明:

/**
 * 設置顯示器的旋轉角度
 * @param u8g2_cb 旋轉選項
 *        U8G2_R0 不做旋轉 水平
 *        U8G2_R1 旋轉90度
 *        U8G2_R2 旋轉180度
 *        U8G2_R3 旋轉270度
 *        U8G2_MIRROR 不做旋轉 水平,顯示內容是鏡像的,暫時不理解
 */
void setDisplayRotation(const u8g2_cb_t *u8g2_cb)

3.2.3.15 u8g2.setDrawColor() —— 設置繪製顏色

函數說明:

/**
 * 設置繪製顏色(暫時還沒有具體去了解用法)
 */
void U8G2::setDrawColor(uint8_t color)

3.2.3.16 u8g2.setFont() —— 設置字體集

這是一個非常重要的方法,非常重要!!!

函數說明:

/**
 * 設置字體集(字體集用於字符串繪製方法或者glyph繪製方法)
 * @param font 具體的字體集
 * @Note 關聯方法  drawUTF8 drawStr drawGlyph print
 */
void U8G2::setFont(const uint8_t *font)

Font會根據像素點高度做了很多區分,具體font請參考 wiki
如果我們需要用到中文字符,可以在wiki裏面搜索一下chinese,你就會發現很多中文font,比如:

//支持UTF-8或者GB2312編碼
u8g2_font_wqy15_t_chinese1
u8g2_font_wqy15_t_chinese2
u8g2_font_wqy15_t_chinese3
u8g2_font_wqy12_t_gb2312
u8g2_font_wqy12_t_gb2312a
......

注意點:

  • 中文字符集消耗內存大,請謹慎使用,可以用在Arduino 101等ram空間比較大的板子上;

image

至於用哪一個,看自己的需求了。

我們看看Font的命名規則:

<prefix> '_' <name> '_' <purpose> <char set>

其中:

  • prefix基本上都是 u8g2;
  • name 一般會掛鉤上字符像素使用量,比如5X7
  • purpose
描述
t Transparent font, Do not use a background color.
h All glyphs have common height(所有的圖形有通用的高度).
m All glyphs have common height and width (monospace).
8 All glyphs fit into a 8x8 pixel box.
  • char set
描述
f The font includes up to 256 glyphs.
r Only glyphs on the range of the ASCII codes 32 to 127 are included in the font.
u Only glyphs on the range of the ASCII codes 32 to 95 (uppercase chars) are included in the font.
n Only numbers and extra glyphs for writing date and time strings are included in the font.
Other custom character list.

注意點:

  • U8G2庫提供的font非常多,博主也暫時消化不了太多。如果我們使用中文的話,就去看看中文font就好;

示例:Fonts u8g2_font_5x7_tr and u8g2_font_pressstart2p_8u

image

image

3.2.3.17 u8g2.setFontDirection() —— 設置字體方向

函數說明:

/**
 * 定義字符串繪製或者圖形繪製的方向
 * @param dir 方向
 * @param 關聯方法 drawStr
 */
void U8G2::setFontDirection(uint8_t dir)

注意點:

  • dir參數
Argument String Rotation Description
0 0 degree Left to right
1 90 degree Top to down
2 180 degree Right to left
3 270 degree Down to top

示例:

u8g2.setFont(u8g2_font_ncenB14_tf);
u8g2.setFontDirection(0);
u8g2.drawStr(15, 20, "Abc");
u8g2.setFontDirection(1);
u8g2.drawStr(15, 20, "Abc");

image

3.2.4 緩存相關函數

緩存相關函數,一般不會去操作,瞭解即可;

3.2.4.1 u8g2.getBufferPtr() —— 獲取緩存空間的地址

函數說明

/**
 * 獲取緩存空間的地址
 * @return 返回緩存空間起始地址
 * @Note 關聯方法 getBufferTileHeight, getBufferTileWidth, clearBuffer
 */
uint8_t *U8G2::getBufferPtr(void)

注意點:

  • 緩存大小等於 8 * u8g2.getBufferTileHeight() * u8g2.getBufferTileWidth().

3.2.4.2 u8g2.getBufferTileHeight() —— 獲取緩衝區的Tile高度

函數說明

/**
 * 獲取緩衝區的Tile高度
 * @return 返回高度值
 */
uint8_t U8G2::getBufferTileHeight(void)

注意點:

  • 一個tile等於8個像素點.

3.2.4.3 u8g2.getBufferTileWidth() —— 獲取緩衝區的Tile寬度

函數說明

/**
 * 獲取緩衝區的Tile寬度
 * @return 返回寬度值
 */
uint8_t U8G2::getBufferTileWidth(void)

注意點:

  • 一個tile等於8個像素點.

3.2.4.4 u8g2.getBufferCurrTileRow() —— 獲取緩衝區的當前Tile row

函數說明

/**
 * 獲取緩衝區的當前Tile row行數
 * @return 返回當前的tilerow
 */
uint8_t U8G2::getBufferCurrTileRow(void)

注意點:

  • 這個方法跟我們上面說到的page position相關.

3.2.4.5 u8g2.setBufferCurrTileRow() —— 設置緩衝區的當前Tile row

函數說明

/**
 * 設置緩衝區的當前Tile row
 * @param 當前的tilerow
 */
void U8G2::setBufferCurrTileRow(uint8_t  row)

注意點:

  • 在 firstPage/nextPage 循環時,由於底層調用了setBufferCurrTileRow,所以儘量不要自己手動調用該方法;

示例:

u8g2.setBufferCurrTileRow(0);       // let y=0 be the topmost row of the buffer
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_helvB08_tr);
u8g2.drawStr(2, 8, "abcdefg");

u8g2.setBufferCurrTileRow(2);	// write the buffer to tile row 2 (y=16) on the display
u8g2.sendBuffer();
u8g2.setBufferCurrTileRow(4);	// write the same buffer to tile row 4 (y=32) on the display
u8g2.sendBuffer();

image

利用好該方法,我們可以實現部分更新;

4.如何運用U8G2庫

    前面博主介紹到U8G2適配了絕大部分的OLED,那麼我們如何構建具體的OLED驅動呢?可分爲以下幾個順序步驟:

  • 區分顯示器
  • 選擇物理總線方式
  • 區分數字連線
  • U8g2初始化
  • U8g2繪製模式

4.1 區分顯示器

    首先,你需要知道OLED顯示器的控制器型號以及屏幕大小。舉個例子,博主手上有一塊SSD1306 128X64的OLED,那麼它的控制器就是SSD1306,屏幕大小是128X64。
    其次,你所選擇的OLED必須在U8g2庫所支持的OLED列表中,具體可參考 鏈接地址

4.2 選擇物理總線方式

    圖像信息是通過物理總線方式發給OLED顯示器。通常,我們的總線包括:

  • 3SPI,3-wire SPI:串行外圍接口,依靠三個控制信號,Clock、Data、CS;
  • 4SPI, 4-Wire SPI,跟3SPI一樣,只是額外多了一條數據命令線,經常叫做D/C;
  • I2C, IIC or TWI: SCL SDA;
  • 8080:A 8-Bit bus which requires 8 data lines, chip select and a write strobe signa
  • 6800: Another 8-Bit bus, but with a different protocol.

    具體的OLED使用什麼物理總線,我們需要查閱各自的數據手冊。比如,博主的SSD1306就是IIC。

4.3 區分數字連線

    知道了物理連線模式之後,我們一般都是把OLED連接到Arduino Board的輸出引腳,也就是軟件模擬具體總線協議。當然,如果有現成的物理總線端口那就更好了。

4.4 U8g2初始化

    經歷以上三步之後,我們就可以開始初始化出具體的OLED驅動了。比如,博主的IIC SSD1306 128X64 的OLED,就可以用以下初始化構造器(Builder設計模式,有空可以去了解一下):

U8G2_SSD1306_128X64_NONAME_1_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE);   // All Boards without Reset of the Display

當然SSD1306還有其他構造器(具體可以參考 wiki):

Controller “ssd1306”, Display “128x64_noname” Descirption
U8G2_SSD1306_128X64_NONAME_1_4W_SW_SPI(rotation, clock, data, cs, dc [, reset]) page buffer, size = 128 bytes
U8G2_SSD1306_128X64_NONAME_2_4W_SW_SPI(rotation, clock, data, cs, dc [, reset]) page buffer, size = 256 bytes
U8G2_SSD1306_128X64_NONAME_F_4W_SW_SPI(rotation, clock, data, cs, dc [, reset]) full framebuffer, size = 1024 bytes
U8G2_SSD1306_128X64_NONAME_1_4W_HW_SPI(rotation, cs, dc [, reset]) page buffer, size = 128 bytes

    那麼,我們這裏就需要重點講述一下構造器的規則。
    構造器的名字包括以下幾方面:

No Description Example
1 Prefix U8G2
2 Display Controller SSD1306
3 Display Name 128X64_NONAME
4 Buffer Size 1, 2 or F (full frame buffer)
5 Communication 4W_SW_SPI

    它們之間使用"_"連接起來。其中:

  • BufferSize,緩存大小
BufferSize Description
1 保持一頁的緩衝區,用於firstPage/nextPage的PageMode.
2 保持兩頁的緩衝區,用於firstPage/nextPage的PageMode…
F 獲取整個屏幕的緩衝區,ram消耗大,一般用在ram空間比較大的arduino板子.
  • Communication,通信協議
Communication Description
4W_SW_SPI 4-wire (clock, data, cs and dc) software emulated SPI
4W_HW_SPI 4-wire (clock, data, cs and dc) hardware SPI (based on Arduino SPI library)
2ND_4W_HW_SPI If supported, second 4-wire hardware SPI (based on Arduino SPI library)
3W_SW_SPI 3-wire (clock, data and cs) software emulated SPI
SW_I2C Software emulated I2C/TWI
HW_I2C Hardware I2C based on the Arduino Wire library
2ND_HW_I2C If supported, use second hardware I2C (Arduino Wire lib)
6800 8-bit parallel interface, 6800 protocol
8080 8-bit parallel interface, 8080 protocol
  • Rotation (軟件模擬總線前提下的構造器的第一個參數)
Rotation/Mirror Description
U8G2_R0 No rotation, landscape
U8G2_R1 90 degree clockwise rotation
U8G2_R2 180 degree clockwise rotation
U8G2_R3 270 degree clockwise rotation
U8G2_MIRROR No rotation, landscape, display content is mirrored (v2.6.x)

所以,一個完整的例子爲:

#include <Arduino.h>
#include <U8g2lib.h>
#include <SPI.h>
#include <Wire.h>

U8G2_ST7920_128X64_1_SW_SPI u8g2(U8G2_R0, 13, 11, 10, 8);

void setup(void) {
  u8g2.begin();
}

void loop(void) {
  u8g2.firstPage();
  do {
    u8g2.setFont(u8g2_font_ncenB14_tr);
    u8g2.drawStr(0,24,"Hello World!");
  } while ( u8g2.nextPage() );
}

    那麼,我們來看看到底構造器裏面做了什麼操作?還是以博主使用的SSD1306 128X64爲例子:

/**
 * SSD1306 4線軟件模擬SPI
 */
U8G2_SSD1306_128X64_NONAME_1_4W_SW_SPI(.....)

    類定義:

/**
 * SSD1306構造器,繼承U8G2
 */
class U8G2_SSD1306_128X64_NONAME_1_4W_SW_SPI : public U8G2 {
  public: U8G2_SSD1306_128X64_NONAME_1_4W_SW_SPI(const u8g2_cb_t *rotation, uint8_t clock, uint8_t data, uint8_t cs, uint8_t dc, uint8_t reset = U8X8_PIN_NONE) : U8G2() {
    //配置SSD1306
    u8g2_Setup_ssd1306_128x64_noname_1(&u8g2, rotation, u8x8_byte_arduino_4wire_sw_spi, u8x8_gpio_and_delay_arduino);
    //設置通信協議
    u8x8_SetPin_4Wire_SW_SPI(getU8x8(), clock, data, cs, dc, reset);
  }
};

    從上面代碼看出,默認調用了父類U8G2的構造函數,我們看看它裏面做了什麼:

class U8G2 : public Print
{
  protected:
    u8g2_t u8g2;
    u8x8_char_cb cpp_next_cb; /*  the cpp interface has its own decoding function for the Arduino print command */
  public:
    u8g2_uint_t tx, ty;
  
    U8G2(void) { 
          //設置Arduino print函數的解碼方法,這裏是ASCII,當然也有UTF-8
          cpp_next_cb = u8x8_ascii_next; 
          //屏幕初始化
          home(); 
    }
    .......
  • U8G2類構造函數主要是定義好解碼方法以及初始化屏幕(包括重置原點);

    然後我們看看,u8g2_Setup_ssd1306_128x64_noname_1做了什麼:

void u8g2_Setup_ssd1306_128x64_noname_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb)
{
  uint8_t tile_buf_height;
  //定義好緩存空間 記住 這裏是 1 page mode
  uint8_t *buf;
  //配置屏幕
  u8g2_SetupDisplay(u8g2, u8x8_d_ssd1306_128x64_noname, u8x8_cad_001, byte_cb, gpio_and_delay_cb);
  //生成buf 這裏是128 bytes
  buf = u8g2_m_16_8_1(&tile_buf_height);
  //初始化buf
  u8g2_SetupBuffer(u8g2, buf, tile_buf_height, u8g2_ll_hvline_vertical_top_lsb, rotation);
}

/*============================================*/
/*
  This procedure is called after setting up the display (u8x8 structure).
  --> This is the central init procedure for u8g2 object
*/
void u8g2_SetupBuffer(u8g2_t *u8g2, uint8_t *buf, uint8_t tile_buf_height, u8g2_draw_ll_hvline_cb ll_hvline_cb, const u8g2_cb_t *u8g2_cb)
{
  u8g2->font = NULL;
  //u8g2->kerning = NULL;
  //u8g2->get_kerning_cb = u8g2_GetNullKerning;
  
  //u8g2->ll_hvline = u8g2_ll_hvline_vertical_top_lsb;
  u8g2->ll_hvline = ll_hvline_cb;
  
  u8g2->tile_buf_ptr = buf;
  u8g2->tile_buf_height = tile_buf_height;
  
  u8g2->tile_curr_row = 0;//頁碼 這是一個很重要的參數
  
  u8g2->font_decode.is_transparent = 0; /* issue 443 */
  u8g2->bitmap_transparency = 0;
  
  u8g2->draw_color = 1;
  u8g2->is_auto_page_clear = 1;//自動清除
  
  u8g2->cb = u8g2_cb;
  u8g2->cb->update_dimension(u8g2);
#ifdef U8G2_WITH_CLIP_WINDOW_SUPPORT
  u8g2_SetMaxClipWindow(u8g2);		/* assign a clip window and call the update() procedure */
#else
  u8g2->cb->update_page_win(u8g2);
#endif

  u8g2_SetFontPosBaseline(u8g2);  /* issue 195 */
  
#ifdef U8G2_WITH_FONT_ROTATION  
  u8g2->font_decode.dir = 0;
#endif
}

可以總結幾點:

  • 配置初始化屏幕
  • 配置初始化緩衝區

注意點:

  • 上面講解涉及到了繪製模式,請參考下一節;

4.5 U8g2繪製模式

    U8g2支持三種繪製模式:

  • Full screen buffer mode,全屏緩存模式
  • Page mode (This is the U8glib picture loop) 分頁模式
  • U8x8, character only mode 僅僅支持普通字符

4.5.1 Full screen buffer mode

特點:

  • 繪製速度快
  • 所有的繪製方法都可以使用
  • 需要大量的ram空間

構造器:

  • 構造器必須帶有F,比如:
U8G2_ST7920_128X64_F_SW_SPI(rotation, clock, data, cs [, reset])

用法:

  1. 清除緩衝區 u8g2.clearBuffer()
  2. 操作一些繪製方法
  3. 發送緩衝區的內容到顯示器 u8g2.sendBuffer().

示例代碼:

void setup(void) {
  u8g2.begin();
}

void loop(void) {
  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_ncenB14_tr);
  u8g2.drawStr(0,20,"Hello World!");
  u8g2.sendBuffer();
}

4.5.2 Page mode

特點:

  • 繪製速度慢
  • 所有的繪製方法都可以使用
  • 需要少量的ram空間

構造器:

  • 構造器必須帶有“1”或者2,比如:
U8G2_ST7920_128X64_ 1 _SW_SPI(rotation, clock, data, cs [, reset])

用法:

  1. 調用 u8g2.firstPage()
  2. 開始一個 do while 循環
  3. 在循環內部 操作一些繪製方法
  4. 不斷判斷 u8g2.nextPage()

示例代碼:

void setup(void) {
  u8g2.begin();
}

void loop(void) {
  u8g2.firstPage();
  do {
    u8g2.setFont(u8g2_font_ncenB14_tr);
    u8g2.drawStr(0,24,"Hello World!");
  } while ( u8g2.nextPage() );
}

4.5.3 U8x8 character mode

特點:

  • 繪製速度快
  • 並不是對所有的顯示器都有效
  • 圖形繪製不可用
  • 不需要ram空間

構造器:

  • 使用U8X8構造器,比如:
U8X8_ST7565_EA_DOGM128_4W_SW_SPI(clock, data, cs, dc [, reset])

用法:

  • 所有繪製命令是直接把數據寫到顯示器

示例代碼:

void setup(void) {
  u8x8.begin();
}

void loop(void) {
  u8x8.setFont(u8x8_font_chroma48medium8_r);
  u8x8.drawString(0,1,"Hello World!");
}

5.U8g2庫具體用例

    上面講解了那麼多理論知識,是時候去實際運用。博主在這裏選用了Arduino Mega2560 以及 NodeMcu ESP8266開發板,結合手上的SSD1306 OLED去講解例子。

5.1 SSD1306 + Mega2560

5.1.1 Hello World

實驗內容:

  • Full screen buffer mode
  • 自帶字體顯示“Hello World”
  • I2C總線

實驗器材:

  • Mega2560 + SSD1306 128X64

實驗代碼:

/*
  HelloWorld.ino
*/

#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

/*
  U8g2lib Example Overview:
    Frame Buffer Examples: clearBuffer/sendBuffer. Fast, but may not work with all Arduino boards because of RAM consumption
    Page Buffer Examples: firstPage/nextPage. Less RAM usage, should work with all Arduino boards.
    U8x8 Text Only Example: No RAM usage, direct communication with display controller. No graphics, 8x8 Text only.
*/

// Please UNCOMMENT one of the contructor lines below
// U8g2 Contructor List (Frame Buffer)
// The complete list is available here: https://github.com/olikraus/u8g2/wiki/u8g2setupcpp
// Please update the pin numbers according to your setup. Use U8X8_PIN_NONE if the reset pin is not connected
//U8G2_NULL u8g2(U8G2_R0);  // null device, a 8x8 pixel display which does nothing
//U8G2_SSD1306_128X64_NONAME_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SSD1306_128X64_NONAME_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 12, /* dc=*/ 4, /* reset=*/ 6); // Arduboy (Production, Kickstarter Edition)
//U8G2_SSD1306_128X64_NONAME_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SSD1306_128X64_NONAME_F_3W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* reset=*/ 8);
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
//U8G2_SSD1306_128X64_ALT0_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);   // same as the NONAME variant, but may solve the "every 2nd line skipped" problem
//U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* reset=*/ 8);
//U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE);   // All Boards without Reset of the Display
//U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ 16, /* data=*/ 17, /* reset=*/ U8X8_PIN_NONE);   // ESP32 Thing, pure SW emulated I2C
//U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ 16, /* data=*/ 17);   // ESP32 Thing, HW I2C with pin remapping
//U8G2_SSD1306_128X64_NONAME_F_6800 u8g2(U8G2_R0, 13, 11, 2, 3, 4, 5, 6, A4, /*enable=*/ 7, /*cs=*/ 10, /*dc=*/ 9, /*reset=*/ 8);
//U8G2_SSD1306_128X64_NONAME_F_8080 u8g2(U8G2_R0, 13, 11, 2, 3, 4, 5, 6, A4, /*enable=*/ 7, /*cs=*/ 10, /*dc=*/ 9, /*reset=*/ 8);
//U8G2_SSD1306_128X64_VCOMH0_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // same as the NONAME variant, but maximizes setContrast() range
//U8G2_SSD1306_128X64_ALT0_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // same as the NONAME variant, but may solve the "every 2nd line skipped" problem
//U8G2_SH1106_128X64_NONAME_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
//U8G2_SH1106_128X64_VCOMH0_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);    // same as the NONAME variant, but maximizes setContrast() range
//U8G2_SH1106_128X64_WINSTAR_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);   // same as the NONAME variant, but uses updated SH1106 init sequence
//U8G2_SH1106_72X40_WISE_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SH1107_64X128_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SH1107_128X128_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SH1107_128X128_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ 8);
//U8G2_SH1107_PIMORONI_128X128_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ 8);
//U8G2_SH1107_SEEED_128X128_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE);
//U8G2_SH1107_SEEED_128X128_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
//U8G2_SH1107_SEEED_96X96_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SH1108_160X160_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SH1122_256X64_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);       // Enable U8G2_16BIT in u8g2.h
//U8G2_SSD1306_128X32_UNIVISION_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ 21, /* data=*/ 20, /* reset=*/ U8X8_PIN_NONE);   // Adafruit Feather M0 Basic Proto + FeatherWing OLED
//U8G2_SSD1306_128X32_UNIVISION_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE);   // Adafruit Feather ESP8266/32u4 Boards + FeatherWing OLED
//U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);  // Adafruit ESP8266/32u4/ARM Boards + FeatherWing OLED
//U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ SCL, /* data=*/ SDA);   // pin remapping with ESP8266 HW I2C
//U8G2_SSD1306_128X32_WINSTAR_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ SCL, /* data=*/ SDA);   // pin remapping with ESP8266 HW I2C
//U8G2_SSD1306_64X48_ER_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);   // EastRising 0.66" OLED breakout board, Uno: A4=SDA, A5=SCL, 5V powered
//U8G2_SSD1306_48X64_WINSTAR_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);   
//U8G2_SSD1306_64X32_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); 
//U8G2_SSD1306_64X32_1F_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); 
//U8G2_SSD1306_96X16_ER_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);   // EastRising 0.69" OLED
//U8G2_SSD1322_NHD_256X64_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Enable U8G2_16BIT in u8g2.h
//U8G2_SSD1322_NHD_256X64_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);  // Enable U8G2_16BIT in u8g2.h
//U8G2_SSD1322_NHD_128X64_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SSD1322_NHD_128X64_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SSD1325_NHD_128X64_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); 
//U8G2_SSD1325_NHD_128X64_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);  
//U8G2_SSD0323_OS128064_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); 
//U8G2_SSD0323_OS128064_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);  
//U8G2_SSD1326_ER_256X32_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);         // experimental driver for ER-OLED018-1
//U8G2_SSD1327_SEEED_96X96_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE);  // Seeedstudio Grove OLED 96x96
//U8G2_SSD1327_SEEED_96X96_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); // Seeedstudio Grove OLED 96x96
//U8G2_SSD1327_EA_W128128_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SSD1327_EA_W128128_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SSD1327_EA_W128128_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ 5, /* data=*/ 4, /* reset=*/ U8X8_PIN_NONE);
//U8G2_SSD1327_EA_W128128_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
//U8G2_SSD1327_MIDAS_128X128_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SSD1327_MIDAS_128X128_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SSD1327_WS_128X128_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SSD1327_WS_128X128_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SSD1329_128X96_NONAME_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SSD1329_128X96_NONAME_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SSD1305_128X32_NONAME_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SSD1305_128X32_NONAME_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SSD1305_128X32_ADAFRUIT_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SSD1305_128X32_ADAFRUIT_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SSD1305_128X64_ADAFRUIT_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SSD1305_128X64_ADAFRUIT_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SSD1309_128X64_NONAME0_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);  
//U8G2_SSD1309_128X64_NONAME0_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);  
//U8G2_SSD1309_128X64_NONAME2_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);  
//U8G2_SSD1309_128X64_NONAME2_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);  
//U8G2_SSD1317_96X96_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);  // not tested, not confirmed
//U8G2_SSD1317_96X96_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);   // not tested, not confirmed
//U8G2_SSD1318_128X96_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);  
//U8G2_SSD1318_128X96_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); 
//U8G2_LD7032_60X32_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 11, /* data=*/ 12, /* cs=*/ 9, /* dc=*/ 10, /* reset=*/ 8); // SW SPI Nano Board
//U8G2_LD7032_60X32_F_4W_SW_I2C u8g2(U8G2_R0, /* clock=*/ 11, /* data=*/ 12, /* reset=*/ U8X8_PIN_NONE);  // NOT TESTED!
//U8G2_UC1701_EA_DOGS102_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_UC1701_EA_DOGS102_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_PCD8544_84X48_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);  // Nokia 5110 Display
//U8G2_PCD8544_84X48_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);     // Nokia 5110 Display
//U8G2_PCF8812_96X65_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);  // Could be also PCF8814
//U8G2_PCF8812_96X65_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);           // Could be also PCF8814
//U8G2_HX1230_96X68_F_3W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* reset=*/ 8);
//U8G2_HX1230_96X68_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_KS0108_128X64_F u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18, /*dc=*/ 17, /*cs0=*/ 14, /*cs1=*/ 15, /*cs2=*/ U8X8_PIN_NONE, /* reset=*/  U8X8_PIN_NONE);   // Set R/W to low!
//U8G2_KS0108_ERM19264_F u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18, /*dc=*/ 17, /*cs0=*/ 14, /*cs1=*/ 15, /*cs2=*/ 16, /* reset=*/  U8X8_PIN_NONE);  // Set R/W to low!
//U8G2_ST7920_192X32_F_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18, /*cs=*/ U8X8_PIN_NONE, /*dc=*/ 17, /*reset=*/ U8X8_PIN_NONE);
//U8G2_ST7920_192X32_F_SW_SPI u8g2(U8G2_R0, /* clock=*/ 18 /* A4 */ , /* data=*/ 16 /* A2 */, /* CS=*/ 17 /* A3 */, /* reset=*/ U8X8_PIN_NONE);
//U8G2_ST7920_128X64_F_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18 /* A4 */, /*cs=*/ U8X8_PIN_NONE, /*dc/rs=*/ 17 /* A3 */, /*reset=*/ 15 /* A1 */);  // Remember to set R/W to 0 
//U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, /* clock=*/ 18 /* A4 */ , /* data=*/ 16 /* A2 */, /* CS=*/ 17 /* A3 */, /* reset=*/ U8X8_PIN_NONE);
//U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* CS=*/ 10, /* reset=*/ 8);
//U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, /* clock=*/ 14, /* data=*/ 13, /* CS=*/ 15, /* reset=*/ 16); // Feather HUZZAH ESP8266, E=clock=14, RW=data=13, RS=CS
//U8G2_ST7920_128X64_F_HW_SPI u8g2(U8G2_R0, /* CS=*/ 10, /* reset=*/ 8);
//U8G2_ST7920_128X64_F_HW_SPI u8g2(U8G2_R0, /* CS=*/ 15, /* reset=*/ 16); // Feather HUZZAH ESP8266, E=clock=14, RW=data=13, RS=CS
//U8G2_ST7565_EA_DOGM128_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_ST7565_EA_DOGM128_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_ST7565_64128N_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_ST7565_64128N_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_ST7565_EA_DOGM132_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ U8X8_PIN_NONE);  // DOGM132 Shield
//U8G2_ST7565_EA_DOGM132_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ U8X8_PIN_NONE); // DOGM132 Shield
//U8G2_ST7565_ZOLEN_128X64_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_ST7565_ZOLEN_128X64_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_ST7565_LM6059_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);    // Adafruit ST7565 GLCD
//U8G2_ST7565_LM6059_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);   // Adafruit ST7565 GLCD
//U8G2_ST7565_LX12864_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_ST7565_LX12864_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_ST7565_ERC12864_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_ST7565_ERC12864_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_ST7565_ERC12864_ALT_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // contrast improved version for ERC12864
//U8G2_ST7565_ERC12864_ALT_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);  // contrast improved version for ERC12864
//U8G2_ST7565_NHD_C12832_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_ST7565_NHD_C12832_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_ST7565_NHD_C12864_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_ST7565_NHD_C12864_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_ST7565_JLX12864_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_ST7565_JLX12864_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_ST7567_PI_132X64_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 7, /* dc=*/ 9, /* reset=*/ 8);  // Pax Instruments Shield, LCD_BL=6
//U8G2_ST7567_PI_132X64_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 7, /* dc=*/ 9, /* reset=*/ 8);  // Pax Instruments Shield, LCD_BL=6
//U8G2_ST7567_JLX12864_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 7, /* dc=*/ 9, /* reset=*/ 8);  
//U8G2_ST7567_JLX12864_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 7, /* dc=*/ 9, /* reset=*/ 8);  
//U8G2_ST7567_ENH_DG128064_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); 
//U8G2_ST7567_ENH_DG128064_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); 
//U8G2_ST7567_ENH_DG128064I_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); 
//U8G2_ST7567_ENH_DG128064I_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); 
//U8G2_ST7567_64X32_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); 
//U8G2_ST75256_JLX172104_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_ST75256_JLX172104_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_ST75256_JLX19296_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_ST75256_JLX19296_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_ST75256_JLX256128_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);  // Enable U8g2 16 bit mode for this display
//U8G2_ST75256_JLX256128_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);   // Enable U8g2 16 bit mode for this display
//U8G2_ST75256_WO256X128_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);  // Enable U8g2 16 bit mode for this display
//U8G2_ST75256_WO256X128_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);   // Enable U8g2 16 bit mode for this display
//U8G2_ST75256_JLX256128_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 9, /* data=*/ 8, /* cs=*/ 7, /* dc=*/ 6, /* reset=*/ 5);  // MKR Zero, Enable U8g2 16 bit mode for this display
//U8G2_ST75256_JLX256128_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 7, /* dc=*/ 6, /* reset=*/ 5);  // MKR Zero, Enable U8g2 16 bit mode for this display
//U8G2_ST75256_JLX256160_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);  // Enable U8g2 16 bit mode for this display
//U8G2_ST75256_JLX256160_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);   // Enable U8g2 16 bit mode for this display
//U8G2_ST75256_JLX240160_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_ST75256_JLX240160_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_ST75256_JLX25664_F_2ND_HW_I2C u8g2(U8G2_R0, /* reset=*/ 8);  // Due, 2nd I2C, enable U8g2 16 bit mode for this display
//U8G2_NT7534_TG12864R_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);  
//U8G2_NT7534_TG12864R_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);  
//U8G2_ST7588_JLX12864_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ 5);  
//U8G2_ST7588_JLX12864_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ 5);
//U8G2_IST3020_ERC19264_F_6800 u8g2(U8G2_R0, 44, 43, 42, 41, 40, 39, 38, 37,  /*enable=*/ 28, /*cs=*/ 32, /*dc=*/ 30, /*reset=*/ 31); // Connect WR pin with GND
//U8G2_IST3020_ERC19264_F_8080 u8g2(U8G2_R0, 44, 43, 42, 41, 40, 39, 38, 37,  /*enable=*/ 29, /*cs=*/ 32, /*dc=*/ 30, /*reset=*/ 31); // Connect RD pin with 3.3V
//U8G2_IST3020_ERC19264_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_LC7981_160X80_F_6800 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18, /*cs=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect RW with GND
//U8G2_LC7981_160X160_F_6800 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18, /*cs=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect RW with GND
//U8G2_LC7981_240X128_F_6800 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18, /*cs=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect RW with GND
//U8G2_LC7981_240X64_F_6800 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 18, /*cs=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect RW with GND
//U8G2_SED1520_122X32_F u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*dc=*/ A0, /*e1=*/ A3, /*e2=*/ A2, /* reset=*/  A4);   // Set R/W to low!
//U8G2_T6963_240X128_F_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable/wr=*/ 17, /*cs/ce=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect RD with +5V, FS0 and FS1 with GND
//U8G2_T6963_256X64_F_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable/wr=*/ 17, /*cs/ce=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect RD with +5V, FS0 and FS1 with GND
//U8G2_T6963_160X80_F_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable/wr=*/ 17, /*cs/ce=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect RD with +5V, FS0 and FS1 with GND
//U8G2_T6963_128X64_F_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable/wr=*/ 17, /*cs/ce=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect RD with +5V, FS0 and FS1 with GND
//U8G2_T6963_128X64_ALT_F_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable/wr=*/ 17, /*cs/ce=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect RD with +5V, FS0 and FS1 with GND
//U8G2_SED1330_240X128_F_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 17, /*cs=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect RD with +5V, FG with GND
//U8G2_SED1330_240X128_F_6800 u8g2(U8G2_R0, 13, 11, 2, 3, 4, 5, 6, A4, /*enable=*/ 7, /*cs=*/ 10, /*dc=*/ 9, /*reset=*/ 8); // A0 is dc pin!
//U8G2_RA8835_NHD_240X128_F_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7, /*enable=*/ 17, /*cs=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // Connect /RD = E with +5V, enable is /WR = RW, FG with GND, 14=Uno Pin A0
//U8G2_RA8835_NHD_240X128_F_6800 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7,  /*enable=*/ 17, /*cs=*/ 14, /*dc=*/ 15, /*reset=*/ 16); // A0 is dc pin, /WR = RW = GND, enable is /RD = E
//U8G2_UC1604_JLX19264_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); 
//U8G2_UC1604_JLX19264_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);  
//U8G2_UC1608_ERC24064_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);  // SW SPI, Due ERC24064-1 Test Setup
//U8G2_UC1608_ERC240120_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); 
//U8G2_UC1608_240X128_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);  // SW SPI, Due ERC24064-1 Test Setup
//U8G2_UC1610_EA_DOGXL160_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/  U8X8_PIN_NONE);
//U8G2_UC1610_EA_DOGXL160_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/  U8X8_PIN_NONE);
//U8G2_UC1611_EA_DOGM240_F_2ND_HW_I2C u8g2(U8G2_R0, /* reset=*/ 8); // Due, 2nd I2C, DOGM240 Test Board
//U8G2_UC1611_EA_DOGM240_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);   // Due, SW SPI, DOGXL240 Test Board
//U8G2_UC1611_EA_DOGXL240_F_2ND_HW_I2C u8g2(U8G2_R0, /* reset=*/ 8);  // Due, 2nd I2C, DOGXL240 Test Board
//U8G2_UC1611_EA_DOGXL240_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);   // Due, SW SPI, DOGXL240 Test Board
//U8G2_UC1611_EW50850_F_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7,  /*enable=*/ 18, /*cs=*/ 3, /*dc=*/ 16, /*reset=*/ 17); // 240x160, Connect RD/WR1 pin with 3.3V, CS is aktive high
//U8G2_UC1611_CG160160_F_8080 u8g2(U8G2_R0, 8, 9, 10, 11, 4, 5, 6, 7,  /*enable=*/ 18, /*cs=*/ 3, /*dc=*/ 16, /*reset=*/ 17); // Connect WR1 and CD1 pin with 3.3V, connect CS0 with cs, WR0 with enable, CD with dc
//U8G2_UC1638_160X128_F_4W_HW_SPI u8g2(U8G2_R2, /* cs=*/ 2, /* dc=*/ 3, /* reset=*/ 4);    // Not tested
//U8G2_SSD1606_172X72_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);   // eInk/ePaper Display
//U8G2_SSD1607_200X200_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);  // eInk/ePaper Display, original LUT from embedded artists
//U8G2_SSD1607_GD_200X200_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Good Display
//U8G2_SSD1607_WS_200X200_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // Waveshare
//U8G2_IL3820_296X128_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // WaveShare 2.9 inch eInk/ePaper Display, enable 16 bit mode for this display!
//U8G2_IL3820_V2_296X128_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);  // ePaper Display, lesser flickering and faster speed, enable 16 bit mode for this display!
//U8G2_MAX7219_64X8_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 11, /* data=*/ 12, /* cs=*/ 10, /* dc=*/ U8X8_PIN_NONE, /* reset=*/ U8X8_PIN_NONE);
//U8G2_MAX7219_32X8_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 11, /* data=*/ 12, /* cs=*/ 10, /* dc=*/ U8X8_PIN_NONE, /* reset=*/ U8X8_PIN_NONE);
//U8G2_MAX7219_8X8_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 11, /* data=*/ 12, /* cs=*/ 10, /* dc=*/ U8X8_PIN_NONE, /* reset=*/ U8X8_PIN_NONE);
//U8G2_LS013B7DH03_128X128_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ U8X8_PIN_NONE, /* reset=*/ 8); // there is no DC line for this display
//U8G2_LS027B7DH01_400X240_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ U8X8_PIN_NONE, /* reset=*/ 8); // there is no DC line for this display
//U8G2_LS013B7DH05_144X168_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ U8X8_PIN_NONE, /* reset=*/ 8); // there is no DC line for this display
//U8G2_ST7511_AVD_320X240_F_8080 u8g2(U8G2_R0, 13, 11, 2, 3, 4, 5, 6, A4, /*enable/WR=*/ 7, /*cs=*/ 10, /*dc=*/ 9, /*reset=*/ 8); // Enable U8g2 16Bit Mode and connect RD pin with 3.3V/5V

// End of constructor list

void setup(void) {
  u8g2.begin();
}

void loop(void) {
  u8g2.clearBuffer();         // 清除內部緩衝區
  u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font
  u8g2.drawStr(0,10,"Hello World!");  // write something to the internal memory
  u8g2.drawStr(0,20,"This is bro cainiao!");  // write something to the internal memory
  u8g2.drawStr(0,30,"Welcome to U8G2!");  // write something to the internal memory
  u8g2.sendBuffer();          // transfer internal memory to the display
  delay(1000);  
}

實驗結果:

image

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章