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 }