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基础