当前位置: 代码迷 >> 综合 >> ESP8266 Arduino开发之路(9)— OLED的UI显示控制
  详细解决方案

ESP8266 Arduino开发之路(9)— OLED的UI显示控制

热度:32   发布时间:2023-12-06 02:51:25.0

ESP8266 Arduino开发之路(9)— OLED的UI显示控制

一、前言

在上一节中,我们使用了esp8266-oled-ssd1306库来实现OLED屏幕的显示,该库函数还提供了UI显示的文件库:OLEDDisplayUi.cpp,我们可以使用其提供的库来实现一些很炫酷的UI界面。
Ui库提供了一组基本的Ui元素,称为FramesOverlays;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);

如下所示为指示栏位于TOPLEFT的效果
在这里插入图片描述

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

  相关解决方案