U8g2移植在STM32

U8g2简介

 

1.1 U8g2是什么

    U8g2是嵌入式设备的单色图形库,一句话简单明了。主要应用于嵌入式设备,包括我们常见的单片机;

1.2 U8g2支持的显示控制器

    U8g2支持单色OLED和LCD,包括以下控制器:SSD1305,SSD1306,SSD1309,SSD1322,SSD1325,SSD1327,SSD1329,SSD1606,SSD1607,SH1106,SH1107,SH1108,SH1122,T6963,RA8835,LC7981,PCD8544,PCF8812,HX1230 ,UC1601,UC1604,UC1608,UC1610,UC1611,UC1701,ST7565,ST7567,ST7588,ST75256,NT7534,IST3020,ST7920,LD7032,KS0108,SED1520,SBN1661,IL3820,MAX7219(有关完整列表,请参见 此处)。
    可以说,基本上主流的显示控制器都支持,比如我们常见的SSD1306 12864,读者在使用该库之前请查阅自己的OLED显示控制器是否处于支持列表中。

1.3 U8g2的优势


    为什么要运用U8g2库?也就是说U8g2库能带给我们什么样的开发便利。在博主看来,主要考虑几个方面:

U8g2库平台支持性好,基本上支持绝大部分Arduino开发板,特别也博主比较喜欢的ESP8266;
U8g2库显示控制器支持性好,基本上市面上的OLED都完美支持;
U8g2库 API众多,特别支持了中文,支持了不同字体,这是一个对于开发者俩说不小的福利。

u8g2是开源的,可直接下载代码移植:GitHub - olikraus/u8g2: U8glib library for monochrome displays, version 2。

2.1下载u8g2库函数

U8g2移植在STM32_第1张图片

只需下载方框内文件 .

u8g2里面支持多种驱动芯片,以u8x8_d_xxx.c命名的就是驱动文件,本文使用的是0.96吋oled,芯片是ssd1306,将不必要的外设驱动(u8x8_d_xxx.c)删除,只保留需要使用的驱动(u8g2_d_memory.cu8g2_d_setup.c要保留),下面以ssd1306为例,保留u8x8_d_ssd1306_128x64_noname.c文件,

U8g2移植在STM32_第2张图片

(3)将剩下的库添加到工程中

U8g2移植在STM32_第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函数

U8g2移植在STM32_第4张图片

(5)修改“u8g2_d_memory.c”文件,这个文件里面其实就是“u8g2_d_setup.c”文件对应的缓冲区,同上面一样,屏蔽掉没用到的,留下用到的:

U8g2移植在STM32_第5张图片

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);
    }
}

最后效果图U8g2移植在STM32_第6张图片

你可能感兴趣的:(笔记,stm32,单片机,嵌入式硬件)