天天看點

【執行個體示範】ESP8266+U8g2庫,玩轉OLED顯示

上篇文章,介紹了ESP8266在Arduino IDE中的基礎使用方法,本篇,來繼續學習OLED顯示屏如何使用ESP8266來控制。

1 ESP8266引腳

首先來看一下ESP8266的引腳定義,因為本篇需要外接OLED,就要先看看ESP8266具有哪些功能的引腳。

ESP8266的引腳定義如下:

【執行個體示範】ESP8266+U8g2庫,玩轉OLED顯示

可以看出,ESP8266的功能引腳包括:

  • 3個序列槽:TXD、RXD
  • 2個SPI接口:MOSI、MISO、SCLK、CS
  • 1個IIC接口:SDA、SCL
  • 多個數字輸入/輸出接口:D1~D8
  • 1個模拟輸入/輸出接口:A0

2 OLED簡介

OLED子產品的尺寸多種多樣,比較常用的是0.96寸的矩形的,也有其它尺寸的OLED。

此外,螢幕的接口,一般有IIC接口和SPI接口兩種。加上電源,IIC接口需要4根線,而SPI接口需要6根線,IIC的通信比SPI通信慢,但4線接線更友善。

【執行個體示範】ESP8266+U8g2庫,玩轉OLED顯示

本篇使用最為常用的0.96寸的OLED,分辨率128x64,黃藍雙色。

注意這裡的雙色,不是值一個像素點可以顯示兩種顔色,而是螢幕的上部1/4隻能顯示黃色,下部的3/4隻能顯示藍色,并且黃色和藍色之間,不是緊密靠在一起的,而是有約一個像素點的間隙。

【執行個體示範】ESP8266+U8g2庫,玩轉OLED顯示

3 U8g2庫簡介與安裝

3.1 U8g2庫簡介

U8g2 是一個用于嵌入式裝置的單色圖形庫。U8g2支援單色OLED和LCD,并支援如SSD1306等多種類型的OLED驅動。

U8g2源碼的開源庫位址:​​https://github.com/olikraus/u8g2​​

U8g2專為Arduino提供的友善安裝的庫位址:https://github.com/olikraus/U8g2_Arduino

想要研究U8g2源碼的可以看看這裡的源代碼,C和C++寫的。

比如畫直線這個函數和具體實作如下:

【執行個體示範】ESP8266+U8g2庫,玩轉OLED顯示

3.2 U8g2庫安裝

和上篇介紹ESP8266庫的安裝類似, U8g2庫的安裝也有兩種方式:

  • 線上安裝

線上安裝,在Arduino IDE的菜單的“項目->加載庫->管理庫”中搜尋u8g2後安裝即可,對網絡環境要求較高

【執行個體示範】ESP8266+U8g2庫,玩轉OLED顯示
  • 源碼安裝

将U8g2專為Arduino提供的庫(https://github.com/olikraus/U8g2_Arduino)整個下載下傳下來,然後還是在Arduino IDE的菜單的“項目->加載庫”中選擇“添加.ZIP庫…”,然後選到你剛下載下傳的U8g2_Arduino源碼檔案夾後即可安裝,也十分的友善。

【執行個體示範】ESP8266+U8g2庫,玩轉OLED顯示

3.3 U8g2庫的基礎使用

使用U8g2庫進行OLED的顯示十分簡單,首先要包含兩個庫,U8g2lib和Wire,後者是IIC通信需要用。

對于IIC接口的OLED,需要在程式中指定一下引腳的接口定義,如果是SPI接口,可以參考U8g2庫自帶例程中SPI接口是使用方法。

然後在Ardunio的setup中進行u8g2的初始化。

最後在Ardunio的loop中就可以編寫自己的邏輯了。

另外,U8g2庫在loop中的通用寫法是使用do{}while()的形式:

u8g2.firstPage();
  do
  {
    //自己的的邏輯
  } while (u8g2.nextPage());
  delay(1000);      

一個簡單的HelloWord在OLED中的顯示如下:

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

#define SCL 5
#define SDA 4

U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /*clock=*/SCL, /*data=*/SDA, /*reset=*/U8X8_PIN_NONE);   

