ESP8266 Arduino開發之路(9)— OLED的UI顯示控制
一、前言
在上一節中,我們使用了
esp8266-oled-ssd1306
庫來實作OLED螢幕的顯示,該庫函數還提供了UI顯示的檔案庫:
OLEDDisplayUi.cpp
,我們可以使用其提供的庫來實作一些很炫酷的UI界面。
Ui庫提供了一組基本的Ui元素,稱為
Frames
和
Overlays
;Frames被用來提供基本的顯示,在設定的時間内顯示一幀圖像後移動到下一個圖像顯示,然後該庫還提供了一個将相應更新的訓示符。另一方面,Overlays是一個總是顯示在相同位置的控件。
參考:https://github.com/ThingPulse/esp8266-oled-ssd1306/tree/4.2.0#ui-library-oleddisplayui
二、UI基本配置
1、對象定義
要使用OLEDDisplayUi庫提供的UI控制功能,我們需要定義一個oled的ui對象,
/* 建立一個olde螢幕ui控制對象,參數為oled螢幕對象指針 */
OLEDDisplayUi ui(&oled);
2、幀率設定
接下來設定幀率,ESP8266在80MHz主頻模式下可以達到渲染60fps的幀率圖像,但是這幾乎會将CPU的時間占滿,你将沒有太多的時間做其他事情,我們建議在160MHz的主頻模式下設定60fps,或者設定為直接設定為30幀。
/* 1.設定幀率,當設定為60fps時,會幾乎占滿cpu,沒有太多時間做其他事 */
ui.setTargetFPS(60);
3、訓示器欄設定
如下圖所示,該訓示器欄表現了頁面總數和目前頁面所在的位置,每個訓示點的像素為
8*8
,
頁面總數通過
setInactiveSymbol
設定,即所謂非活動符号,目前頁面符号稱為活動符号,通過
setActiveSymbol
設定。
/* 2. 設定設定訓示欄活動和非活動符号外形 */
ui.setActiveSymbol(activeSymbol); // 外形數組activeSymbol[]在image.h中定義
ui.setInactiveSymbol(inactiveSymbol); // 外形數組inactiveSymbol[]在image.h中定義
其參數為外形像素點數組,需要我們自己定義,為一個8位元組數組,每一位表示一個像素點,共
8*8
個像素點,如下所示,數組中的元素使用二進制表示
const uint8_t activeSymbol[] PROGMEM = {
B00000000,
B00000000,
B00011000,
B00100100,
B01000010,
B01000010,
B00100100,
B00011000
};
const uint8_t inactiveSymbol[] PROGMEM = {
B00000000,
B00000000,
B00000000,
B00000000,
B00011000,
B00011000,
B00000000,
B00000000
};
然後還可以設定訓示欄的位置,提供
TOP
,
LEFT
,
BOTTOM
,
RIGHT
四個位置的設定
/* 3. 訓示欄位置設定: TOP, LEFT, BOTTOM, RIGHT */
ui.setIndicatorPosition(BOTTOM);
如下所示為訓示欄位于
TOP
和
LEFT
的效果
4、動畫效果
該UI庫提供了四個動畫效果:
SLIDE_LEFT
,
SLIDE_RIGHT
,
SLIDE_UP
,
SLIDE_DOWN
,
即在上一幅圖像和下一幅圖像切換時的動畫效果,
/* 5. 設定從上一幀過渡到下一幀的動畫效果:SLIDE_LEFT, SLIDE_RIGHT, SLIDE_UP, SLIDE_DOWN */
ui.setFrameAnimation(SLIDE_LEFT);
5、添加圖像
接下來就到最重要的環節了,我們需要設定我們需要顯示的每一幅圖像
/* 6. 添加我們需要顯示的圖像,第一個參數為添加的圖像數組,第二個參數為圖像數量 */
ui.setFrames(frames, frameCount);
在這個方法調用之前,我們需要将圖像數組和圖像數量定義出來
/* 将要顯示的每一幀圖像函數定義在一個數組中 */
FrameCallback frames[] = { drawFrame1, drawFrame2, drawFrame3, drawFrame4, drawFrame5 };
/* 圖像數量 */
int frameCount = 5;
而圖像數組中的每一個函數都需要我們自己編寫好,例如:
/* 要顯示的第1幀圖像 */
void drawFrame1(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
/* 繪制一個xbm圖像 */
/* 注意:所有坐标位置都需要相對于傳入參數x和y繪制 */
display->drawXbm(x + 34, y + 14, WiFi_Logo_width, WiFi_Logo_height, WiFi_Logo_bits);
}
6、Overlay
Overlay
是一個總是顯示在相同位置的控件,我們可以用來顯示如時鐘這類資訊。
/* 7. 添加一個Overlays,Overlay是一個總是顯示在相同位置的控件,第一個參數為添加的Overlays數組,第二個參數為Overlays數量*/
ui.setOverlays(overlays, overlaysCount);
在這個方法調用之前,我們需要将Overlays數組和Overlays數量定義出來
/* 将要顯示的每一個Overlays函數定義在一個數組中 */
OverlayCallback overlays[] = { msOverlay };
/* Overlays數量 */
int overlaysCount = 5;
而Overlays數組中的每一個函數都需要我們自己編寫好,例如下所示,将目前系統運作時間顯示在右上角;
millis()
函數用來擷取Arduino開機後運作的時間長度,該時間長度機關是毫秒,最長可記錄接近50天左右的時間。如果超出記錄時間上限,記錄将從0重新開始。
/* 一個Overlay定義函數 */
void msOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) {
display->setTextAlignment(TEXT_ALIGN_RIGHT);
display->setFont(ArialMT_Plain_10);
display->drawString(128, 0, String(millis()));
}
三、實作效果
主程式代碼如下所示
/*
* ESP8266-NodeMCU通過驅動oled顯示ui界面
* 需要使用Arduino-OLED第三方庫:https://github.com/ThingPulse/esp8266-oled-ssd1306/tree/4.2.0
* ui界面顯示需要用到OLEDDisplayUi.cpp和OLEDDisplayUi.h
*/
/* 使用0.96寸的OLED螢幕需要使用包含這個頭檔案 */
#include "SSD1306Wire.h"
/* OLED螢幕ui界面需要使用的頭檔案 */
#include "OLEDDisplayUi.h"
#include "text.h"
#include "image.h"
/* 設定oled螢幕的相關資訊 */
const int I2C_ADDR = 0x3c; // oled螢幕的I2c位址
#define SDA_PIN 4 // SDA引腳,預設gpio4(D2)
#define SCL_PIN 5 // SCL引腳,預設gpio5(D1)
/* 建立一個oled螢幕對象,需要輸入IIC位址,SDA和SCL引腳号 */
SSD1306Wire oled(I2C_ADDR, SDA_PIN, SCL_PIN);
/* 建立一個olde螢幕ui控制對象,參數為oled螢幕對象指針 */
OLEDDisplayUi ui(&oled);
void setup() {
/* 1. 初始化序列槽通訊波特率為115200*/
Serial.begin(115200);
/* 2. oled螢幕ui顯示控制初始化*/
oled_ui_init();
/* 3. oled螢幕初始化 */
oled.init();
oled.flipScreenVertically(); // 設定螢幕翻轉
oled.setContrast(255); // 設定螢幕亮度
oled.clear(); oled.display(); // 清除螢幕
}
/* 要顯示的第1幀圖像 */
void drawFrame1(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
/* 繪制一個xbm圖像 */
/* 注意:所有坐标位置都需要相對于傳入參數x和y繪制 */
display->drawXbm(x + 34, y + 14, WiFi_Logo_width, WiFi_Logo_height, WiFi_Logo_bits);
}
/* 要顯示的第2幀圖像 */
void drawFrame2(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
/* 顯示在SSD1306Fonts.h中的3中預設字型 */
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(ArialMT_Plain_10);
display->drawString(0 + x, 10 + y, "Arial 10");
display->setFont(ArialMT_Plain_16);
display->drawString(0 + x, 20 + y, "Arial 16");
display->setFont(ArialMT_Plain_24);
display->drawString(0 + x, 34 + y, "Arial 24");
}
/* 要顯示的第3幀圖像 */
void drawFrame3(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
/* 顯示不同對齊方式下的字母顯示方式 */
display->setFont(ArialMT_Plain_10);
/* 左對齊顯示,起始坐标需要設定在左起始點 */
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawString(0 + x, 11 + y, "Left aligned (0,10)");
/* 中心對其顯示,起始坐标需要設定在中心位置 */
display->setTextAlignment(TEXT_ALIGN_CENTER);
// display->drawString(64 + x, 22 + y, "Center aligned (64,22)");
display->drawString(64 + x, 22 + y, "Center aligned (64,22)");
/* 右對齊顯示,起始坐标需要設定在最右側坐标位置 */
display->setTextAlignment(TEXT_ALIGN_RIGHT);
// display->drawString(128 + x, 33 + y, "Right aligned (128,33)");
display->drawString(128 + x, 33 + y, "Right aligned (128,33)");
}
/* 要顯示的第4幀圖像 */
void drawFrame4(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
/* 多行文本顯示 */
/* 在給定位置繪制一個最大寬度的字元串。如果給定的字元串比指定的寬度寬,文本将以空格或破折号換行到下一行*/
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(ArialMT_Plain_10);
display->drawStringMaxWidth(0 + x, 10 + y, 128, "Lorem ipsum\n dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore.");
}
/* 要顯示的第5幀圖像 */
void drawFrame5(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
/* 空圖像 */
}
/* 将要顯示的每一幀圖像函數定義在一個數組中 */
FrameCallback frames[] = { drawFrame1, drawFrame2, drawFrame3, drawFrame4, drawFrame5 };
/* 圖像數量 */
int frameCount = 5;
/* 一個Overlay定義函數 */
void msOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) {
display->setTextAlignment(TEXT_ALIGN_RIGHT);
display->setFont(ArialMT_Plain_10);
display->drawString(128, 0, String(millis()));
}
/* 将要顯示的每一個Overlays函數定義在一個數組中 */
OverlayCallback overlays[] = { msOverlay };
/* Overlays數量 */
int overlaysCount = 1;
/* oled螢幕ui顯示控制初始化*/
void oled_ui_init(void)
{
/* 1.設定幀率,當設定為60fps時,會幾乎占滿cpu,沒有太多時間做其他事 */
ui.setTargetFPS(60);
/* 2. 設定訓示欄活動和非活動符号外形 */
ui.setActiveSymbol(activeSymbol); // 外形數組activeSymbol[]在image.h中定義
ui.setInactiveSymbol(inactiveSymbol); // 外形數組inactiveSymbol[]在image.h中定義
/* 3. 訓示欄位置設定: TOP, LEFT, BOTTOM, RIGHT */
ui.setIndicatorPosition(BOTTOM);
/* 4. 設定訓示欄訓示條移動的方向 */
ui.setIndicatorDirection(LEFT_RIGHT);
/* 5. 設定從上一幀過渡到下一幀的動畫效果:SLIDE_LEFT, SLIDE_RIGHT, SLIDE_UP, SLIDE_DOWN */
ui.setFrameAnimation(SLIDE_LEFT);
/* 6. 添加我們需要顯示的圖像,第一個參數為添加的圖像數組,第二個參數為圖像數量 */
ui.setFrames(frames, frameCount);
/* 7. 添加一個Overlays,Overlay是一個總是顯示在相同位置的控件,第一個參數為添加的Overlays數組,第二個參數為Overlays數量*/
ui.setOverlays(overlays, overlaysCount);
}
void loop() {
/* 重新整理OLED螢幕,傳回值為在目前設定的重新整理率下顯示完目前圖像後所剩餘的時間 */
int remainingTimeBudget = ui.update();
if (remainingTimeBudget > 0) {
// 我們可以在這剩餘的時間做一些事情,但是如果時間不夠,就不要做任何事情了
delay(remainingTimeBudget);
Serial.println(remainingTimeBudget);
}
/* LED狀态取反 */
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}
編譯上傳到開發闆後實作效果如下所示:
四、其他設定
除了上面一些基本設定之外,還有一些其他設定如下所示
/* 1. 禁止自動切換下一幀,預設是開啟自動切換的 */
ui.disableAutoTransition();
/* 2. 使能自動切換下一幀,預設是開啟自動切換的*/
ui.enableAutoTransition();
/* 3. 設定圖像切換方向為從後往前,預設為從前往後 */
ui.setAutoTransitionBackwards();
/* 4. 設定圖像切換方向為從前往後,預設為從前往後 */
ui.setAutoTransitionForwards();
/* 5. 設定每一幀圖檔持續時間, 機關為ms */
ui.setTimePerFrame(1000);
/* 6. 設定兩幀圖檔之間的切換時間, 機關為ms */
ui.setTimePerTransition(2000);
/* 7. 關閉訓示條欄的顯示,預設開啟 */
ui.disableAllIndicators();
/* 8. 開啟訓示條欄的顯示,預設開啟 */
ui.enableAllIndicators();
五、附錄
上一篇:ESP8266 Arduino開發之路(8)— 使用OLED顯示文字和圖檔
下一篇:ESP8266 Arduino開發之路(10)— JSON基礎