#申请原创# @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演示效果:
附件
|
使用了软件和硬件两种方式,运用了SPI和I2C两种通信,在MM32平台均实现了OLED的显示,并移植了基本涵盖了u8g2,用户基于该**可快速在灵动平台搭建OLED开发,其软件模拟也可移植到其他平台。功能齐全,讲解详细。