目录
学习目标:
利用stm32f103的GPIO管脚、VCC和GND连接 OLED屏的I2C接口,采用cubemx设计一个HAL库程序框架,然后下载U82G源码,针对stm32f103和 0.96寸的I2C接口OLED屏,进行代码裁剪,然后移植到HAL程序程序中,完成OLED的各种显示。
I2C(Inter-Integrated Circuit)是一种使用两根信号线(SCL和SDA)进行通信的串行通信协议,适用于系统内多个集成电路(IC)间的数据交换。它支持最多127个设备),允许多主设备系统并且每个主设备可以与所有从设备通信。I2C的通信速率介于传统串口和SPI之间,且数据传输时每发送8位数据需要额外的1位元数据来确认接收状态。相比于SPI,I2C的硬件复杂度较低,而软件实现则相对简单,因此在嵌入式系统和各种电子设备中被广泛应用。
信号线:
总线结构:
起始和停止条件:
地址传输:
数据传输:
应答机制:
多主设备和速率控制:
一个 I2C 总线连接多个 I2C 设备如图所示:
SDA 和 SCL 这两根线必须要接一个上拉电阻,一般是 4.7K。其余的 I2C 从器件都挂接到 SDA 和 SCL 这两根线上,这样就可以通过 SDA 和 SCL 这两根线来访问多个 I2C设备。若有更多设备,都以如图器件连接方式。
对于I2C的时序协议,我们要注意图上的起始位、停止位。除此之外,还有重要的读写时序,应答信号。
起始位,顾名思义,是通信起始标志。
在I2C通信协议中,起始位(Start Bit)是由主设备生成的信号,用于指示一个新的数据传输即将开始。它通过将SCL保持为高电平的同时,将SDA线从高电平切换到低电平来发送。起始位的作用是在总线上同步所有设备,并告知它们即将进行通信。这一过程为每次数据传输建立了准确的起点,确保设备间的有效数据交换。
停止位就是停止 I2C 通信的标志位,和起始位的功能相反。
在I2C通信协议中,停止位(Stop Bit)由主设备发出,用于表示一次数据传输的结束或整个通信的终止。它通过将SCL保持为高电平的同时,将SDA线从低电平切换到高电平来发送。停止位的作用是告知所有设备当前数据传输已完成,释放总线控制权,使其他设备可以准备进行下一次通信或响应。这一过程确保了数据传输的完整性和通信的顺利进行,与起始位共同构成了每次数据传输的边界标识。
"应答信号"由从设备发送给主设备,用于确认接收到的数据或指令的有效性。主设备在发送完一个数据字节后释放SDA线,等待从设备通过拉低SDA线一个时钟周期来发送ACK,表示从设备准备好接收下一个数据字节或执行下一步操作。
当 I2C 主机发送完 8 位数据以后会将 SDA 设置为输入状态,等待 I2C 从机应答,也就是等到 I2C 从机告诉主机它接收到数据了。应答信号是由从机发出的,主机需要提供应答信号所需的时钟,主机发送完 8 位数据以后紧跟着的一个时钟信号就是给应答信号使用的。从机通过将 SDA 拉低来表示发出应答信号,表示通信成功,否则表示通信失败。这一交互过程确保了数据传输的正确性和通信的有效性,是协议中重要的一环,帮助主设备和从设备协调和控制数据的流动,从而保证通信的稳定和可靠性。
I2C 单字节读时序比写时序要复杂一点,读时序分为 4 大步,第一步是发送设备地址,第二步是发送要读取的寄存器地址,第三步重新发送设备地址,最后一步就是 I2C 从器件输出要读取的寄存器值,步骤如下:
- 主机发送起始信号。
- 主机发送要读取的 I2C 从设备地址。
- 读写控制位,因为是向 I2C 从设备发送数据,因此是写信号。
- 从机发送的 ACK 应答信号。
- 重新发送 START 信号。
- 主机发送要读取的寄存器地址。
- 从机发送的 ACK 应答信号。
- 重新发送 START 信号。
- 重新发送要读取的 I2C 从设备地址。
- 读写控制位,这里是读信号,表示接下来是从 I2C 从设备里面读取数据。
- 从机发送的 ACK 应答信号。
- 从 I2C 器件里面读取到的数据。
- 主机发出 NO ACK 信号,表示读取完成,不需要从机再发送 ACK 信号了。
- 主机发出 STOP 信号,停止 I2C 通信。
写时序的具体步骤:
- 开始信号
- 发送 I2C 设备地址,每个 I2C 器件都有一个设备地址,通过发送具体的设备地址来决定访问哪个 I2C 器件。这是一个 8 位的数据,其中高 7 位是设备地址,最后 1 位是读写位,为1 的话表示这是一个读操作,为 0 的话表示这是一个写操作。
- I2C 器件地址后面跟着一个读写位,为 0 表示写操作,为 1 表示读操作。
- 从机发送的 ACK 应答信号。
- 重新发送开始信号。
- 发送要写写入数据的寄存器地址。
- 从机发送的 ACK 应答信号。
- 发送要写入寄存器的数据。
- 从机发送的 ACK 应答信号。
- 停止信号。
U8g2库是一款开源库,专为Arduino和其他嵌入式平台设计,支持单色和彩色OLED显示屏,包括SSD1306、SSD1325、SSD1331、SH1106等控制器。它提供了丰富的绘图功能和文本显示功能,支持多种字体和Unicode字符,使用简单的API快速实现图形界面和动画效果,适用于资源受限的系统。
利用STM32f103的GPIO管脚、VCC和GND连接 OLED屏的I2C接口,采用cubemx设计一个HAL库程序框架,然后下载U82G源码,针对stm32f103和 0.96寸的I2C接口OLED屏,进行代码裁剪,然后移植到HAL程序程序中,完成OLED的各种显示。
RCC配置
SYS配置
I2C2配置
TIM1配置
时钟树配置
工程配置
U8g2库开源网址:https://github.com/olikraus/u8g2
U8g2支持多种显示驱动的屏幕,因为源码中也包含了各个驱动对应的文件(不需要自己去写屏幕底层驱动),为了减小整个工程的代码体积,在移植U8g2时,可以删除一些无用的文件。具体主要关注的是U8g2库文件中的csrc文件,对U8g2进行精简。
u8x8_d_xxx.c,xxx包括驱动的型号和屏幕分辨率。ssd1306驱动芯片的OLED,使用u8x8_ssd1306_128x64_noname.c这个文件,其它的屏幕驱动和分辨率的文件可以删掉。
此外,还有两个代码需要精简:
精简u8g2_d_setup.c
精简u8g2_d_memory.c
只留下u8g2_m_16_8_f这个函数,其它的函数要删掉或注释掉,否则编译时可能会提示内存不足
新建一个U8g2的Groups,将精简后的文件加入KEIL当中。
stm32_u8g2.h
- #ifndef __STM32_U8G2_H
- #define __STM32_U8G2_H
-
- /* Includes ------------------------------------------------------------------*/
- #include "main.h"
- #include "u8g2.h"
- /* USER CODE BEGIN Includes */
-
- /* USER CODE END Includes */
-
-
-
- /* USER CODE BEGIN Private defines */
-
- /* USER CODE END Private defines */
- #define u8 unsigned char // ?unsigned char ????
- #define MAX_LEN 128 //
- #define OLED_ADDRESS 0x78 // oled
- #define OLED_CMD 0x00 //
- #define OLED_DATA 0x40 //
-
- /* USER CODE BEGIN Prototypes */
- uint8_t u8x8_byte_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
- uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
- void u8g2Init(u8g2_t *u8g2);
- void draw(u8g2_t *u8g2);
- void testDrawPixelToFillScreen(u8g2_t *u8g2);
-
- #endif
stm32_u8g2.c
- #include "stm32_u8g2.h"
- #include "tim.h"
- #include "i2c.h"
-
-
- uint8_t u8x8_byte_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
- {
- /* 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;
-
- switch (msg)
- {
- case U8X8_MSG_BYTE_INIT:
- {
- /* add your custom code to init i2c subsystem */
- MX_I2C2_Init(); //I2C初始化
- }
- break;
-
- case U8X8_MSG_BYTE_START_TRANSFER:
- {
- buf_idx = 0;
- }
- break;
-
- case U8X8_MSG_BYTE_SEND:
- {
- data = (uint8_t *)arg_ptr;
-
- while (arg_int > 0)
- {
- buffer[buf_idx++] = *data;
- data++;
- arg_int--;
- }
- }
- break;
-
- case U8X8_MSG_BYTE_END_TRANSFER:
- {
- if (HAL_I2C_Master_Transmit(&hi2c2, OLED_ADDRESS, buffer, buf_idx, 1000) != HAL_OK)
- return 0;
- }
- break;
-
- case U8X8_MSG_BYTE_SET_DC:
- break;
-
- default:
- return 0;
- }
-
- return 1;
- }
-
-
-
- uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
- {
- 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
- Tims_delay_us(5);
- 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;
- }
-
- //U8g2的初始化,需要调用下面这个u8g2_Setup_ssd1306_128x64_noname_f函数,该函数的4个参数含义:
- //u8g2:传入的U8g2结构体
- //U8G2_R0:默认使用U8G2_R0即可(用于配置屏幕是否要旋转)
- //u8x8_byte_sw_i2c:使用软件IIC驱动,该函数由U8g2源码提供
- //u8x8_gpio_and_delay:就是上面我们写的配置函数
-
- void u8g2Init(u8g2_t *u8g2)
- {
- u8g2_Setup_ssd1306_i2c_128x64_noname_f(u8g2, U8G2_R0, u8x8_byte_hw_i2c, u8x8_gpio_and_delay); // 初始化u8g2 结构体
- u8g2_InitDisplay(u8g2); //
- u8g2_SetPowerSave(u8g2, 0); //
- u8g2_ClearBuffer(u8g2);
- }
-
-
- void draw(u8g2_t *u8g2)
- {
- u8g2_ClearBuffer(u8g2);
-
- u8g2_SetFontMode(u8g2, 1); /*字体模式选择*/
- u8g2_SetFontDirection(u8g2, 0); /*字体方向选择*/
- u8g2_SetFont(u8g2, u8g2_font_inb24_mf); /*字库选择*/
- u8g2_DrawStr(u8g2, 0, 20, "U");
-
- u8g2_SetFontDirection(u8g2, 1);
- u8g2_SetFont(u8g2, u8g2_font_inb30_mn);
- u8g2_DrawStr(u8g2, 21,8,"8");
-
- u8g2_SetFontDirection(u8g2, 0);
- u8g2_SetFont(u8g2, u8g2_font_inb24_mf);
- u8g2_DrawStr(u8g2, 51,30,"g");
- u8g2_DrawStr(u8g2, 67,30,"\xb2");
-
- u8g2_DrawHLine(u8g2, 2, 35, 47);
- u8g2_DrawHLine(u8g2, 3, 36, 47);
- u8g2_DrawVLine(u8g2, 45, 32, 12);
- u8g2_DrawVLine(u8g2, 46, 33, 12);
-
- u8g2_SetFont(u8g2, u8g2_font_4x6_tr);
- u8g2_DrawStr(u8g2, 1,54,"github.com/olikraus/u8g2");
-
- u8g2_SendBuffer(u8g2);
- HAL_Delay(1000);
- }
-
- //画点填充
- void testDrawPixelToFillScreen(u8g2_t *u8g2)
- {
- int t = 1000;
- u8g2_ClearBuffer(u8g2);
-
- for (int j = 0; j < 64; j++)
- {
- for (int i = 0; i < 128; i++)
- {
- u8g2_DrawPixel(u8g2,i, j);
- }
- }
- HAL_Delay(1000);
- }
test.h
- #ifndef __TEST_H
- #define __TEST_H
-
- #include "main.h"
- #include "u8g2.h"
-
- void testDrawProcess(u8g2_t *u8g2);
- void testShowFont(u8g2_t *u8g2);
- void testDrawFrame(u8g2_t *u8g2);
- void testDrawRBox(u8g2_t *u8g2);
- void testDrawCircle(u8g2_t *u8g2);
- void testDrawFilledEllipse(u8g2_t *u8g2);
- void testDrawMulti(u8g2_t *u8g2);
- void testDrawXBM(u8g2_t *u8g2);
-
- void u8g2DrawTest(u8g2_t *u8g2);
-
- #endif
test.c
- #include "test.h"
-
- //---------------U8g2测试函数
-
- #define SEND_BUFFER_DISPLAY_MS(u8g2, ms)\
- do {\
- u8g2_SendBuffer(u8g2); \
- HAL_Delay(ms);\
- }while(0);
-
-
- //进度条显示
- void testDrawProcess(u8g2_t *u8g2)
- {
- for(int i=10;i<=80;i=i+2)
- {
- u8g2_ClearBuffer(u8g2);
-
- char buff[20];
- sprintf(buff,"%d%%",(int)(i/80.0*100));
-
- u8g2_SetFont(u8g2,u8g2_font_ncenB12_tf);
- u8g2_DrawStr(u8g2,16,32,"STM32 U8g2");//字符显示
-
- u8g2_SetFont(u8g2,u8g2_font_ncenB08_tf);
- u8g2_DrawStr(u8g2,100,49,buff);//当前进度显示
-
- u8g2_DrawRBox(u8g2,16,40,i,10,4);//圆角填充框矩形框
- u8g2_DrawRFrame(u8g2,16,40,80,10,4);//圆角矩形
-
- u8g2_SendBuffer(u8g2);
- }
- HAL_Delay(500);
- }
-
-
- //字体测试 数字英文可选用 u8g2_font_ncenB..(粗) 系列字体
- //u8g2_font_unifont_t_symbols/u8g2_font_unifont_h_symbols(细 圆润)
- void testShowFont(u8g2_t *u8g2)
- {
- int t = 1000;
- char testStr[14] = "STM32F103C8T6";
-
- u8g2_ClearBuffer(u8g2);
-
- u8g2_SetFont(u8g2,u8g2_font_u8glib_4_tf);
- u8g2_DrawStr(u8g2,0,5,testStr);
- SEND_BUFFER_DISPLAY_MS(u8g2,t);
-
- u8g2_SetFont(u8g2,u8g2_font_ncenB08_tf);
- u8g2_DrawStr(u8g2,0,30,testStr);
- SEND_BUFFER_DISPLAY_MS(u8g2,t);
-
- u8g2_SetFont(u8g2,u8g2_font_ncenB10_tr);
- u8g2_DrawStr(u8g2,0,60,testStr);
- SEND_BUFFER_DISPLAY_MS(u8g2,t);
- }
-
- //画空心矩形
- void testDrawFrame(u8g2_t *u8g2)
- {
- int t = 1000;
- int x = 16;
- int y = 32;
- int w = 50;
- int h = 20;
- u8g2_ClearBuffer(u8g2);
- u8g2_DrawStr(u8g2,0, 15, "DrawFrame");
-
- u8g2_DrawFrame(u8g2, x, y, w, h);
- SEND_BUFFER_DISPLAY_MS(u8g2,t);
- u8g2_DrawFrame(u8g2, x+w+5, y-10, w-20, h+20);
- SEND_BUFFER_DISPLAY_MS(u8g2,t);
- }
-
- //画实心圆角矩形
- void testDrawRBox(u8g2_t *u8g2)
- {
- int t = 1000;
- int x = 16;
- int y = 32;
- int w = 50;
- int h = 20;
- int r = 3;
- u8g2_ClearBuffer(u8g2);
- u8g2_DrawStr(u8g2,0, 15, "DrawRBox");
-
- u8g2_DrawRBox(u8g2, x, y, w, h, r);
- SEND_BUFFER_DISPLAY_MS(u8g2,t);
- u8g2_DrawRBox(u8g2, x+w+5, y-10, w-20, h+20, r);
- SEND_BUFFER_DISPLAY_MS(u8g2,t);
- }
-
- //画空心圆
- void testDrawCircle(u8g2_t *u8g2)
- {
- int t = 600;
- int stx = 0; //画图起始x
- int sty = 16; //画图起始y
- int with = 16;//一个图块的间隔
- int r = 15; //圆的半径
- u8g2_ClearBuffer(u8g2);
- u8g2_DrawStr(u8g2, 0, 15, "DrawCircle");
-
- u8g2_DrawCircle(u8g2, stx, sty - 1 + with, r, U8G2_DRAW_UPPER_RIGHT); //右上
- SEND_BUFFER_DISPLAY_MS(u8g2,t);
- u8g2_DrawCircle(u8g2, stx + with, sty, r, U8G2_DRAW_LOWER_RIGHT); //右下
- SEND_BUFFER_DISPLAY_MS(u8g2,t);
- u8g2_DrawCircle(u8g2, stx - 1 + with * 3, sty - 1 + with, r, U8G2_DRAW_UPPER_LEFT); //左上
- SEND_BUFFER_DISPLAY_MS(u8g2,t);
- u8g2_DrawCircle(u8g2, stx - 1 + with * 4, sty, r, U8G2_DRAW_LOWER_LEFT); //左下
- SEND_BUFFER_DISPLAY_MS(u8g2,t);
- u8g2_DrawCircle(u8g2, stx - 1 + with * 2, sty - 1 + with * 2, r, U8G2_DRAW_ALL);//整个圆
- SEND_BUFFER_DISPLAY_MS(u8g2,t);
-
- u8g2_DrawCircle(u8g2, 32*3, 32, 31, U8G2_DRAW_ALL);//右侧整个圆
- SEND_BUFFER_DISPLAY_MS(u8g2,t);
- }
-
- //画实心椭圆
- void testDrawFilledEllipse(u8g2_t *u8g2)
- {
- int t = 800;
- int with = 16;//一个图块的间隔
- int rx = 27; //椭圆x方向的半径
- int ry = 22; //椭圆y方向的半径
- u8g2_ClearBuffer(u8g2);
- u8g2_DrawStr(u8g2,0, 14, "DrawFilledEllipse");
-
- SEND_BUFFER_DISPLAY_MS(u8g2,t);
- u8g2_DrawFilledEllipse(u8g2, 0, with, rx, ry, U8G2_DRAW_LOWER_RIGHT);//右下
- SEND_BUFFER_DISPLAY_MS(u8g2,t);
- u8g2_DrawFilledEllipse(u8g2, with * 4 - 1, with, rx, ry, U8G2_DRAW_LOWER_LEFT); //左下
- SEND_BUFFER_DISPLAY_MS(u8g2,t);
- u8g2_DrawFilledEllipse(u8g2, 0, with * 4 - 1, rx, ry, U8G2_DRAW_UPPER_RIGHT); //右上
- SEND_BUFFER_DISPLAY_MS(u8g2,t);
- u8g2_DrawFilledEllipse(u8g2, with * 4 - 1, with * 4 - 1, rx, ry, U8G2_DRAW_UPPER_LEFT); //左上
- SEND_BUFFER_DISPLAY_MS(u8g2,t);
- u8g2_DrawFilledEllipse(u8g2, with * 6, with * 2.5, rx, ry, U8G2_DRAW_ALL);//整个椭圆
- SEND_BUFFER_DISPLAY_MS(u8g2,t);
- }
-
- //环形测试
- void testDrawMulti(u8g2_t *u8g2)
- {
- u8g2_ClearBuffer(u8g2);
- for (int j = 0; j < 64; j+=16)
- {
- for (int i = 0; i < 128; i+=16)
- {
- u8g2_DrawPixel(u8g2, i, j);
- u8g2_SendBuffer(u8g2);
- }
- }
-
- //实心矩形逐渐变大
- u8g2_ClearBuffer(u8g2);
- for(int i=30; i>0; i-=2)
- {
- u8g2_DrawBox(u8g2,i*2,i,128-i*4,64-2*i);
- u8g2_SendBuffer(u8g2);
- }
- //空心矩形逐渐变小
- u8g2_ClearBuffer(u8g2);
- for(int i=0; i<32; i+=2)
- {
- u8g2_DrawFrame(u8g2,i*2,i,128-i*4,64-2*i);
- u8g2_SendBuffer(u8g2);
- }
-
- //实心圆角矩形逐渐变大
- u8g2_ClearBuffer(u8g2);
- for(int i=30; i>0; i-=2)
- {
- u8g2_DrawRBox(u8g2,i*2,i,128-i*4,64-2*i,10-i/3);
- u8g2_SendBuffer(u8g2);
- }
- //空心圆角矩形逐渐变小
- u8g2_ClearBuffer(u8g2);
- for(int i=0; i<32; i+=2)
- {
- u8g2_DrawRFrame(u8g2,i*2,i,128-i*4,64-2*i,10-i/3);
- u8g2_SendBuffer(u8g2);
- }
-
- //实心圆逐渐变大
- u8g2_ClearBuffer(u8g2);
- for(int i=2; i<64; i+=3)
- {
- u8g2_DrawDisc(u8g2,64,32,i, U8G2_DRAW_ALL);
- u8g2_SendBuffer(u8g2);
- }
- //空心圆逐渐变小
- u8g2_ClearBuffer(u8g2);
- for(int i=64; i>0; i-=3)
- {
- u8g2_DrawCircle(u8g2,64,32,i, U8G2_DRAW_ALL);
- u8g2_SendBuffer(u8g2);
- }
-
- //实心椭圆逐渐变大
- u8g2_ClearBuffer(u8g2);
- for(int i=2; i<32; i+=3)
- {
- u8g2_DrawFilledEllipse(u8g2,64,32, i*2, i, U8G2_DRAW_ALL);
- u8g2_SendBuffer(u8g2);
- }
- //空心椭圆逐渐变小
- u8g2_ClearBuffer(u8g2);
- for(int i=32; i>0; i-=3)
- {
- u8g2_DrawEllipse(u8g2,64,32, i*2, i, U8G2_DRAW_ALL);
- u8g2_SendBuffer(u8g2);
- }
- }
-
-
- // width: 128, height: 48
- const unsigned char bilibili[] U8X8_PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xe0, 0x03, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xf0, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x01, 0xfc, 0x00, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x03, 0xfc, 0x00, 0x00, 0x3c, 0xc0, 0x0f, 0x00, 0x80, 0x03, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0x07, 0xfc, 0x00, 0x00, 0x3c, 0xc0, 0x0f, 0x00, 0xc0, 0x07, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xfc, 0x00, 0x00, 0x3c, 0x80, 0x0f, 0x00, 0xc0, 0x07, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x80, 0x0f, 0xf8, 0x00, 0x00, 0x3c, 0x80, 0x0f, 0x00, 0x80, 0x07, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x78, 0x80, 0x0f, 0x00, 0x80, 0x07, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x78, 0x80, 0x0f, 0x00, 0x80, 0x07, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x80, 0x79, 0x80, 0x0f, 0x00, 0x98, 0x07, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0xe0, 0x79, 0x9f, 0x0f, 0x00, 0xbe, 0xe7, 0x01, 0xc0, 0x07, 0x10, 0x40, 0x00, 0x1f, 0xf8, 0x00, 0xe0, 0x7b, 0x1f, 0x0f, 0x00, 0xbe, 0xe7, 0x01, 0xc0, 0x87, 0x1f, 0xe0, 0x0f, 0x1f, 0xf8, 0x00, 0xe0, 0x7b, 0x1e, 0x0f, 0x00, 0x3e, 0xe7, 0x01, 0xc0, 0xe7, 0x3f, 0xe0, 0x3f, 0x1f, 0xf0, 0x00, 0xe0, 0x7b, 0x1e, 0x0f, 0x00, 0x3e, 0xe7, 0x01, 0xc0, 0xe7, 0x3f, 0xe0, 0x3f, 0x1f, 0xf0, 0x00, 0x60, 0x71, 0x1e, 0x0f, 0x00, 0x34, 0xe7, 0x01, 0xc0, 0xe7, 0x07, 0x00, 0x3f, 0x1f, 0xf0, 0x00, 0x00, 0x70, 0x00, 0x1f, 0x00, 0x00, 0x07, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0xc0, 0x73, 0x1e, 0x1f, 0x00, 0x3c, 0xc7, 0x01, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0xc0, 0x73, 0x1e, 0x1f, 0x00, 0x7c, 0xe7, 0x01, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0xc0, 0x73, 0x1e, 0x1f, 0x00, 0x7c, 0xef, 0x01, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x01, 0xc0, 0x77, 0x1e, 0x1e, 0x00, 0x7c, 0xef, 0x01, 0xc0, 0x07, 0x00, 0x03, 0x00, 0x1f, 0xf0, 0xff, 0xc1, 0xf7, 0x1e, 0xfe, 0x1f, 0x78, 0xef, 0x01, 0xc0, 0x07, 0x70, 0x37, 0x00, 0x1f, 0xe0, 0xff, 0x87, 0xf7, 0x1e, 0xfe, 0xff, 0x78, 0xee, 0x01, 0xc0, 0x07, 0xe0, 0x3f, 0x00, 0x1f, 0xe0, 0xff, 0x9f, 0xf7, 0x1e, 0xfe, 0xff, 0x79, 0xce, 0x01, 0xc0, 0x07, 0xc0, 0x18, 0x00, 0x1f, 0xe0, 0xff, 0xbf, 0xe7, 0x1e, 0xfe, 0xff, 0x7b, 0xce, 0x01, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0xc7, 0xbf, 0xe7, 0x1e, 0xfe, 0xf8, 0x77, 0xce, 0x01, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0x0f, 0x3f, 0xe7, 0x1c, 0xfe, 0xf0, 0x77, 0xce, 0x03, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0xcf, 0x3f, 0xe7, 0x1c, 0xfe, 0xf8, 0xf3, 0xce, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xe0, 0xef, 0x1f, 0xe7, 0x1c, 0xfe, 0xfe, 0xf1, 0xce, 0x03, 0x80, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xe0, 0xff, 0x0f, 0xcf, 0x1c, 0xfc, 0xff, 0xf0, 0xc0, 0x03, 0x00, 0xff, 0xff, 0xff, 0xff, 0x07, 0xe0, 0xff, 0x03, 0x06, 0x1c, 0xfc, 0x7f, 0x60, 0xc0, 0x01, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x03, 0xe0, 0xff, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
- // width: 128, height: 48
- const unsigned char three_support[] U8X8_PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x80, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x03, 0x00, 0x00, 0x80, 0x0f, 0xf0, 0x01, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0x00, 0xc0, 0xfd, 0xff, 0x00, 0x00, 0xc0, 0x7f, 0xfe, 0x01, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xe0, 0xfd, 0xff, 0x01, 0x00, 0xc0, 0x1f, 0xf8, 0x03, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xe0, 0xfd, 0xff, 0x01, 0x00, 0xc0, 0x0f, 0xf0, 0x03, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0xe0, 0xfd, 0xff, 0x01, 0x00, 0xc0, 0x67, 0xe6, 0x03, 0x00, 0x00, 0xfc, 0xff, 0x03, 0x00, 0x00, 0xe0, 0xfd, 0xff, 0x01, 0x00, 0xc0, 0x67, 0xe6, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x01, 0x00, 0x00, 0xe0, 0xfd, 0xff, 0x00, 0x00, 0xc0, 0x67, 0xe6, 0x03, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0x00, 0xe0, 0xfd, 0xff, 0x00, 0x00, 0xc0, 0x67, 0xee, 0x03, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0xe0, 0xfd, 0xff, 0x00, 0x00, 0x80, 0x7f, 0xfe, 0x01, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0xe0, 0xfd, 0xff, 0x00, 0x00, 0x80, 0x7f, 0xfe, 0x01, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00, 0xe0, 0xfd, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00, 0xe0, 0xfd, 0x7f, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x00, 0xf8, 0xf9, 0x01, 0x00, 0x00, 0xe0, 0xfd, 0x7f, 0x00, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0xf8, 0xf0, 0x00, 0x00, 0x00, 0xe0, 0xfd, 0x1f, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0x00, 0x30, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-
- void testDrawXBM(u8g2_t *u8g2)
- {
- int t = 1000;
- u8g2_ClearBuffer(u8g2);
- u8g2_DrawStr(u8g2,0, 14, "DrawXBM");
-
- u8g2_DrawXBM(u8g2,0, 16, 128, 48, bilibili);
- SEND_BUFFER_DISPLAY_MS(u8g2,t);
-
- u8g2_ClearBuffer(u8g2);
- u8g2_DrawStr(u8g2,0, 14, "bilibili");
- u8g2_DrawXBM(u8g2,0, 16, 128, 48, three_support);
- SEND_BUFFER_DISPLAY_MS(u8g2,t);
- }
-
- void u8g2DrawTest(u8g2_t *u8g2)
- {
- testDrawProcess(u8g2);
- testDrawMulti(u8g2);
- //testDrawFrame(u8g2);
- //testDrawRBox(u8g2);
- //testDrawCircle(u8g2);
- //testDrawFilledEllipse(u8g2);
- testShowFont(u8g2);
- testDrawXBM(u8g2);
-
- }
- int main(void)
- {
- /* USER CODE BEGIN 1 */
-
- /* USER CODE END 1 */
-
- /* MCU Configuration--------------------------------------------------------*/
-
- /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
- HAL_Init();
-
- /* USER CODE BEGIN Init */
-
- /* USER CODE END Init */
-
- /* Configure the system clock */
- SystemClock_Config();
-
- /* USER CODE BEGIN SysInit */
-
- /* USER CODE END SysInit */
-
- /* Initialize all configured peripherals */
- MX_GPIO_Init();
- MX_I2C2_Init();
- MX_TIM1_Init();
- /* USER CODE BEGIN 2 */
- u8g2_t u8g2;
- u8g2Init(&u8g2);
- /* USER CODE END 2 */
-
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
- /* USER CODE END WHILE */
-
- /* USER CODE BEGIN 3 */
-
- u8g2_FirstPage(&u8g2);
- do
- {
- draw(&u8g2);
-
- u8g2DrawTest(&u8g2);
- } while (u8g2_NextPage(&u8g2));
-
-
- }
- /* USER CODE END 3 */
- }
为了隐私安全,中间打了马赛克
通过实践,我不仅深入理解了I2C协议的工作原理和时序要求,还掌握了如何驱动OLED屏幕进行文本和图形显示,以及使用开源GUI库U8G2在stm32平台上的移植方法。
在理论知识的基础上,实际操作中我意识到了硬件连接的重要性,如何利用CubeMX设计HAL库的程序框架,配置GPIO管脚和I2C接口,确保设备能够正确工作。这一步骤是整个项目的基础,直接影响后续功能的实现和稳定性。
移植U8G2库到stm32平台并不是一件简单的事情,需要对库进行适当裁剪和调整,以兼容目标硬件和显示需求。在这个过程中,我学会了如何根据具体的项目需求修改代码,并通过调试解决遇到的各种问题,如显示不正常或者功能无法完全实现的情况。
最后通过展示个人学号和姓名的文本显示,我体验到了GUI图形界面在嵌入式系统中的应用潜力。这种直观和互动性强的界面不仅能提升用户体验,也为物联网设备的应用场景增添了更多可能性。
参考博客:
https://blog.csdn.net/weixin_47932709/article/details/108938838