HAL/LL/STD STM32 U8g2库 +I2C SSD1306/sh1106 WouoUI磁贴案例
- 📍WouoUI原项目地址:
https://github.com/RQNG/WouoUI
- 📍基于STM32F103C8T6 LL库驱动版本:
https://gitee.com/chcsx/platform-test/tree/master/MDK-ARM
- 🌿串口控制WouoUIPage版本:
https://github.com/Sheep118/WouoUI-PageVersion
- 🎬视频演示:
WouoUI移植磁贴案例,新增确认弹窗
- 📍基于标准库驱动,STM32F103RCT6移植u8g2 硬件i2c WouoUI磁贴:
https://gitee.com/henrycrh/stm32-f103-rct6_-wouo-ui/tree/master/STM32F10x_FWlib/src
- 🎬视频演示:
[开源]STM32F103RCT6移植u8g2 > 硬件i2c > WouoUI移植
[开源]STM32F103RCT6移植u8g2 > 硬件i2c > WouoUI移植
- 🔖使用LL库和STD标准库的可以参照上面的例程测试。这里不多作说明。
- 🔖串口控制WouoUIPage版本,该开源项目原作者,提供了较为详细的项目介绍和API接口使用说明,这里不做过多说明,该项目耦合度低,移植方便。原项目stm32 demo默认使用的是标准库SPI,这里会提供一个,移植到使用HAL库的I2C DMA方式的工程。
✅功能部分说明
- 🌿显示部分:U8g2库驱动
- 🌿按键:采用Multi-button库驱动
- 🎞SH1106驱动显示效果:
- 📺I2C SSD1306 0.96"屏幕显示效果:
🌾HAL库程序是基于上面的LL库移植过来的,采用的是STM32F103VET6
。保留了按键控制功能,去掉了其他没有的外设。
-
🔖AC6编译器,优化等级默认
Level 1 (o1)
。
-
🔖AC5编译器,优化等级至少要设置
Level 1 (o1)
,否则会报L6406E
错误。
-
🌿屏蔽相关报警信息
--diag_suppress=1,111,223,1295
- 1
- 🌿测试使用1.3“SH1106屏幕显示正常,0.96" ssd1306屏幕会闪屏。
- 📚移植的HAL库程序:
链接:https://pan.baidu.com/s/1Oh3ysdU8-1X0I_JJVVemkg?pwd=slro
提取码:slro
- 1
- 2
📄HAL库程序引脚说明
STM32F103VET6
按键控制
PE8 上翻页
PE7 下翻页
PB1 确认/长按返回
===================
I2C1 SCL ---- PB6
I2C1 SDA ---- PB7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
🔨HAL库程序SSD1306/sh1106屏幕选择与代码调整
- ✨在oled.c中,OLED初始化
OLED_Init(void)
函数。(sh1106屏幕刷SSD1306程序也可以显示,只是边框有一部分是马赛克雪花)
//***************************** 使用下面2个
u8g2_Setup_sh1106_i2c_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_hw_i2c, stm32_gpio_and_delay); //1.3" sh1106 使用这个
// u8g2_Setup_ssd1306_i2c_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_hw_i2c, stm32_gpio_and_delay); //0.96"SSD1306使用这个
//****************************** 使用上面2个
- 1
- 2
- 3
- 4
🌼U8g2库移植说明
- 🌿可以借用上面的LL库的工程,直接拷贝对应的驱动文件夹到自己所创建的工程目录下。
- 🌿其他屏幕型号,需要提前准备一个能驱动显示的工程作为模板。
- 🌿将以下3个核心函数,拷贝到能显示的模板工程中,根据驱动屏幕型号进行调整:
uint8_t u8x8_byte_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);//硬件I2C
uint8_t stm32_gpio_and_delay(U8X8_UNUSED u8x8_t *u8x8, U8X8_UNUSED uint8_t msg, U8X8_UNUSED uint8_t arg_int, U8X8_UNUSED void *arg_ptr);
void OLED_Init(void);
- 1
- 2
- 3
uint8_t u8x8_byte_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)//硬件I2C { /* u8g2/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER */ static uint8_t buffer[128]; static uint8_t buf_idx; uint8_t *data;
<span class="token keyword">switch</span> <span class="token punctuation">(</span>msg<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">case</span> U8X8_MSG_BYTE_INIT<span class="token operator">:</span> <span class="token punctuation">{<!-- --></span> <span class="token comment">/* add your custom code to init i2c subsystem */</span> <span class="token function">MX_I2C1_Init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//I2C初始化</span> <span class="token punctuation">}</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">case</span> U8X8_MSG_BYTE_START_TRANSFER<span class="token operator">:</span> <span class="token punctuation">{<!-- --></span> buf_idx <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">case</span> U8X8_MSG_BYTE_SEND<span class="token operator">:</span> <span class="token punctuation">{<!-- --></span> data <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">uint8_t</span> <span class="token operator">*</span><span class="token punctuation">)</span>arg_ptr<span class="token punctuation">;</span> <span class="token keyword">while</span> <span class="token punctuation">(</span>arg_int <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> buffer<span class="token punctuation">[</span>buf_idx<span class="token operator">++</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token operator">*</span>data<span class="token punctuation">;</span> data<span class="token operator">++</span><span class="token punctuation">;</span> arg_int<span class="token operator">--</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">case</span> U8X8_MSG_BYTE_END_TRANSFER<span class="token operator">:</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">int</span> ret <span class="token operator">=</span> <span class="token function">HAL_I2C_Master_Transmit</span><span class="token punctuation">(</span><span class="token operator">&</span>hi2c1<span class="token punctuation">,</span> <span class="token punctuation">(</span>OLED_ADDRESS<span class="token punctuation">)</span><span class="token punctuation">,</span> buffer<span class="token punctuation">,</span> buf_idx<span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>ret <span class="token operator">!=</span> HAL_OK<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">case</span> U8X8_MSG_BYTE_SET_DC<span class="token operator">:</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">default</span><span class="token operator">:</span> <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span>
}
uint8_t stm32_gpio_and_delay(U8X8_UNUSED u8x8_t u8x8, U8X8_UNUSED uint8_t msg, U8X8_UNUSED uint8_t arg_int, U8X8_UNUSED void arg_ptr)
{
#if 0
switch (msg)
{
// case U8X8_MSG_GPIO_AND_DELAY_INIT:
// oled_init();
// break;
case U8X8_MSG_GPIO_SPI_DATA:
if(arg_int)OLED_SDIN_Set();
else OLED_SDIN_Clr();
break;
case U8X8_MSG_GPIO_SPI_CLOCK:
if(arg_int)OLED_SCLK_Set();
else OLED_SCLK_Clr();
break;
case U8X8_MSG_GPIO_CS:
//CS???
case U8X8_MSG_GPIO_DC:
if(arg_int)OLED_DC_Set();
else OLED_DC_Clr();
break;
case U8X8_MSG_GPIO_RESET:
if(arg_int)OLED_RST_Set();
else OLED_RST_Clr();
break;
//Function which delays 100ns
case U8X8_MSG_DELAY_100NANO:
__NOP();
break;
case U8X8_MSG_DELAY_MILLI:
HAL_Delay(arg_int);
break;
default:
return 0;//A message was received which is not implemented, return 0 to indicate an error
}
return 1;
#elif 0
// printf(“%s:msg = %d,arg_int = %d\r\n”,FUNCTION,msg,arg_int);
switch (msg)
{
// case U8X8_MSG_GPIO_AND_DELAY_INIT:
// oled_init();
// break;
case U8X8_MSG_DELAY_100NANO: // delay arg_int * 100 nano seconds
__NOP();
break;
case U8X8_MSG_DELAY_10MICRO: // delay arg_int * 10 micro seconds
for (uint16_t n = 0; n < 320; n++)
{
__NOP();
}
break;
case U8X8_MSG_DELAY_MILLI: // delay arg_int * 1 milli second
HAL_Delay(1);
break;
case U8X8_MSG_DELAY_I2C: // arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz
// delay 5us
delay_us(5); // arg_int=1: delay by 5us, arg_int = 4: delay by 1.25us
<span class="token keyword">case</span> U8X8_MSG_GPIO_I2C_CLOCK<span class="token operator">:</span> <span class="token comment">// arg_int=0: Output low at I2C clock pin</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>arg_int <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
<span class="token function">LL_GPIO_SetOutputPin</span><span class="token punctuation">(</span>LCD_SCL_GPIO_Port<span class="token punctuation">,</span> LCD_SCL_Pin<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// HAL_GPIO_WritePin(GPIOB, SCL2_Pin, GPIO_PIN_SET);</span>
<span class="token punctuation">}</span>
<span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>arg_int <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
<span class="token function">LL_GPIO_ResetOutputPin</span><span class="token punctuation">(</span>LCD_SCL_GPIO_Port<span class="token punctuation">,</span> LCD_SCL_Pin<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// HAL_GPIO_WritePin(GPIOB, SCL2_Pin, GPIO_PIN_RESET);</span>
<span class="token punctuation">}</span>
<span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token comment">// arg_int=1: Input dir with pullup high for I2C clock pin</span>
<span class="token keyword">case</span> U8X8_MSG_GPIO_I2C_DATA<span class="token operator">:</span> <span class="token comment">// arg_int=0: Output low at I2C data pin</span>
<span class="token comment">// printf("U8X8_MSG_GPIO_I2C_DATA:%d\r\n",arg_int);</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>arg_int <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
<span class="token function">LL_GPIO_SetOutputPin</span><span class="token punctuation">(</span>LCD_SDA_GPIO_Port<span class="token punctuation">,</span> LCD_SDA_Pin<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// HAL_GPIO_WritePin(GPIOB, SDA2_Pin, GPIO_PIN_SET);</span>
<span class="token punctuation">}</span>
<span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>arg_int <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
<span class="token function">LL_GPIO_ResetOutputPin</span><span class="token punctuation">(</span>LCD_SDA_GPIO_Port<span class="token punctuation">,</span> LCD_SDA_Pin<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// HAL_GPIO_WritePin(GPIOB, SDA2_Pin, GPIO_PIN_RESET);</span>
<span class="token punctuation">}</span>
<span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token comment">// arg_int=1: Input dir with pullup high for I2C data pin</span>
<span class="token keyword">default</span><span class="token operator">:</span>
<span class="token function">u8x8_SetGPIOResult</span><span class="token punctuation">(</span>u8x8<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// default return value</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span>
#elif 0
switch (msg)
{
case U8X8_MSG_GPIO_AND_DELAY_INIT:
break;
case U8X8_MSG_DELAY_MILLI:
HAL_Delay(arg_int);
break;
case U8X8_MSG_GPIO_I2C_CLOCK:
break;
case U8X8_MSG_GPIO_I2C_DATA:
break;
default:
return 0;
}
return 1; // command processed successfully.
#elif 1
switch (msg)
{
case U8X8_MSG_DELAY_100NANO: // delay arg_int * 100 nano seconds
__NOP();
break;
case U8X8_MSG_DELAY_10MICRO: // delay arg_int * 10 micro seconds
for (uint16_t n = 0; n < 320; n++)
{
__NOP();
}
break;
case U8X8_MSG_DELAY_MILLI: // delay arg_int * 1 milli second
HAL_Delay(1);
break;
case U8X8_MSG_DELAY_I2C: // arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz
// delay_us(5);
for (uint16_t n = 0; n < 160; n++)
{
__NOP();
}
break; // arg_int=1: delay by 5us, arg_int = 4: delay by 1.25us
case U8X8_MSG_GPIO_I2C_CLOCK: // arg_int=0: Output low at I2C clock pin
break; // arg_int=1: Input dir with pullup high for I2C clock pin
case U8X8_MSG_GPIO_I2C_DATA: // arg_int=0: Output low at I2C data pin
break; // arg_int=1: Input dir with pullup high for I2C data pin
case U8X8_MSG_GPIO_MENU_SELECT:
u8x8_SetGPIOResult(u8x8, /* get menu select pin state / 0);
break;
case U8X8_MSG_GPIO_MENU_NEXT:
u8x8_SetGPIOResult(u8x8, / get menu next pin state / 0);
break;
case U8X8_MSG_GPIO_MENU_PREV:
u8x8_SetGPIOResult(u8x8, / get menu prev pin state / 0);
break;
case U8X8_MSG_GPIO_MENU_HOME:
u8x8_SetGPIOResult(u8x8, / get menu home pin state */ 0);
break;
default:
u8x8_SetGPIOResult(u8x8, 1); // default return value
break;
}
return 1;
}
#endif
/**
- @brief OLED初始化
*/
void OLED_Init(void)
{
// u8g2_Setup_sh1106_i2c_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_4wire_sw_spi, stm32_gpio_and_delay);
// u8g2_Setup_sh1106_i2c_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_sw_i2c, stm32_gpio_and_delay);
u8g2_Setup_sh1106_i2c_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_hw_i2c, stm32_gpio_and_delay);
u8g2_InitDisplay(&u8g2);
u8g2_SetPowerSave(&u8g2, 0);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
📚HAL库U8g2单独驱动程序SSD1306/sh1106屏幕
- 🌿SSD1306/sh1106屏幕选择
// u8g2_Setup_sh1106_i2c_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_hw_i2c, u8x8_stm32_gpio_and_delay); //1.3" sh1106 使用这个
u8g2_Setup_ssd1306_i2c_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_hw_i2c, u8x8_stm32_gpio_and_delay);//0.96"SSD1306使用这个
- 1
- 2
链接:https://pan.baidu.com/s/1_hQ1Op00aBoBkjhudml9pw?pwd=6z3u
提取码:6z3u
- 1
- 2
📚串口控制WouoUIPage STM32 HAL库I2C DMA方式工程版本
- 🔖基于STM32F103,兼容SSD1306/sh1106。在oled.h中修改对应宏,决定选择屏幕类型
#define SH1106_OLED 0
#define SSD1306_OLED 1
#define SCREEN_TYPE SH1106_OLED //SSD1306:0 ; SH1106:1
- 1
- 2
- 3
- 🔖测试方法:推荐使用带快捷键配置串口发送指令的串口调试助手,例如SSCOM、正点原子串口调试助手
链接:https://pan.baidu.com/s/1gh1-SFdA_IzaArTd_w4LWQ?pwd=hr3k
提取码:hr3k
- 1
- 2