void setup()
{
  u8g2.begin();
  u8g2.enableUTF8Print(); // enable UTF8 support for the Arduino print() function
}

void loop()
{
  u8g2.setFont(u8g2_font_unifont_t_symbols);
  u8g2.firstPage();
  do
  {
    u8g2.setCursor(0, 15); //指定顯示位置
    u8g2.print("Hello World!"); //使用print來顯示字元串
  } while (u8g2.nextPage());
  delay(1000);
}      

注意,setCursor(0, 15),是将畫圖位置移動到x=0,y=15處,然後以這個點的右上區域進行字元串的顯示,這樣看起來就是顯示在OLED的第一行,如果你設定setCursor(0, 0),字元串實際是到螢幕外面了,不會顯示!

【執行個體示範】ESP8266+U8g2庫,玩轉OLED顯示

4U8g2常用API函數

4.1 基礎設定

  • setFont(font)設定字型
  • ​font​

    ​:u8g2的字型,比較常用的有u8g2_font_unifont_t_symbols(通常使用這個)和u8g2_font_wqy12_t_gb2312b(用于顯示漢字)等
  • setFontMode(num) 設定字型背景顔色模式
  • ​num​

    ​​:啟用(​

    ​1​

    ​)透明模式
  • ​num​

    ​​:禁用(​

    ​0​

    ​)透明模式
  • setDrawColor(color) 設定所有繪圖函數的位值
  • ​color​

    ​​:​

    ​0​

    ​(顯示RAM中的清晰像素值)
  • ​color​

    ​​:​

    ​1​

    ​(設定像素值)
  • ​color​

    ​​:​

    ​2​

    ​(異或模式)

4.2 畫像素點

  • drawPixel(x,y)

隻有指定位置即可顯示像素點,比如把所有的點都顯示出來:

//畫像素點-填充螢幕
void testDrawPixelToFillScreen()
{
  int t = 1000;
  u8g2.clearBuffer();

  for (int j = 0; j < 64; j++)
  {
    for (int i = 0; i < 128; i++)
    {
      u8g2.drawPixel(i, j);
    }
  }
  SEND_BUFFER_DISPLAY_MS(t);
}      

效果如下面的右圖:

【執行個體示範】ESP8266+U8g2庫,玩轉OLED顯示

注意測試程式中,我定義了一個宏定義,用于延時顯示每一次的畫圖,友善觀察OLED的顯示過程:

#define SEND_BUFFER_DISPLAY_MS(ms)\
  do {\
    u8g2.sendBuffer(); \
    delay(ms);\
  }while(0);      

可以指定延時時間,如500毫秒或1000毫秒等。

4.3 畫直線

  • drawLine(x0,y0,x1,y1) 畫一條線
  • ​x0,y0​

    ​線的起點
  • ​x1,y1​

    ​線的終點
  • drawHLine(x,y,w) 畫一條水準線
  • ​x,y​

    ​線的起點
  • ​w​

    ​水準線的長度(寬度)
  • drawVLine(x,y,h) 畫一條豎直線
  • ​x,y​

    ​線的起點
  • ​h​

    ​豎直線的長度(高度)

測試函數:

//畫直線
void testDrawLine()
{
  int t = 500;
  u8g2.clearBuffer();
  u8g2.drawStr(33, 14, "drawLine");

  u8g2.drawLine(0, 0, 127, 63);
  SEND_BUFFER_DISPLAY_MS(t);
  u8g2.drawLine(0, 0, 127, 0);
  SEND_BUFFER_DISPLAY_MS(t);
  u8g2.drawLine(32, 15, 127, 15);
  SEND_BUFFER_DISPLAY_MS(t);
  u8g2.drawLine(33, 16, 127, 16);
  SEND_BUFFER_DISPLAY_MS(t);
  u8g2.drawLine(127, 0, 127, 15);
  SEND_BUFFER_DISPLAY_MS(t);
  u8g2.drawLine(127, 16, 127, 63);
  SEND_BUFFER_DISPLAY_MS(t);
}      

顯示效果如下面的左上圖:

【執行個體示範】ESP8266+U8g2庫,玩轉OLED顯示

