U8G2图形库介绍
U8g2:用于单色显示的库,版本 2
U8g2 是一个用于嵌入式设备的单色图形库。U8g2支持单色OLED和LCD,包括以下控制器:SSD1305, SSD1306, SSD1309, SSD1316, SSD1320, SSD1322, SSD1325, SSD1327, SSD1329, SSD1606, SSD1607,895, SH11607,84D1607,SH11607,84D1607,94D1607,94D1607,84D1607,4D1607,4D1607,4D1607,84D1807 ,PCF8812,HX1230,UC1601,UC1604,UC1608,UC1610,UC1611,UC1617,UC1638,UC1701,ST7511,ST7528,ST7565,ST7567,ST7571,ST7586,ST7588,ST75256,ST75320,NT7534,ST7920,IST3020,IST7920,LD7032,KS0108 、KS0713、HD44102、T7932、SED1520、SBN1661、IL3820、MAX7219(完整列表见此处)。
Arduino 库 U8g2 可以从 Arduino IDE 的库管理器安装。U8g2 还包括 U8x8 库:
U8g2:
- 包括所有图形程序(线/框/圆绘制)。
- 支持多种字体。(几乎)对字体高度没有限制。
- 需要微控制器中的一些内存来呈现显示。
U8x8:
- 仅文本输出(字符)设备。
- 仅允许适合 8x8 像素网格的字体。
- 直接写入显示器。微控制器中不需要缓冲器。
移植准备工作
移植U8G2图像库需要准备好,U8G2的源码 U8g2下载地址: https://github.com/olikraus/u8g2 准备一份KEIL工程,我这里使用了一份我自己写的时间片轮询程序(唯一的要求,带屏幕的初始化就行)
开始移植文件
U8G2源码中,这个csrc是c语言版的源码,直接把他复制到keil的工程里。 我将csrc文件复制到keil工程中的,HARDWARE文件夹内,改名为OLED_U8G2。(名字和位置,可以根据实际情况更改)
修改keil配置
添加一个分组,把U8G2的文件全部添加进去 但是,里面有好多u8g2_d_xxx.c格式的文件,里面有三个文件的必要的。其中一个需要根据你OLED屏幕的驱动芯片和像素(如这里选择的文件,就是ssd1306,这个驱动芯片。128*64的像素) 还有这两个文件也是必要的,除了这三个文件以后的u8g2_d_xxx的文件全部删除。 这四个文件也删除了 然后,添加一下环境配置中的c/c++,让keil可以找到这些文件。
修改U8G2源码
重点就是修改,u8g2_d_memory.c 与 u8g2_d_setup.c 这两个文件
u8g2_d_setup.c修改
快捷键 ctrl+A 全选以后,直接把全部文件注释了 然后,取消注释头文件,并且找到你屏幕驱动对应的那个函数取消注释 这里找到了,跟我ssd1306 128*64对应的函数,取消注释。最后一个英文字母f代表的是内存。就是一次传输多少字节的数据。f为1024个字节,2为256个字节,1为128个字节。这个主要是根据单片机的性能来选择的。比如是stmf103c8t6这种小容量的芯片,就选择后缀为1的函数。
u8g2_d_memory.c修改
同样的操作,ctrl+A把全部文件注释了以后,取消对头文件的注释。 然后,在u8g2_d_memory.c文件中,查找下图红框框里的函数,把对应的函数,取消注释。 取消注释
注意
- 上面的所有操作,需要根据屏幕的驱动芯片
- f 代表的是一次刷新屏幕的字节数(根据芯片选择 f 、 2 、1)
U8G2接口程序
u8g2_Setup_ssd1306_128x64_noname_f就是刚刚选择的屏幕驱动函数。 下面两句就是开打屏幕的显示。
u8g2_Setup_ssd1306_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_4wire_sw_spi, u8x8_stm32_gpio_and_delay);
u8g2_InitDisplay(&u8g2);
u8g2_SetPowerSave(&u8g2,0);
重点是u8x8_stm32_gpio_and_delay这个函数,这个回调函数,需要由我们使用者来写。他主要就是给U8G2提供的延时函数和通信接口。 这里使用的是4线的spi通信
uint8_t u8x8_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)
{
switch(msg)
{
case U8X8_MSG_DELAY_100NANO:
__NOP();
break;
case U8X8_MSG_DELAY_10MICRO:
for (uint16_t n = 0; n < 320; n++)
{
__NOP();
}
break;
case U8X8_MSG_DELAY_MILLI:
delay_ms(1);
break;
case U8X8_MSG_DELAY_I2C:
delay_us(5);
break;
case U8X8_MSG_GPIO_SPI_DATA:
if(arg_int == 1)
GPIO_SetBits(GPIOA,GPIO_Pin_1);
else if(arg_int == 0)
GPIO_ResetBits(GPIOA,GPIO_Pin_1);
break;
case U8X8_MSG_GPIO_SPI_CLOCK:
if(arg_int == 1)
GPIO_SetBits(GPIOA,GPIO_Pin_0);
else if(arg_int == 0)
GPIO_ResetBits(GPIOA,GPIO_Pin_0);
break;
case U8X8_MSG_GPIO_CS:
if(arg_int == 1)
GPIO_SetBits(GPIOA,GPIO_Pin_4);
else if(arg_int == 0)
GPIO_ResetBits(GPIOA,GPIO_Pin_4);
break;
case U8X8_MSG_GPIO_DC:
if(arg_int == 1)
GPIO_SetBits(GPIOA,GPIO_Pin_3);
else if(arg_int == 0)
GPIO_ResetBits(GPIOA,GPIO_Pin_3);
break;
case U8X8_MSG_GPIO_RESET:
if(arg_int == 1)
GPIO_SetBits(GPIOA,GPIO_Pin_2);
else if(arg_int == 0)
GPIO_ResetBits(GPIOA,GPIO_Pin_2);
break;
case U8X8_MSG_GPIO_MENU_SELECT:
u8x8_SetGPIOResult(u8x8, 0);
break;
case U8X8_MSG_GPIO_MENU_NEXT:
u8x8_SetGPIOResult(u8x8, 0);
break;
case U8X8_MSG_GPIO_MENU_PREV:
u8x8_SetGPIOResult(u8x8, 0);
break;
case U8X8_MSG_GPIO_MENU_HOME:
u8x8_SetGPIOResult(u8x8, 0);
break;
default:
u8x8_SetGPIOResult(u8x8, 1);
break;
}
return 1;
}
最终效果
int t = 0;
u8g2_t u8g2;
delay_init(168);
LED_Init();
OLED_Init();
LED0=0;
u8g2_Setup_ssd1306_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_4wire_sw_spi, u8x8_stm32_gpio_and_delay);
u8g2_InitDisplay(&u8g2);
u8g2_SetPowerSave(&u8g2,0);
while(1)
{
LED0=~LED0;
delay_ms(100);
u8g2_ClearBuffer(&u8g2);
if(++t >= 32) t = 1;
u8g2_DrawCircle(&u8g2,64,32,t,U8G2_DRAW_ALL);
u8g2_DrawCircle(&u8g2,32,32,t,U8G2_DRAW_ALL);
u8g2_DrawCircle(&u8g2,96,32,t,U8G2_DRAW_ALL);
u8g2_SendBuffer(&u8g2);
}
|