arduino u8g2库的构造函数探秘

/* 采用 SSD1306 驱动芯片,分辨率为 128*X*64,通信方式为软件 I²C 总线 */
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ 16, /* data=*/ 17, /* reset=*/ U8X8_PIN_NONE);

/* 采用 SSD1306 驱动芯片,分辨率为 128*X*64,通信方式为硬件 I²C 总线 */
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ 16, /* data=*/ 17);

事实上,U8G2 库的 Arduino C++ 构造函数 u8g2(),其返回值类型都遵循着统一的命名规则:

前缀屏幕驱动芯片型号分辨率生产品牌缓冲区大小通信方式
U8G2 SSD1306 128X64 NONAME F HW_I2C
U8G2 SSD1306 128X64 NONAME F SW_I2C
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /*clock=*/SCL, /*data=*/SDA, /*reset=*/U8X8_PIN_NONE);  
部分 含义
固定U8G2
驱动芯片名字
显示大小
OLED名字,一般就是NONAME
1/2/F分别是一页、二页、全部完成的显示缓存,占用芯片内存依次增加
通信类型          SW:软件模拟                HW:硬件模拟

 

 

 

 

 

 

 

 

形参的含义:

形参 含义
U8G2_R0/1/2/3/MIRROR 不旋转、顺90、顺180、顺270、镜像
clock  SPI:时钟        I2C:SCL
data I2C        SDA
reset 屏幕的重置引脚,没有就U8X8_PIN_NONE
cs 片选
dc 命令脚

 

 

 

 

 

 

 

 

接下来的三个表格,分别展示了上述表格当中缓冲区大小、通信方式、显示旋转方向的具体参数信息:

缓冲区大小功能描述
1 占用 1 页的微控制器 RAM 作为缓冲区。
2 占用 2 页的微控制器 RAM 作为缓冲区(可以获得更快的显示刷新速度)。
F 在微控制器 RAM 当中保存完整的显示帧(推荐在 RAM 存储空间足够大的场景下使用)。
显示旋转方向功能描述
U8G2_R0 不旋转,横向显示。
U8G2_R1 顺时针 90° 度旋转。
U8G2_R2 顺时针 180° 度旋转。
U8G2_R3 顺时针 270° 度旋转。
U8G2_MIRROR 不旋转,横向显示,但是内容会被镜像。
通信方式功能描述
4W_SW_SPI 四线制(Clock\Data\CS\DC)的软件模拟 SPI。
4W_HW_SPI 四线制(Clock\Data\CS\DC)的硬件 SPI。
2ND_4W_HW_SPI 第 2 个四线制的硬件 SPI。
3W_SW_SPI 三线制(Clock\Data\CS)的软件模拟 SPI。
SW_I2C 软件模拟的 I²C 总线通信。
HW_I2C 硬件 I²C 总线通信。
2ND_HW_I2C 第 2 个硬件 I²C 通信总线。
6800 采用 6800 协议的 8 位并行接口。
8080 采用 8080 协议的 8 位并行接口。
注意:如果当前没有连接重置输入引脚,那么就可以将构造函数中的 reset 参数,直接填写为 U8X8_PIN_NONE。

采用 u8g2() 构造函数创建 u8g2 类的时候,需要传入一系列的参数,下面表格就展示了这些参数的具体信息:

引脚参数数据手册名称功能描述
clock SCL / SCLK ... SPI 或者 I²C 总线的时钟线。
data SDA / MOSI / SDIN ... SPI 或者 I²C 总线的数据线。
d0 ... d7 D0 ... D7 并行接口的数据线。
cs CS 片选信号线。
dc D/C / A0 / RS, ... 数据/命令选择线。
enable 8080:WR / 6800:E 8080 接口的 Write 写入线,6800 接口的 Enable 使能线。
reset - 重置信号线。

U8G2 库默认使用 8 位显示模式(即 256 色),如果需要使用 16 位显示模式,则必须在 u8g2.h 头文件当中添加如下注释

#define U8G2_16BIT

注意:16 位显示模式下,保存 U8G2 像素坐标的数据类型也会从 8 位变换为 16 位。

u8x8() 构造函数

U8G2 所包含的 U8x8 库无需占用微控制器的 RAM 存储空间,可以用于直接显示一些文本信息。但是需要注意 u8x8() 构造函数的参数构成,与 u8g2() 构造函数并不相同:

U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/16, /* data=*/17, /* reset=*/U8X8_PIN_NONE);

U8x8 库的 Arduino C++ 构造函数 u8x8(),其返回值类型都遵循着如下的命名规则:

前缀屏幕驱动芯片型号分辨率生产品牌通信方式
U8G2 SSD1306 128X64 NONAME HW_I2C
... ... ... ... ... ... ... SW_I2C

