1 前言
本文主要描述了基于【ART-Pi LoRa开发套件】LSD4RF-TEST2002[STM32L4]硬件平台与RT-Thread Studio软件平台,如何使用单色图形库u8g2软件包驱动1.3英寸OLED屏幕,并实现oled屏动态rtc时间显示。
详细示例代码可查看sdk-bsp-stm32l476-lsd4rf-test2002-v2\projects\oled_sh1106_u8g2。
本文主要包含如下内容:
- u8g2单色图形库与oled知识简介
- OLED驱动移植
- U8G2显示时钟应用示例
1.1 准备工作
- 硬件开发平台
- ART-Pi LoRa开发套件
- RF评估板(LSD4RF-TEST2002 V2[STM32L4] ) 的J5位号 + OLED屏幕扩展板(LSD4RF-TEST200B V3)
- 软件开发平台
- RT-Thread Studio 2.1.0版本
- RF评估板(LSD4RF-TEST2002[STM32L4])开发板资源包
- sdk-bsp-stm32l476-lsd4rf-test2002-v2
1.2 背景知识
1.2.1 U8G2单色图形库简介
u8g2 是目前 Arduino 平台上使用最广泛的单色图形库(单色屏驱动)之一,u8g2具有如下主要特色:
- u8g2 库平台支持性好,基本上支持绝大部分 Arduino 开发板;
- U8g2 支持单色 OLED 和 LCD,基本上主流的显示控制器都支持。u8g2 支持近 200 种单色屏,同样的代码可以直接运行在不同的屏幕上
- u8g2 库 API 众多,支持中文,支持不同字体。
u8g2 githu开源仓库:https://github.com/olikraus/u8g2
1.2.1.1 RT-Thread u8g2 单色驱动屏软件包
u8g2 单色驱动屏软件包是基于RT-Thread移植实现的u8g2单色图形库。
1.2.2 OLED简介
OLED(Organic Light-Emitting Diode)即有机发光二极管,则可以通过有机材料的性质实现自身发光。OLED采用非常薄的有机材料图层和玻璃基板制成,当有电流通过时,有机材料会发光。
3 u8g2软件包使用
基于LSD4RF-TEST2002驱动OLED屏幕,采用了u8g2软件包,IIC驱动采用RT-Thread内核的I2C设备驱动(软I2C)。完整测试示例可参考 sdk-bsp-stm32l476-lsd4rf-test2002-v2\projects\oled_sh1106_u8g2。
3.1 使能u8g2软件包
在“RT-Thread Settings”中,使能u8g2软件包。
- 点击“+Add”-> 搜索”u8g2” -> “+添加”
- 或者点击“更多配置”->“软件包”-> “peripheral libraries and drivers”-> “U8G2:a monochrome graphic library”

- “U8G2:a monochrome graphic library”
- 使能 Use hardware i2c(这里指的是使用RT Thread I2C设备(软IIC)
- i2c device name 因为是软IIC,可以任意定义
- 这里选择c语言版本 c-latest

3.2 OLED驱动移植
3.2.1 使能RT-Thread IIC设备驱动
“RT-Thread Settings”->“更多配置”->“Hardware Device Config”-> 勾选 “Enable I2C BUS”。LSD4RF-TEST2002 OLED i2c设备当前默认定义使用i2c1。

shell命令窗口输入list_device,查看i2c1设备是否正确加载

3.2.2 初始化u8g2_port.c OLED关联引脚
修改 u8g2_port.c 如下代码
uint8_t u8x8_rt_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
//....
case U8X8_MSG_GPIO_AND_DELAY_INIT:
rt_pin_mode(u8x8->pins[U8X8_PIN_RESET],PIN_MODE_OUTPUT);
rt_pin_mode(u8x8->pins[U8X8_PIN_DC],PIN_MODE_OUTPUT);
rt_pin_write(u8x8->pins[U8X8_PIN_RESET],1);
rt_pin_write(u8x8->pins[U8X8_PIN_DC],0);
break
}
3.2.3 初始化u8g2与功能测试
#define OLED_PIN_RESET GET_PIN(D,12)
#define OLED_PIN_DC GET_PIN(D,11)
int u8g2_oled_sh1106_init(void)
{
// Initialization
u8g2_Setup_sh1106_i2c_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_rt_hw_i2c, u8x8_rt_gpio_and_delay);
u8x8_SetPin(u8g2_GetU8x8(&u8g2), U8X8_PIN_RESET, OLED_PIN_RESET);
u8x8_SetPin(u8g2_GetU8x8(&u8g2), U8X8_PIN_DC, OLED_PIN_DC);
u8g2_InitDisplay(&u8g2);
u8g2_SetPowerSave(&u8g2, 0);
/* Test U8G2 OLED function */
/* full buffer example, setup procedure ends in _f */
u8g2_ClearBuffer(&u8g2);
u8g2_SetFont(&u8g2, u8g2_font_logisoso16_tf);
u8g2_DrawStr(&u8g2, 25, 42, "Loading...");
u8g2_SendBuffer(&u8g2);
rt_thread_mdelay(500);
/* full buffer example, setup procedure ends in _f */
u8g2_ClearBuffer(&u8g2);
u8g2_SetFont(&u8g2, u8g2_font_ncenB08_tr);
u8g2_DrawStr(&u8g2, 1, 18, "U8g2 on RT-Thread");
u8g2_SendBuffer(&u8g2);
// Draw Graphics
u8g2_SetFont(&u8g2, u8g2_font_unifont_t_symbols);
u8g2_DrawGlyph(&u8g2, 112, 56, 0x2603 );
u8g2_SendBuffer(&u8g2);
/* End of Test U8G2 OLED function */
return 0;
}
INIT_APP_EXPORT(u8g2_oled_sh1106_init);
3.3 u8g2显示时钟示例
如下示例实现使用u8g2提供api功能,动态更新RTC时间到OLED屏幕。
3.3.1 使能“软件模拟RTC”
在“RT-Thread Settings”->使能“软件模拟RTC”

