#申请原创# @21小跑堂
简介
OLED,是一种有机电质发光器件,又称为有机电激光显示。与之前提到的LCD1602、LCD1284相比,具有更低的功耗、更快的响应速度、更宽的可视角度、更高的显示分辨率、更轻的质量等等优点,而被广泛使用。淘宝上找到一款常见的是由SSD1306驱动的0.96寸的OLED,驱动接口有3线串行、4线串行和I2C这3种接口类型;另外OLED还有支持并行接口驱动的,这个会在后面的帖子来给大家分享。
u8g2是用于嵌入式设备支持单色OLED或LCD的图形库软件,支持市面上决大多数的显示屏驱动控制器,SSD1306就包含在内。u8g2图形库包含3个部分:u8g2、u8x8和u8log,其中u8g2包括了所有的图形功能,支持多种字体;u8x8可以直接将显示内容输出到显示屏显示,无需显示缓存;u8log则是一个输出终端的功能。另外u8g2还支持3种不同的绘图模式:全屏缓冲模式、页面模式和u8x8仅字符模式;全屏缓冲模式和页面模式支持所有的图形,区别在于所占用的显示缓存大小不同,从而致使刷新速度的快慢;而u8x8仅字符模式不需要显示缓存,可以直接将需要显示的内容输出显示,缺点就是不支持u8g8的图形显示,同时也依赖于显示驱动芯片是否支持该模式。
实现功能
1、OLED底层驱动:分别使用硬件I2C、软件模拟I2C、硬件SPI、软件模拟SPI这4种方式来实现对OLED显示屏的驱动,并实现一幅动画效果的演示。 2、u8g2移植:基于I2C和SPI这两种不同接口的驱动方式,分别移植u8g2的GUI,对移植过程和注意事项进行说明。 3、u8g2演示:通过一个简单的示例完成u8g2的效果演示。
1、OLED底层驱动
使用自制的MM32F0140最小系统板,结合I2C和SPI接口的两块0.96寸的OLED模块,实现驱动显示。在上图中SPI接口的OLED模块中,CS是片选信号连接PA4、DC是数据或命令切换连接PB0、RES是复位连接PB1、DI是SPI数据线连接PB5、DO是SPI时钟线连接PB7;在I2C接口的OLED中,SCL和SDA与MM32F0140的硬件I2C相连接,分别连接PB10和PB11。按照这样线序连接方式,一方面是按照MCU引脚I2C/SPI复用功能连接的,可以通过硬件I2C/SPI接口来驱动OLED显示;另一方面可以直接使用GPIO来模拟I2C/SPI时序来驱动OLED显示,如下图所示:
在OLED初始化过程中先根据宏定义对MCU的I2C和SPI进行初始化配置,然后配置OLED显示屏有参数并清空显示内容,最后通过TASK调用OLED_Handler来显示一个动画效果。对于使用硬件I2C还是软件模拟I2C、硬件SPI还是软件模拟SPI可以通过OLED_HW_I2C和OLED_HW_SPI宏来配置,参考代码如下所示: - void OLED_I2C_SendData(uint8_t Address, uint8_t Data)
- {
- #if OLED_HW_I2C /* 硬件I2C */
- I2C_SendData(I2C1, Address);
- while(!I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE));
- I2C_SendData(I2C1, Data);
- while(!I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE));
- I2C_GenerateSTOP(I2C1, ENABLE);
- while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_STOP_DET));
- #else /* 模拟I2C */
- sI2C_GenerateStart(&sI2C_OLED);
- sI2C_WriteByte(&sI2C_OLED, 0x78);
- if(sI2C_GetACK(&sI2C_OLED))
- {
- sI2C_GenerateStop(&sI2C_OLED); return;
- }
- sI2C_WriteByte(&sI2C_OLED, Address);
- if(sI2C_GetACK(&sI2C_OLED))
- {
- sI2C_GenerateStop(&sI2C_OLED); return;
- }
- sI2C_WriteByte(&sI2C_OLED, Data);
- if(sI2C_GetACK(&sI2C_OLED))
- {
- sI2C_GenerateStop(&sI2C_OLED); return;
- }
- sI2C_GenerateStop(&sI2C_OLED);
- #endif
- }
- void OLED_SPI_SendData(uint8_t Data)
- {
- #if OLED_HW_SPI /* 硬件SPI */
- uint32_t Timeout = 0;
- SPI_SendData(SPI1, Data);
- while(!SPI_GetFlagStatus(SPI1, SPI_FLAG_TXEPT))
- {
- if(Timeout++ > 0xFFFF) break;
- }
- #else /* 模拟SPI */
- for(uint8_t i = 0; i < 8; i++)
- {
- if((Data << i) & 0x80) OLED_DI_H();
- else OLED_DI_L();
- OLED_DO_H();
- OLED_DO_L();
- }
- #endif
- }
- void OLED_WriteCMD(uint8_t Command)
- {
- OLED_I2C_SendData(0x00, Command);
- OLED_DC_L();
- OLED_CS_L();
- OLED_SPI_SendData(Command);
- OLED_CS_H();
- }
- void OLED_WriteDAT(uint8_t Data)
- {
- OLED_I2C_SendData(0x40, Data);
- OLED_DC_H();
- OLED_CS_L();
- OLED_SPI_SendData(Data);
- OLED_CS_H();
- }
- void OLED_WriteBuffer(uint8_t *Buffer, uint8_t Length)
- {
- for(uint8_t i = 0; i < Length; i++)
- {
- OLED_WriteDAT(*Buffer++);
- }
- }
- void OLED_InitI2C(void)
- {
- #if OLED_HW_I2C /* 硬件I2C */
- GPIO_InitTypeDef GPIO_InitStructure;
- I2C_InitTypeDef I2C1_InitStructure;
- RCC_APB1PeriphClockCmd(RCC_APB1ENR_I2C1, ENABLE);
- I2C_StructInit(&I2C1_InitStructure);
- I2C1_InitStructure.I2C_Mode = I2C_Mode_MASTER;
- I2C1_InitStructure.I2C_OwnAddress = 0;
- I2C1_InitStructure.I2C_Speed = I2C_Speed_FAST;
- I2C1_InitStructure.I2C_ClockSpeed = 400000;
- I2C_Init(I2C1, &I2C1_InitStructure);
- I2C_Send7bitAddress(I2C1, 0x78, I2C_Direction_Transmitter);
- I2C_Cmd(I2C1, ENABLE);
- RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOB, ENABLE);
- GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_1);
- GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_1);
- GPIO_StructInit(&GPIO_InitStructure);
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
- GPIO_Init(GPIOB, &GPIO_InitStructure);
- #else /* 模拟I2C */
- sI2C_Init(&sI2C_OLED);
- #endif
- }
- void OLED_InitSPI(void)
- {
- #if OLED_HW_SPI /* 硬件SPI */
- GPIO_InitTypeDef GPIO_InitStructure;
- SPI_InitTypeDef SPI_InitStructure;
- RCC_APB2PeriphClockCmd(RCC_APB2ENR_SPI1, ENABLE);
- SPI_StructInit(&SPI_InitStructure);
- SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
- SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
- SPI_InitStructure.SPI_DataWidth = 8;
- SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
- SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
- SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
- SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
- SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
- SPI_Init(SPI1, &SPI_InitStructure);
- SPI_Cmd(SPI1, ENABLE);
- RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);
- GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_0); /* PA4 SPI1_NSS */
- GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_0); /* PA5 SPI1_SCK */
- GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_0); /* PA6 SPI1_MISO */
- GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_0); /* PA7 SPI1_MOSI */
- GPIO_StructInit(&GPIO_InitStructure);
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIO_Init(GPIOA, &GPIO_InitStructure);
- GPIO_StructInit(&GPIO_InitStructure);
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
- GPIO_Init(GPIOA, &GPIO_InitStructure);
- SPI_BiDirectionalLineConfig(SPI1, SPI_Direction_Rx);
- SPI_BiDirectionalLineConfig(SPI1, SPI_Direction_Tx);
- RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOB, ENABLE);
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_Init(GPIOB, &GPIO_InitStructure);
- #else /* 模拟SPI */
- GPIO_InitTypeDef GPIO_InitStructure;
- RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_Init(GPIOA, &GPIO_InitStructure);
- RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOB, ENABLE);
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_Init(GPIOB, &GPIO_InitStructure);
- OLED_CS_H(); OLED_DC_L();
- OLED_DI_L(); OLED_DO_L();
- #endif
- OLED_RES_H(); SysTick_DelayMS(100);
- OLED_RES_L(); SysTick_DelayMS(100);
- OLED_RES_H(); SysTick_DelayMS(100);
- }
- void OLED_InitCFG(void)
- {
- SysTick_DelayMS(1000); /* 这里的延时很重要,上电后延时,没有错误的冗余设计 */
- OLED_WriteCMD(0xAE); /* Display Off */
- OLED_WriteCMD(0x20); /* Set Memory Addressing Mode */
- OLED_WriteCMD(0x10); /* 00 Horizontal Addressing Mode
- 01 Vertical Addressing Mode
- 10 Page Addressing Mode (RESET)
- 11 Invalid */
- OLED_WriteCMD(0xB0); /* Set Page Start Address for Page Addressing Mode,0-7 */
- OLED_WriteCMD(0xC8); /* Set COM Output Scan Direction */
- OLED_WriteCMD(0x00); /* Set Low Column Address */
- OLED_WriteCMD(0x10); /* Set High Column Address */
- OLED_WriteCMD(0x40); /* Set Start Line Address */
- OLED_WriteCMD(0x81); /* Set Contrast Control Register */
- OLED_WriteCMD(0xFF); /* Brightness 0x00~0xff */
- OLED_WriteCMD(0xA1); /* Set Segment Re-map 0 to 127 */
- OLED_WriteCMD(0xA6); /* Set Normal Display */
- OLED_WriteCMD(0xA8); /* Set Multiplex Ratio(1 to 64) */
- OLED_WriteCMD(0x3F);
- OLED_WriteCMD(0xA4); /* 0xA4: Output Follows RAM Content
- 0xA5: Output Ignores RAM Content */
- OLED_WriteCMD(0xD3); /* Aet Display offset */
- OLED_WriteCMD(0x00); /* Not Offset */
- OLED_WriteCMD(0xD5); /* Set Display Clock Divide Ratio/Oscillator Frequency */
- OLED_WriteCMD(0xF0); /* Set Divide Ratio */
- OLED_WriteCMD(0xD9); /* Set Pre-charge Period */
- OLED_WriteCMD(0x22);
- OLED_WriteCMD(0xDA); /* Set Com Pins Hardware Configuration */
- OLED_WriteCMD(0x12);
- OLED_WriteCMD(0xDB); /* Set VCOMH */
- OLED_WriteCMD(0x20); /* 0x20=0.77*VCC */
- OLED_WriteCMD(0x8D); /* Set DC-DC Enable */
- OLED_WriteCMD(0x14);
- OLED_WriteCMD(0xAF); /* Turn On OLED Panel */
- }
- void OLED_SetPosition(uint8_t x, uint8_t y)
- {
- OLED_WriteCMD(0xB0 + y);
- OLED_WriteCMD(((x & 0xF0) >> 4) | 0x10);
- OLED_WriteCMD(((x & 0x0F) >> 0) | 0x00);
- }
- void OLED_Clear(uint8_t Data)
- {
- uint8_t x = 0, y = 0;
- for(y = 0; y < 8; y++)
- {
- OLED_SetPosition(0, y);
- for(x = 0; x < 128; x++)
- {
- OLED_WriteDAT(Data);
- }
- }
- }
- void OLED_Init(void)
- {
- OLED_InitI2C();
- OLED_InitSPI();
- OLED_InitCFG();
- OLED_Clear(0x00);
- TASK_Append(TASK_ID_OLED, OLED_Handler, 50);
- }
- #include "DOG02.c"
- #include "DOG03.c"
- #include "DOG04.c"
- #include "DOG05.c"
- #include "DOG06.c"
- #include "DOG07.c"
- #include "DOG08.c"
- #include "DOG09.c"
- #include "DOG10.c"
- #include "DOG11.c"
- #include "DOG12.c"
- #include "DOG13.c"
- #include "DOG14.c"
- #include "DOG15.c"
- #include "DOG16.c"
- #include "DOG17.c"
- #include "DOG18.c"
- #include "DOG19.c"
- #include "DOG20.c"
- #include "DOG21.c"
- #include "DOG22.c"
- #include "DOG23.c"
- #include "DOG24.c"
- #include "DOG25.c"
- #include "DOG26.c"
- #include "DOG27.c"
- void OLED_DrawImage(uint8_t Width, uint8_t Height, const uint8_t *ImageData)
- {
- uint8_t x = 0, y = 0;
- uint8_t Buffer[0x80];
- uint16_t Index = 0;
- for(y = 0; y < Height / 8; y++)
- {
- OLED_SetPosition(32, y);
- for(x = 0; x < Width; x++)
- {
- Buffer[x] = ~ImageData[Index++];
- }
- OLED_WriteBuffer(Buffer, Width);
- }
- }
- void OLED_Handler(void)
- {
- static uint8_t Index = 0;
- switch(Index)
- {
- case 0 : OLED_DrawImage(64, 64, gImage_DOG02); break;
- case 1 : OLED_DrawImage(64, 64, gImage_DOG03); break;
- case 2 : OLED_DrawImage(64, 64, gImage_DOG04); break;
- case 3 : OLED_DrawImage(64, 64, gImage_DOG05); break;
- case 4 : OLED_DrawImage(64, 64, gImage_DOG06); break;
- case 5 : OLED_DrawImage(64, 64, gImage_DOG07); break;
- case 6 : OLED_DrawImage(64, 64, gImage_DOG08); break;
- case 7 : OLED_DrawImage(64, 64, gImage_DOG09); break;
- case 8 : OLED_DrawImage(64, 64, gImage_DOG10); break;
- case 9 : OLED_DrawImage(64, 64, gImage_DOG11); break;
- case 10: OLED_DrawImage(64, 64, gImage_DOG12); break;
- case 11: OLED_DrawImage(64, 64, gImage_DOG13); break;
- case 12: OLED_DrawImage(64, 64, gImage_DOG14); break;
- case 13: OLED_DrawImage(64, 64, gImage_DOG15); break;
- case 14: OLED_DrawImage(64, 64, gImage_DOG16); break;
- case 15: OLED_DrawImage(64, 64, gImage_DOG17); break;
- case 16: OLED_DrawImage(64, 64, gImage_DOG18); break;
- case 17: OLED_DrawImage(64, 64, gImage_DOG19); break;
- case 18: OLED_DrawImage(64, 64, gImage_DOG20); break;
- case 19: OLED_DrawImage(64, 64, gImage_DOG21); break;
- case 20: OLED_DrawImage(64, 64, gImage_DOG22); break;
- case 21: OLED_DrawImage(64, 64, gImage_DOG23); break;
- case 22: OLED_DrawImage(64, 64, gImage_DOG24); break;
- case 23: OLED_DrawImage(64, 64, gImage_DOG25); break;
- case 24: OLED_DrawImage(64, 64, gImage_DOG26); break;
- case 25: OLED_DrawImage(64, 64, gImage_DOG27); break;
- }
- Index = (Index + 1) % 26;
- }
OLED底层驱动显示效果:
2、u8g2移植
首先我们到https://github.com/olikraus/u8g2这个网址下载开源代码,当前版本中有基于C和C++这两种代码库,并提供了示例参考例程;我们使用的是基于C的开发库,所以将cscr文件中的源代码添加到工程中,根据文件类型和功能,对其进行分文件夹归类,最终如附件源码工程中所示;然后将u8g2的源代码添加到工程中,其中包含了u8g2的图形实现的功能程序,也有根据显示驱动来添加的底层驱动文件,最后对工程头文件包含路径进行设置,具体参考附件中的源代码工程;接下来我们就可以通过代码来实现,因为我们同时是驱动两个OLED,分别是I2C和SPI接口的,所以在移植的时候,也同时包含了这两种实现方式;我们在main.c文件中实现接口和功能,先根据不同的接口定义2个u8g2结构体变量并进行初始化: - u8g2_t u8g2_spi;
- u8g2_t u8g2_i2c;
- void u8g2_UserInit(void)
- {
- /* 初始化u8g2 */
- u8g2_Setup_ssd1306_128x64_noname_f(&u8g2_spi, U8G2_R0, u8x8_byte_4wire_sw_spi, u8x8_mm32_spi_gpio_and_delay);
- /* 初始化显示器 */
- u8g2_InitDisplay(&u8g2_spi);
- /* 唤醒显示器 */
- u8g2_SetPowerSave(&u8g2_spi, 0);
- /* 设置英文字体 */
- u8g2_SetFont(&u8g2_spi, u8g2_font_6x12_mr);
- /* 初始化u8g2 */
- u8g2_Setup_ssd1306_i2c_128x64_noname_f(&u8g2_i2c, U8G2_R0, u8x8_byte_sw_i2c, u8x8_mm32_i2c_gpio_and_delay);
- /* 初始化显示器 */
- u8g2_InitDisplay(&u8g2_i2c);
- /* 唤醒显示器 */
- u8g2_SetPowerSave(&u8g2_i2c, 0);
- /* 设置英文字体 */
- u8g2_SetFont(&u8g2_i2c, u8g2_font_6x12_mr);
- TASK_Append(TASK_ID_U8G2, u8g2_UserHandler, 50);
- }
在初始化的时候,我们发现I2C和SPI调用的接口函数是不一样的,SPI接口调用的是u8g2_Setup_ssd1306_128x64_noname_f函数,I2C接口调用的是u8g2_Setup_ssd1306_i2c_128x64_noname_f函数;在这两个函数中形参功能都是类似的,第一个参数是全局u8g2结构体变量,第二个参数用于指示显示方向,第3个参数用于指明u8g2驱动操作函数,第4个参数用于指明u8g2底层GPIO操作的回调函数;不管是SPI还是I2C,对于u8g2底层驱动来说,都是用模拟时序的方式来实现的,所以在移植u8g2时,对之前的OLED_HW_I2C和OLED_HW_SPI这两个宏都要设置为0。
u8g2_Setup_ssd1306_128x64_noname_f和u8g2_Setup_ssd1306_i2c_128x64_noname_f这两个函数在u8g2_d_setup.c文件中,仅需要留下这两个函数就可以,将其它的函数进行屏蔽。在u8g2_d_memory.c文件中定义memory操作功能函数,我们这边选用u8g2_m_16_8_f这个函数,将其它的函数进行屏蔽。在后面示例中需要显示字符,所以就需要选择一个系统字库,通过调用u8g2_SetFont来进行设置;字体的选择在u8g2_fonts.c文件中,保留需要使用的字库,对其它的字库进行屏蔽。如上这些对没有使用的函数或者字体进行屏蔽是根据显示驱动、MEMORY管理和字体选择来决定的,屏蔽也是为了节省代码空间和未使用到的报错。
最后就是要实现底层对GPIO操作和延时的回调函数,供u8g2底层驱动来调用;在SPI接口调用时使用到SPI_DATA、SPI_CLOCK、SPI_CS、DC、RESET和DELAY_NANO,在I2C接口调用时使用到了I2C_DATA、I2C_CLOCK和DELAY_I2C;具体的函数接口实现如下所示: - uint8_t u8x8_mm32_spi_gpio_and_delay(
- U8X8_UNUSED u8x8_t *u8x8,
- U8X8_UNUSED uint8_t msg,
- U8X8_UNUSED uint8_t arg_int,
- U8X8_UNUSED void *arg_ptr)
- {
- switch (msg)
- {
- case U8X8_MSG_GPIO_AND_DELAY_INIT:
- OLED_Init();
- break;
- case U8X8_MSG_GPIO_SPI_DATA:
- if(arg_int) OLED_DI_H();
- else OLED_DI_L();
- break;
- case U8X8_MSG_GPIO_SPI_CLOCK:
- if(arg_int) OLED_DO_H();
- else OLED_DO_L();
- break;
- case U8X8_MSG_GPIO_CS:
- if(arg_int) OLED_CS_H();
- else OLED_CS_L();
- break;
- case U8X8_MSG_GPIO_DC:
- if(arg_int) OLED_DC_H();
- else OLED_DC_L();
- break;
- case U8X8_MSG_GPIO_RESET:
- if(arg_int) OLED_RES_H();
- else OLED_RES_L();
- break;
- case U8X8_MSG_DELAY_NANO:
- __nop();
- break;
- default: return 0;
- }
- return 1;
- }
- uint8_t u8x8_mm32_i2c_gpio_and_delay(
- U8X8_UNUSED u8x8_t *u8x8,
- U8X8_UNUSED uint8_t msg,
- U8X8_UNUSED uint8_t arg_int,
- U8X8_UNUSED void *arg_ptr)
- {
- switch (msg)
- {
- case U8X8_MSG_GPIO_AND_DELAY_INIT:
- OLED_Init();
- break;
- case U8X8_MSG_GPIO_I2C_DATA:
- if(arg_int) OLED_SDA_H();
- else OLED_SDA_L();
- break;
- case U8X8_MSG_GPIO_I2C_CLOCK:
- if(arg_int) OLED_SCL_H();
- else OLED_SCL_L();
- break;
- case U8X8_MSG_DELAY_I2C:
- __nop();
- break;
- default: return 0;
- }
- return 1;
- }
至此u8g2移植和初始化就完成了。
3、u8g2演示 演示的功能是分别在I2C和SPI接口的OLED显示屏上显示3个半径相同坐标不同的圆,圆半径由小到大,再由大到小进行变化显示,在屏幕顶端居中的位置显示当前的圆半径数值,具体代码实现如下: - void u8g2_UserHandler(void)
- {
- static int rad = 0, direction = 0, select = 0;
- char str[10];
- memset(str, 0, sizeof(str));
- if(direction == 0)
- {
- if(++rad == 0x1F) direction = 1;
- }
- else
- {
- if(--rad == 0x01) direction = 0;
- }
- sprintf(str, "%02d", rad);
- if(select == 0)
- {
- /* 清空缓冲区的内容 */
- u8g2_ClearBuffer(&u8g2_spi);
- /* 画圆 */
- u8g2_DrawCircle(&u8g2_spi, 32, 32, rad, U8G2_DRAW_ALL);
- u8g2_DrawCircle(&u8g2_spi, 64, 32, rad, U8G2_DRAW_ALL);
- u8g2_DrawCircle(&u8g2_spi, 96, 32, rad, U8G2_DRAW_ALL);
- u8g2_DrawStr(&u8g2_spi, 58, 10, str);
- /* 绘制缓冲区的内容 */
- u8g2_SendBuffer(&u8g2_spi);
- }
- else
- {
- /* 清空缓冲区的内容 */
- u8g2_ClearBuffer(&u8g2_i2c);
- /* 画圆 */
- u8g2_DrawCircle(&u8g2_i2c, 32, 32, rad, U8G2_DRAW_ALL);
- u8g2_DrawCircle(&u8g2_i2c, 64, 32, rad, U8G2_DRAW_ALL);
- u8g2_DrawCircle(&u8g2_i2c, 96, 32, rad, U8G2_DRAW_ALL);
- u8g2_DrawStr(&u8g2_i2c, 58, 10, str);
- /* 绘制缓冲区的内容 */
- u8g2_SendBuffer(&u8g2_i2c);
- }
- if((direction == 0) && (rad == 1))
- {
- if(select == 0) select = 1;
- else select = 0;
- }
- }
GUI演示效果:
附件
|