观察可以发现,除了没有缓冲区大小设置相关的参数之外,u8x8() 构造函数的返回类型命名方式,与 U8G2 库的 u8g2() 构造函数基本保持一致。接下来同样可以通过 Arduino C++ 和 U8x8 库,基于 UINIO-MCU-ESP32S3 和 UINIO-Monitor 实现一个 Hello UinIO.com! 字符串显示的示例:

#include <Arduino.h>
#include <SPI.h>
#include <U8x8lib.h>

/* u8x8 构造函数 */
U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/16, /* data=*/17, /* reset=*/U8X8_PIN_NONE);

void setup(void) {
  u8x8.begin();
}

void loop(void) {
  u8x8.setFont(u8x8_font_chroma48medium8_r);
  u8x8.drawString(0, 0, "Hello UinIO.com!");
  delay(1000);
}

源码分析

/**
 * SSD1306构造器,继承U8G2
 */
class U8G2_SSD1306_128X64_NONAME_1_4W_SW_SPI : public U8G2 {
  public: U8G2_SSD1306_128X64_NONAME_1_4W_SW_SPI(const u8g2_cb_t *rotation, uint8_t clock, uint8_t data, uint8_t cs, uint8_t dc, uint8_t reset = U8X8_PIN_NONE) : U8G2() {
    //配置SSD1306
    u8g2_Setup_ssd1306_128x64_noname_1(&u8g2, rotation, u8x8_byte_arduino_4wire_sw_spi, u8x8_gpio_and_delay_arduino);
    //设置通信协议
    u8x8_SetPin_4Wire_SW_SPI(getU8x8(), clock, data, cs, dc, reset);
  }
};

从上面代码看出,默认调用了父类U8G2的构造函数,我们看看它里面做了什么:

class U8G2 : public Print
{
  protected:
    u8g2_t u8g2;
    u8x8_char_cb cpp_next_cb; /*  the cpp interface has its own decoding function for the Arduino print command */
  public:
    u8g2_uint_t tx, ty;
  
    U8G2(void) { 
          //设置Arduino print函数的解码方法,这里是ASCII,当然也有UTF-8
          cpp_next_cb = u8x8_ascii_next; 
          //屏幕初始化
          home(); 
    }
    .......

 

U8G2类构造函数主要是定义好解码方法以及初始化屏幕(包括重置原点);

void u8g2_Setup_ssd1306_128x64_noname_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb)
{
 //buf height buf高度 uint8_t tile_buf_height;
//定义好缓存空间 这里是 1 page mode uint8_t *buf; //配置屏幕 u8g2_SetupDisplay(u8g2, u8x8_d_ssd1306_128x64_noname, u8x8_cad_001, byte_cb, gpio_and_delay_cb); //生成buf 这里是128 bytes buf = u8g2_m_16_8_1(&tile_buf_height); //初始化buf u8g2_SetupBuffer(u8g2, buf, tile_buf_height, u8g2_ll_hvline_vertical_top_lsb, rotation); } /*============================================*/ /* This procedure is called after setting up the display (u8x8 structure). --> This is the central init procedure for u8g2 object
  这里是核心初始化函数 调用时机是setting up display之后
*/ void u8g2_SetupBuffer(u8g2_t *u8g2, uint8_t *buf, uint8_t tile_buf_height, u8g2_draw_ll_hvline_cb ll_hvline_cb, const u8g2_cb_t *u8g2_cb) {
  //字体设置为NULL u8g2
->font = NULL; //u8g2->kerning = NULL; //u8g2->get_kerning_cb = u8g2_GetNullKerning; //这个HVLINE不知道是什么 //u8g2->ll_hvline = u8g2_ll_hvline_vertical_top_lsb; u8g2->ll_hvline = ll_hvline_cb; //tile块bufptr和高度 u8g2->tile_buf_ptr = buf; u8g2->tile_buf_height = tile_buf_height; u8g2->tile_curr_row = 0;//页码 这是一个很重要的参数 u8g2->font_decode.is_transparent = 0; /* issue 443 */ u8g2->bitmap_transparency = 0; u8g2->draw_color = 1; u8g2->is_auto_page_clear = 1;//自动清除 u8g2->cb = u8g2_cb; u8g2->cb->update_dimension(u8g2); #ifdef U8G2_WITH_CLIP_WINDOW_SUPPORT u8g2_SetMaxClipWindow(u8g2); /* assign a clip window and call the update() procedure 设置窗口裁剪并且进入update流程*/ #else u8g2->cb->update_page_win(u8g2); #endif u8g2_SetFontPosBaseline(u8g2); /* issue 195 */ #ifdef U8G2_WITH_FONT_ROTATION u8g2->font_decode.dir = 0; #endif }

 

posted @ 2025-01-14 11:26  mcwhirr  阅读(415)  评论(0)    收藏  举报