天天看点

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

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

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

页面总数通过

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

的效果

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

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));
    
}

           

编译上传到开发板后实现效果如下所示:

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

四、其他设置

除了上面一些基本设置之外,还有一些其他设置如下所示

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

继续阅读