shell命令窗口
- 输入 date 命令查看当前rtc时间。
- 输入 date [year month day hour min sec]修改当前rtc时间,比如 date 2021 4 25 14 23 01

3.3.2 添加oled实时时间显示
使用u8g2更新oled RTC实时时间示例代码如下
void u8g2_oled_rtc_info_update(void)
{
time_t now;
int sec = 0, min = 0, hour = 0;
int day = 0, month = 0, year = 0;
char sec_str[3];
char min_str[3];
char hour_str[3];
char day_str[3];
char mon_str[3];
char year_str[3];
struct tm *p;
now = time(RT_NULL);
p=gmtime((const time_t*) &now);
year = p->tm_year + 1900;
month = p->tm_mon + 1;
day = p->tm_mday;
hour = p->tm_hour;
min = p->tm_min;
sec = p->tm_sec;
rt_sprintf(year_str, "%02d",year % 100);
rt_sprintf(mon_str, "%02d", month);
rt_sprintf(day_str, "%02d", day);
rt_sprintf(hour_str, "%02d", hour);
rt_sprintf(min_str, "%02d", min);
rt_sprintf(sec_str, "%02d", sec);
//u8g2_ClearBuffer(&u8g2);
u8g2_SetFont(&u8g2, u8g2_font_6x10_tr);
u8g2_DrawStr(&u8g2, 20, 35, year_str);
u8g2_DrawStr(&u8g2, 30,35,"-");
u8g2_DrawStr(&u8g2, 35, 35, mon_str);
u8g2_DrawStr(&u8g2, 45,35,"-");
u8g2_DrawStr(&u8g2, 50, 35, day_str);
u8g2_DrawStr(&u8g2, 60,35," ");
u8g2_DrawStr(&u8g2, 73, 35, hour_str);
u8g2_DrawStr(&u8g2, 83,35,":");
u8g2_DrawStr(&u8g2, 88, 35, min_str);
u8g2_DrawStr(&u8g2, 98,35,":");
u8g2_DrawStr(&u8g2, 103, 35, sec_str);
u8g2_SendBuffer(&u8g2);
}
void oled_update_thread_entry(void *parameter)
{
while(1)
{
u8g2_oled_rtc_info_update();
rt_thread_mdelay(1000);
}
}
基于RF评估板(LSD4RF-TEST2002[STM32L4])实际运行效果如下

4 参考
你好我用的也是1.3寸的中景圆的oled但是显示乱码,不知道哪里的问题
@认清自我 如果采用的是u8g2测试,确认下屏幕的驱动芯片是否匹配(比如SSD1306、SH1106),若不清楚屏幕参数,可以测试下u8g2提供的几种初始化接口,如u8g2_Setup_sh1106_i2c_128x64_noname_f、u8g2_Setup_sh1106_i2c_128x64_vcomh0_f,另外确定OLED屏幕的相关引脚是否正确配置