4.4 畫空心/實心(圓角)矩形

  • drawFrame(x,y,w,h) 繪制一個空心框
  • drawBox(x,y,w,h) 繪制一個實心矩形
  • drawRFrame(x,y,w,h,r) 繪制一個空心框(圓角)
  • drawRBox(x,y,w,h,r) 繪制一個實心矩形 (圓角)
  • ​x,y​

    ​起點坐标
  • ​w,h​

    ​框的寬度和高度
  • ​r​

    ​圓角的半徑

測試函數:

//畫空心圓角矩形
void testDrawRFrame()
{
  int t = 500;
  int x = 16;
  int y = 32;
  int w = 50;
  int h = 20;
  int r = 3;
  u8g2.clearBuffer();
  u8g2.drawStr(0, 15, "drawRFrame");

  u8g2.drawRFrame(x, y, w, h, r);
  SEND_BUFFER_DISPLAY_MS(t);
  u8g2.drawRFrame(x+w+5, y-10, w-20, h+20, r);
  SEND_BUFFER_DISPLAY_MS(t);
}      

顯示效果如下面的右下圖:

【執行個體示範】ESP8266+U8g2庫,玩轉OLED顯示

4.5 畫空心/實心圓

  • drawCircle(x,y,rad,opt) 繪制一個空心圓
  • drawDisc(x,y,rad,opt) 繪制一個實心圓
  • ​x,y​

    ​為圓心坐标
  • ​rad​

    ​為圓的半徑
  • ​opt​

    ​為選擇畫的部分,分為:
  • ​U8G2_DRAW_UPPER_RIGHT​

    ​(右上)
  • ​U8G2_DRAW_UPPER_LEFT​

    ​(左上)
  • ​U8G2_DRAW_LOWER_LEFT​

    ​(左下)
  • ​U8G2_DRAW_LOWER_RIGHT​

    ​(右下)
  • ​U8G2_DRAW_ALL​

    ​(全部)

空心圓

//畫空心圓
void testDrawCircle()
{
  int t = 500;
  int stx = 0;  //畫圖起始x
  int sty = 16; //畫圖起始y
  int with = 16;//一個圖塊的間隔
  int r = 15;   //圓的半徑
  u8g2.clearBuffer();
  u8g2.drawStr(0, 15, "drawCircle");

  u8g2.drawCircle(stx, sty - 1 + with, r, U8G2_DRAW_UPPER_RIGHT); //右上
  SEND_BUFFER_DISPLAY_MS(t);
  u8g2.drawCircle(stx + with, sty, r, U8G2_DRAW_LOWER_RIGHT); //右下
  SEND_BUFFER_DISPLAY_MS(t);
  u8g2.drawCircle(stx - 1 + with * 3, sty - 1 + with, r, U8G2_DRAW_UPPER_LEFT); //左上
  SEND_BUFFER_DISPLAY_MS(t);
  u8g2.drawCircle(stx - 1 + with * 4, sty, r, U8G2_DRAW_LOWER_LEFT); //左下
  SEND_BUFFER_DISPLAY_MS(t);
  u8g2.drawCircle(stx - 1 + with * 2, sty - 1 + with * 2, r, U8G2_DRAW_ALL);//整個圓
  SEND_BUFFER_DISPLAY_MS(t);
}      

顯示效果如下面的左圖:

【執行個體示範】ESP8266+U8g2庫,玩轉OLED顯示

注意,U8g2庫畫出的圓,因像素點的顯示原理,圓的直徑占用的寬度不是半徑的2倍,而是2倍再加一個像素點。

4.6 畫空心/實心橢圓

  • drawEllipse(x,y,rx,ry,opt) 繪制一個空心橢圓
  • drawFilledEllipse(x,y,rx,ry,opt) 繪制一個實心橢圓
  • ​x,y​

    ​為圓心坐标
  • ​rx,ry​

    ​為與橢圓x和y方向的半徑
  • ​opt​

    ​與畫圓時的作用一緻

橢圓的顯示與圓的顯示類似,隻是橢圓可以分别指定x和y方向的半徑

【執行個體示範】ESP8266+U8g2庫,玩轉OLED顯示

4.7 字元串、漢字和變量顯示

