U8g2库平台支持性好,基本上支持绝大部分Arduino开发板,特别也博主比较喜欢的ESP8266;
U8g2库显示控制器支持性好,基本上市面上的OLED都完美支持;
U8g2库 API众多,特别支持了中文,支持了不同字体,这是一个对于开发者俩说不小的福利。
u8g2是开源的,可直接下载代码移植:GitHub - olikraus/u8g2: U8glib library for monochrome displays, version 2。
只需下载方框内文件 .
u8g2里面支持多种驱动芯片,以u8x8_d_xxx.c
命名的就是驱动文件,本文使用的是0.96吋oled,芯片是ssd1306,将不必要的外设驱动(u8x8_d_xxx.c
)删除,只保留需要使用的驱动(u8g2_d_memory.c
和u8g2_d_setup.c
要保留),下面以ssd1306
为例,保留u8x8_d_ssd1306_128x64_noname.c
文件,
(3)将剩下的库添加到工程中
(4)修改"u8g2_d_setup.c"这个文件,里面有各种驱动芯片的初始化函数,删除其他函数,只留下与使用的驱动芯片相关的函数。
本文使用的ssd1306,但是与ssd1306相关的有多个函数,例如:
u8g2_Setup_ssd1306_128x64_noname_1、
u8g2_Setup_ssd1306_128x64_noname_2、
u8g2_Setup_ssd1306_128x64_noname_f,
这些都是spi接口的;
u8g2_Setup_ssd1306_i2c_128x64_noname_1、
u8g2_Setup_ssd1306_i2c_128x64_noname_2、
u8g2_Setup_ssd1306_i2c_128x64_noname_f,
这些都是i2c接口的;
后缀1、2、f代表缓冲区大小的不同:
1代表128字节,
2代表256字节,
f代表1024字节;
根据单片机空间的大小选择合适的接口,缓冲区小的,刷新lcd/oled的时候就比较耗时,反之。
本文使用u8g2_Setup_ssd1306_i2c_128x64_noname_f
这个接口:
所以删除或者屏蔽u8g2_d_setup.c
中不必要的内容,只保留u8g2_Setup_ssd1306_128x64_noname_f
函数
(5)修改“u8g2_d_memory.c”文件,这个文件里面其实就是“u8g2_d_setup.c”文件对应的缓冲区,同上面一样,屏蔽掉没用到的,留下用到的:
6)两个回调函数
void u8g2_Setup_ssd1306_i2c_128x64_noname_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
参数byte_cb和gpio_and_delay_cb是需要编写的两个回调函数。
byte_cb:是通信相关的函数,比如i2c写数据,
gpio_and_delay_cb:是延时相关的函数。
关于回调函数的写法,官方也给出了参考例子:https://github.com/olikraus/u8g2/wiki/Porting-to-new-MCU-platform
通信函数:直接使用官方的这个u8x8_byte_sw_i2c
#define SCL_Pin GPIO_Pin_9
#define SDA_Pin GPIO_Pin_8
#define IIC_GPIO_Port GPIOB
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
GPIO_InitStructure.GPIO_Pin = SCL_Pin|SDA_Pin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(IIC_GPIO_Port, &GPIO_InitStructure);
}
延时函数:在这个通信函数分为硬件接口和软件模拟方式,软件模拟方式官方基本写好了,只需要简单的指定io口即可。函数里面,根据传递的参数,拉低或者拉高SCL以及SDA。
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
Delay_ms(1);
break;
case U8X8_MSG_DELAY_I2C: // arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz
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
if(arg_int == 1)
{
GPIO_SetBits(IIC_GPIO_Port, SCL_Pin);
}
else if(arg_int == 0)
{
GPIO_ResetBits(IIC_GPIO_Port, SCL_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
if(arg_int == 1)
{
GPIO_SetBits(IIC_GPIO_Port, SDA_Pin);
}
else if(arg_int == 0)
{
GPIO_ResetBits(IIC_GPIO_Port, SDA_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;
}
最后对OLED初始化
void oled_init(void)
{
u8g2_Setup_ssd1306_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_4wire_sw_spi, gpio_and_delay_cb); // 初始化u8g2
u8g2_InitDisplay(&u8g2); // 初始化显示器
u8g2_SetPowerSave(&u8g2, 0); // 唤醒显示器
u8g2_ClearBuffer(&u8g2); // 清空缓冲区的内容
}
main.c的代码
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "stdio.h"
#include "u8g2.h"
#include "u8g2_C.h"
void process_Test(u8g2_t *u8g2);
int main(void)
{
IIC_Init();
u8g2_t u8g2;
u8g2Init(&u8g2);
while(1)
{
Delay_ms(100);
u8g2_ClearBuffer(&u8g2);
process_Test(&u8g2);
u8g2_SendBuffer(&u8g2);
}
}
//进度条显示
void process_Test(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_DrawStr(u8g2,0,i,"1");//字符显示
u8g2_SetFont(u8g2,u8g2_font_ncenB18_tf); //设置字体
u8g2_DrawStr(u8g2,24,32,"STM32");//字符显示
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);
}
}