字元串的顯示,可以使用drawStr函數,也可以使用通用風格的print函數。

  • drawStr(x,y,string) 繪制一個字元串
  • ​x,y​

    ​起點坐标
  • ​string​

    ​字元串

如果想要使用print顯示漢字,需要先設定如下兩句:

u8g2.enableUTF8Print();//enable UTF8
u8g2.setFont(u8g2_font_wqy12_t_gb2312b);//設定中文字元集      

如果想要顯示變量,使用print函數即可:

字元串、漢字、變量的測試函數如下:

//字元串/文字/變量顯示測試
void testDrawStr()
{
  int t = 1000;
  u8g2.clearBuffer();
  u8g2.drawStr(0, 14, "drawStr / print");
  SEND_BUFFER_DISPLAY_MS(t);

  u8g2.drawStr(0, 32, "~!@#$%^&*()_+");
  SEND_BUFFER_DISPLAY_MS(t);

  u8g2.enableUTF8Print();//enable UTF8
  u8g2.setFont(u8g2_font_wqy12_t_gb2312b);//設定中文字元集
  u8g2.setCursor(0, 48);
  u8g2.print("碼農愛學習");
  SEND_BUFFER_DISPLAY_MS(t);

  int a = 234;
  u8g2.setCursor(0, 64);
  u8g2.print("int a = ");
  u8g2.setCursor(40, 64);
  u8g2.print(a);//顯示變量
  SEND_BUFFER_DISPLAY_MS(t);
}      

顯示效果:

【執行個體示範】ESP8266+U8g2庫,玩轉OLED顯示

4.8 畫内置圖示

  • drawGlyph(x,y,addr) 繪制U8g2内置的圖示
  • ​x,y​

    ​起點坐标
  • ​addr​

    ​内置圖示的位址

U8g2庫内置了需要預先定義的圖形,通過drawGlyp函數以及指定的位址,即可看OLED上顯示對應的圖示:

各個圖形的位址定義如下:

【執行個體示範】ESP8266+U8g2庫,玩轉OLED顯示

編寫一個測試程式:

void testGlyph()
{
  int t = 1000;
  u8g2.clearBuffer();
  u8g2.drawStr(0, 14, "drawGlyph");

  u8g2.drawGlyph(0, 32, 0x23f0);
  SEND_BUFFER_DISPLAY_MS(t);

  u8g2.drawGlyph(16, 32, 0x23f3);
  SEND_BUFFER_DISPLAY_MS(t);

  u8g2.drawGlyph(32, 32, 0x2603);
  SEND_BUFFER_DISPLAY_MS(t);

  u8g2.drawGlyph(48, 32, 0x2615);
  SEND_BUFFER_DISPLAY_MS(t);

  u8g2.drawGlyph(64, 32, 0x2618);
  SEND_BUFFER_DISPLAY_MS(t);
}      

測試效果如下:

【執行個體示範】ESP8266+U8g2庫,玩轉OLED顯示

4.9 畫自定義圖檔

  • drawXBM(x,y,w,h,addr) 繪制一個實心矩形 (圓角)
  • ​x,y​

    ​起點坐标
  • ​w,h​

    ​圖檔的寬度和高度`
  • ​addr​

    ​圖檔(數組)的位址

自定義圖檔的顯示,需要先将圖形轉換為數組,可以使用如下工具進行圖檔到數組的轉換:

https://tools.clz.me/image-to-bitmap-array

【執行個體示範】ESP8266+U8g2庫,玩轉OLED顯示

編寫測試程式:

// width: 128, height: 48
const unsigned char bilibili[] U8X8_PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ... 省略若幹行 };

void testDrawXBM()
{
  int t = 1000;
  u8g2.clearBuffer();
  u8g2.drawStr(0, 14, "drawXBM");
  u8g2.drawXBM(0, 16, 128, 48, bilibili);
  SEND_BUFFER_DISPLAY_MS(t);
}      

效果如下:

【執行個體示範】ESP8266+U8g2庫,玩轉OLED顯示

5 總結

本篇介紹了ESP8266的引腳定義以及U8g2庫在OLED的使用基礎,并重點介紹了U8g2庫的各種畫圖函數,這個函數總結下來如下下表所示: