前言:本文主要内容为将优秀的图形库U8g2移植到STM32单片机上,用于OLED显示精美UI。其实,目前GitHub上有需要优秀的开源GUI库,但是大部分的GUI解决方案并不适合0.96 OLED(128×64 像素,基于 SSD1306)这种资源紧缺型的显示模组使用。所以,在这里给大家介绍和移植一下目前最为主流的0.96寸OLED的GUI图形库——U8g2。(本文为HAL库下的移植,标准库和其区别不大,文末有代码开源)
U8g2库开源网址:https://github.com/olikraus/u8g2
实验硬件:STM32F103C8T6;0.96寸OLED(128×64)
硬件实物图:
效果图:
引脚连接:
OLED模块:
VCC –> 3.3V
GND –> GND
SCL –> PB10
SDA –> PB11
一、U8g2简介
1.1 U8g2是什么
U8g2是GitHub上一款十分优秀的开源图形库(GUI库),其本质是嵌入式设备的单色图形库。在 Github 上超过3.2K Star,2.6K Commit。其开发语言90%为C语言,且代码简洁干练便于移植与后期修改。
1.2U8g2支持的显示控制器
U8g2支持单色OLED和LCD,包括以下控制器:SSD1305, SSD1306, SSD1309, SSD1312, SSD1316, SSD1320, SSD1322, SSD1325, SSD1327, SSD1329, SSD1606, SSD1607, SH1106, SH1107, SH1108, SH1122, T6963, RA8835, LC7981, PCD8544, 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。(可以看出适配的驱动IC是非常多的,考虑到后续U8g2图形库继续维护升级可能会支持更多控制器)
可以说,基本上主流的显示控制器都支持,比如我们常见的SSD1306等,读者在使用该库之前请查阅自己的OLED显示控制器是否处于支持列表中。
1.3U8g2的优势
U8g2库平台支持性好,基本上支持绝大部分Arduino与STM32开发板,也包含物联网比较常用的esp8266;
U8g2库显示控制器支持性好,基本上市面上的OLED都完美支持;
U8g2库 API函数众多,特别支持了中文,支持了不同字体,这是一个对于开发者俩说不小的福利;
- U8g2 库移植简单,容易使用(这一点也是笔者比较钟意的);
其实,我们可以把U8g2当作一个工具箱,需要使用的时候就去打开工具箱,使用里面的已经写好的API函数去实现我们需要达到的显示效果。(当然,前提是需要熟悉U8g2的使用,这一点网上有很多用法博客写得都很详细,感兴趣的读者朋友可以去看看)
二、CubexMX配置
在移植U8g2库之前,我们需要使用CubeMX软件配置一下MCU的部分功能。特别注意:U8g2图形库自带兼容的IC控制驱动程序,所以移植完成后不需要自己在写OLED或是LCD的驱动了。
1、RCC配置外部高速晶振(精度更高)——HSE;
2、SYS配置:Debug设置成Serial Wire(否则可能导致芯片自锁);
3、I2C2配置:作为OLED的通讯方式;
4、TIM1配置:U8g2图形库需要us级延迟推动(U8g2的心跳)
5、时钟树配置:
6、工程配置
三、U8g2移植
3.1 准备U8g2库文件
移植U8g2图像库需要准备好,U8g2的源码是在GitHub上开源的。
U8g2下载地址:https://github.com/olikraus/u8g2(如果打开不了读者朋友,可以评论区留言邮箱笔者有时间会发送过去)
进入源码地址后下载整个U8g2图形库的压缩包。
3.2 精简U8g2库文件
U8g2支持多种显示驱动的屏幕,因为源码中也包含了各个驱动对应的文件(所以不需要自己去写屏幕底层驱动了),为了减小整个工程的代码体积,在移植U8g2时,可以删除一些无用的文件。
这里我们主要关注的是U8g2库文件中的csrc文件。
3.2.1 去掉无用的驱动文件
这些驱动文件通常是u8x8_d_xxx.c,xxx包括驱动的型号和屏幕分辨率。ssd1306驱动芯片的OLED,使用u8x8_ssd1306_128x64_noname.c这个文件,其它的屏幕驱动和分辨率的文件可以删掉。
3.2.2 精简u8g2_d_setup.c
由于笔者的OLED是IIC接口,只留一个本次要用到u8g2_Setup_ssd1306_i2c_128x64_noname_f就好(如果是SPI接口,需要使用u8g2_Setup_ssd1306_128x64_noname_f这个函数),其它的可以删掉或注释掉。
注意,与这个函数看起来十分相似的函数的有:
- u8g2_Setup_ssd1306_128x64_noname_1
- u8g2_Setup_ssd1306_128x64_noname_2
- u8g2_Setup_ssd1306_128x64_noname_f
- u8g2_Setup_ssd1306_i2c_128x64_noname_1
- u8g2_Setup_ssd1306_i2c_128x64_noname_2
- u8g2_Setup_ssd1306_i2c_128x64_noname_f
其中,前面3个,是给SPI接口的OLED用的,函数最后的数字或字母,代表显示时的buf大小:
- 1:128字节
- 2:256字节
- f:1024字节
3.2.3 精简u8g2_d_memory.c
由于用到的u8g2_Setup_ssd1306_i2c_128x64_noname_f函数中,只调用了u8g2_m_16_8_f这个函数,所以留下这个函数,其它的函数一定要删掉或注释掉,否则编译时很可能会提示内存不足!!
3.3 将精简后的U8g2库添加至Keil
左侧Keil工程目录添加自己精简后U8g2库文件中的csrc文件,然后再添加U8g2的头文件搜寻目录(U8g2里面都是csrc文件里面的文件,读者朋友可以根据自己的需要删减),如下:
四、代码
4.1编写移植函数
stm32_u8g2.h:
#ifndef __STM32_U8G2_H#define __STM32_U8G2_H/* Includes ------------------------------------------------------------------*/#include "main.h"#include "u8g2.h"/* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* USER CODE BEGIN Private defines */ /* USER CODE END Private defines */#define u8 unsigned char// " />#include "stm32_u8g2.h"#include "tim.h"#include "i2c.h"uint8_t u8x8_byte_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr){/* u8g2/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER */static uint8_t buffer[128];static uint8_t buf_idx;uint8_t *data; switch (msg){case U8X8_MSG_BYTE_INIT:{/* add your custom code to init i2c subsystem */MX_I2C2_Init(); //I2C初始化}break; case U8X8_MSG_BYTE_START_TRANSFER:{buf_idx = 0;}break; case U8X8_MSG_BYTE_SEND:{data = (uint8_t *)arg_ptr; while (arg_int > 0){buffer[buf_idx++] = *data;data++;arg_int--;}}break; case U8X8_MSG_BYTE_END_TRANSFER:{if (HAL_I2C_Master_Transmit(&hi2c2, OLED_ADDRESS, buffer, buf_idx, 1000) != HAL_OK)return 0;}break; case U8X8_MSG_BYTE_SET_DC:break; default:return 0;} return 1;}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 secondsfor (uint16_t n = 0; n < 320; n++){__NOP();}break;case U8X8_MSG_DELAY_MILLI: // delay arg_int * 1 milli secondHAL_Delay(1);break;case U8X8_MSG_DELAY_I2C: // arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHzTims_delay_us(5);break;// arg_int=1: delay by 5us, arg_int = 4: delay by 1.25uscase U8X8_MSG_GPIO_I2C_CLOCK: // arg_int=0: Output low at I2C clock pinbreak;// arg_int=1: Input dir with pullup high for I2C clock pincase U8X8_MSG_GPIO_I2C_DATA:// arg_int=0: Output low at I2C data pinbreak;// arg_int=1: Input dir with pullup high for I2C data pincase 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 valuebreak;}return 1;}//U8g2的初始化,需要调用下面这个u8g2_Setup_ssd1306_128x64_noname_f函数,该函数的4个参数含义://u8g2:传入的U8g2结构体//U8G2_R0:默认使用U8G2_R0即可(用于配置屏幕是否要旋转)//u8x8_byte_sw_i2c:使用软件IIC驱动,该函数由U8g2源码提供//u8x8_gpio_and_delay:就是上面我们写的配置函数void u8g2Init(u8g2_t *u8g2){u8g2_Setup_ssd1306_i2c_128x64_noname_f(u8g2, U8G2_R0, u8x8_byte_hw_i2c, u8x8_gpio_and_delay); // 初始化u8g2 结构体u8g2_InitDisplay(u8g2); // u8g2_SetPowerSave(u8g2, 0); // u8g2_ClearBuffer(u8g2);}void draw(u8g2_t *u8g2){u8g2_ClearBuffer(u8g2); u8g2_SetFontMode(u8g2, 1); /*字体模式选择*/u8g2_SetFontDirection(u8g2, 0); /*字体方向选择*/u8g2_SetFont(u8g2, u8g2_font_inb24_mf); /*字库选择*/u8g2_DrawStr(u8g2, 0, 20, "U");u8g2_SetFontDirection(u8g2, 1);u8g2_SetFont(u8g2, u8g2_font_inb30_mn);u8g2_DrawStr(u8g2, 21,8,"8");u8g2_SetFontDirection(u8g2, 0);u8g2_SetFont(u8g2, u8g2_font_inb24_mf);u8g2_DrawStr(u8g2, 51,30,"g");u8g2_DrawStr(u8g2, 67,30,"\xb2");u8g2_DrawHLine(u8g2, 2, 35, 47);u8g2_DrawHLine(u8g2, 3, 36, 47);u8g2_DrawVLine(u8g2, 45, 32, 12);u8g2_DrawVLine(u8g2, 46, 33, 12);u8g2_SetFont(u8g2, u8g2_font_4x6_tr);u8g2_DrawStr(u8g2, 1,54,"github.com/olikraus/u8g2");u8g2_SendBuffer(u8g2);HAL_Delay(1000);}//画点填充void testDrawPixelToFillScreen(u8g2_t *u8g2){int t = 1000;u8g2_ClearBuffer(u8g2);for (int j = 0; j < 64; j++){for (int i = 0; i < 128; i++){u8g2_DrawPixel(u8g2,i, j);}}HAL_Delay(1000);}
上述编写的移植函数代码属于HAL库下的代码,标准库的代码其实差不多,有个别地方需要注意修改。有一定MCU编程基础的朋友应该很简单就可以做到仿写,如果有疑问可以留言。移植代码的本质:这些函数代码就是对应的U8g2图形库的接口函数,通过这些函数去启用U8g2图形库。
4.2 U8g2图形库测试函数
test.h:
#ifndef __TEST_H#define __TEST_H#include "main.h"#include "u8g2.h"void testDrawProcess(u8g2_t *u8g2);void testShowFont(u8g2_t *u8g2);void testDrawFrame(u8g2_t *u8g2);void testDrawRBox(u8g2_t *u8g2);void testDrawCircle(u8g2_t *u8g2);void testDrawFilledEllipse(u8g2_t *u8g2);void testDrawMulti(u8g2_t *u8g2);void testDrawXBM(u8g2_t *u8g2);void u8g2DrawTest(u8g2_t *u8g2);#endif
test.c:
#include "test.h"//---------------U8g2测试函数#define SEND_BUFFER_DISPLAY_MS(u8g2, ms)\do {\u8g2_SendBuffer(u8g2); \HAL_Delay(ms);\}while(0);//进度条显示void testDrawProcess(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_SetFont(u8g2,u8g2_font_ncenB12_tf);u8g2_DrawStr(u8g2,16,32,"STM32 U8g2");//字符显示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);}HAL_Delay(500);}//字体测试 数字英文可选用 u8g2_font_ncenB..(粗) 系列字体//u8g2_font_unifont_t_symbols/u8g2_font_unifont_h_symbols(细 圆润)void testShowFont(u8g2_t *u8g2){int t = 1000;char testStr[14] = "STM32F103C8T6";u8g2_ClearBuffer(u8g2);u8g2_SetFont(u8g2,u8g2_font_u8glib_4_tf);u8g2_DrawStr(u8g2,0,5,testStr);SEND_BUFFER_DISPLAY_MS(u8g2,t);u8g2_SetFont(u8g2,u8g2_font_ncenB08_tf);u8g2_DrawStr(u8g2,0,30,testStr);SEND_BUFFER_DISPLAY_MS(u8g2,t);u8g2_SetFont(u8g2,u8g2_font_ncenB10_tr);u8g2_DrawStr(u8g2,0,60,testStr);SEND_BUFFER_DISPLAY_MS(u8g2,t);}//画空心矩形void testDrawFrame(u8g2_t *u8g2){int t = 1000;int x = 16;int y = 32;int w = 50;int h = 20;u8g2_ClearBuffer(u8g2);u8g2_DrawStr(u8g2,0, 15, "DrawFrame");u8g2_DrawFrame(u8g2, x, y, w, h);SEND_BUFFER_DISPLAY_MS(u8g2,t);u8g2_DrawFrame(u8g2, x+w+5, y-10, w-20, h+20);SEND_BUFFER_DISPLAY_MS(u8g2,t);}//画实心圆角矩形void testDrawRBox(u8g2_t *u8g2){int t = 1000;int x = 16;int y = 32;int w = 50;int h = 20;int r = 3;u8g2_ClearBuffer(u8g2);u8g2_DrawStr(u8g2,0, 15, "DrawRBox");u8g2_DrawRBox(u8g2, x, y, w, h, r);SEND_BUFFER_DISPLAY_MS(u8g2,t);u8g2_DrawRBox(u8g2, x+w+5, y-10, w-20, h+20, r);SEND_BUFFER_DISPLAY_MS(u8g2,t);}//画空心圆void testDrawCircle(u8g2_t *u8g2){int t = 600;int stx = 0;//画图起始xint sty = 16; //画图起始yint with = 16;//一个图块的间隔int r = 15; //圆的半径u8g2_ClearBuffer(u8g2);u8g2_DrawStr(u8g2, 0, 15, "DrawCircle");u8g2_DrawCircle(u8g2, stx, sty - 1 + with, r, U8G2_DRAW_UPPER_RIGHT); //右上SEND_BUFFER_DISPLAY_MS(u8g2,t);u8g2_DrawCircle(u8g2, stx + with, sty, r, U8G2_DRAW_LOWER_RIGHT); //右下SEND_BUFFER_DISPLAY_MS(u8g2,t);u8g2_DrawCircle(u8g2, stx - 1 + with * 3, sty - 1 + with, r, U8G2_DRAW_UPPER_LEFT); //左上SEND_BUFFER_DISPLAY_MS(u8g2,t);u8g2_DrawCircle(u8g2, stx - 1 + with * 4, sty, r, U8G2_DRAW_LOWER_LEFT); //左下SEND_BUFFER_DISPLAY_MS(u8g2,t);u8g2_DrawCircle(u8g2, stx - 1 + with * 2, sty - 1 + with * 2, r, U8G2_DRAW_ALL);//整个圆SEND_BUFFER_DISPLAY_MS(u8g2,t);u8g2_DrawCircle(u8g2, 32*3, 32, 31, U8G2_DRAW_ALL);//右侧整个圆SEND_BUFFER_DISPLAY_MS(u8g2,t);}//画实心椭圆void testDrawFilledEllipse(u8g2_t *u8g2){int t = 800;int with = 16;//一个图块的间隔int rx = 27;//椭圆x方向的半径int ry = 22;//椭圆y方向的半径u8g2_ClearBuffer(u8g2);u8g2_DrawStr(u8g2,0, 14, "DrawFilledEllipse");SEND_BUFFER_DISPLAY_MS(u8g2,t);u8g2_DrawFilledEllipse(u8g2, 0, with, rx, ry, U8G2_DRAW_LOWER_RIGHT);//右下SEND_BUFFER_DISPLAY_MS(u8g2,t);u8g2_DrawFilledEllipse(u8g2, with * 4 - 1, with, rx, ry, U8G2_DRAW_LOWER_LEFT); //左下SEND_BUFFER_DISPLAY_MS(u8g2,t);u8g2_DrawFilledEllipse(u8g2, 0, with * 4 - 1, rx, ry, U8G2_DRAW_UPPER_RIGHT); //右上SEND_BUFFER_DISPLAY_MS(u8g2,t);u8g2_DrawFilledEllipse(u8g2, with * 4 - 1, with * 4 - 1, rx, ry, U8G2_DRAW_UPPER_LEFT); //左上SEND_BUFFER_DISPLAY_MS(u8g2,t);u8g2_DrawFilledEllipse(u8g2, with * 6, with * 2.5, rx, ry, U8G2_DRAW_ALL);//整个椭圆SEND_BUFFER_DISPLAY_MS(u8g2,t);}//环形测试void testDrawMulti(u8g2_t *u8g2){u8g2_ClearBuffer(u8g2);for (int j = 0; j < 64; j+=16){for (int i = 0; i 0; i-=2){u8g2_DrawBox(u8g2,i*2,i,128-i*4,64-2*i);u8g2_SendBuffer(u8g2);}//空心矩形逐渐变小u8g2_ClearBuffer(u8g2);for(int i=0; i0; i-=2){u8g2_DrawRBox(u8g2,i*2,i,128-i*4,64-2*i,10-i/3);u8g2_SendBuffer(u8g2);}//空心圆角矩形逐渐变小u8g2_ClearBuffer(u8g2);for(int i=0; i<32; i+=2){u8g2_DrawRFrame(u8g2,i*2,i,128-i*4,64-2*i,10-i/3);u8g2_SendBuffer(u8g2);}//实心圆逐渐变大u8g2_ClearBuffer(u8g2);for(int i=2; i0; i-=3){u8g2_DrawCircle(u8g2,64,32,i, U8G2_DRAW_ALL);u8g2_SendBuffer(u8g2);}//实心椭圆逐渐变大u8g2_ClearBuffer(u8g2);for(int i=2; i0; i-=3){u8g2_DrawEllipse(u8g2,64,32, i*2, i, U8G2_DRAW_ALL);u8g2_SendBuffer(u8g2);}}// width: 128, height: 48const unsigned char bilibili[] U8X8_PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xe0, 0x03, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xf0, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x01, 0xfc, 0x00, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x03, 0xfc, 0x00, 0x00, 0x3c, 0xc0, 0x0f, 0x00, 0x80, 0x03, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0x07, 0xfc, 0x00, 0x00, 0x3c, 0xc0, 0x0f, 0x00, 0xc0, 0x07, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xfc, 0x00, 0x00, 0x3c, 0x80, 0x0f, 0x00, 0xc0, 0x07, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x80, 0x0f, 0xf8, 0x00, 0x00, 0x3c, 0x80, 0x0f, 0x00, 0x80, 0x07, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x78, 0x80, 0x0f, 0x00, 0x80, 0x07, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x78, 0x80, 0x0f, 0x00, 0x80, 0x07, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x80, 0x79, 0x80, 0x0f, 0x00, 0x98, 0x07, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0xe0, 0x79, 0x9f, 0x0f, 0x00, 0xbe, 0xe7, 0x01, 0xc0, 0x07, 0x10, 0x40, 0x00, 0x1f, 0xf8, 0x00, 0xe0, 0x7b, 0x1f, 0x0f, 0x00, 0xbe, 0xe7, 0x01, 0xc0, 0x87, 0x1f, 0xe0, 0x0f, 0x1f, 0xf8, 0x00, 0xe0, 0x7b, 0x1e, 0x0f, 0x00, 0x3e, 0xe7, 0x01, 0xc0, 0xe7, 0x3f, 0xe0, 0x3f, 0x1f, 0xf0, 0x00, 0xe0, 0x7b, 0x1e, 0x0f, 0x00, 0x3e, 0xe7, 0x01, 0xc0, 0xe7, 0x3f, 0xe0, 0x3f, 0x1f, 0xf0, 0x00, 0x60, 0x71, 0x1e, 0x0f, 0x00, 0x34, 0xe7, 0x01, 0xc0, 0xe7, 0x07, 0x00, 0x3f, 0x1f, 0xf0, 0x00, 0x00, 0x70, 0x00, 0x1f, 0x00, 0x00, 0x07, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0xc0, 0x73, 0x1e, 0x1f, 0x00, 0x3c, 0xc7, 0x01, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0xc0, 0x73, 0x1e, 0x1f, 0x00, 0x7c, 0xe7, 0x01, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0xc0, 0x73, 0x1e, 0x1f, 0x00, 0x7c, 0xef, 0x01, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x01, 0xc0, 0x77, 0x1e, 0x1e, 0x00, 0x7c, 0xef, 0x01, 0xc0, 0x07, 0x00, 0x03, 0x00, 0x1f, 0xf0, 0xff, 0xc1, 0xf7, 0x1e, 0xfe, 0x1f, 0x78, 0xef, 0x01, 0xc0, 0x07, 0x70, 0x37, 0x00, 0x1f, 0xe0, 0xff, 0x87, 0xf7, 0x1e, 0xfe, 0xff, 0x78, 0xee, 0x01, 0xc0, 0x07, 0xe0, 0x3f, 0x00, 0x1f, 0xe0, 0xff, 0x9f, 0xf7, 0x1e, 0xfe, 0xff, 0x79, 0xce, 0x01, 0xc0, 0x07, 0xc0, 0x18, 0x00, 0x1f, 0xe0, 0xff, 0xbf, 0xe7, 0x1e, 0xfe, 0xff, 0x7b, 0xce, 0x01, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0xc7, 0xbf, 0xe7, 0x1e, 0xfe, 0xf8, 0x77, 0xce, 0x01, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0x0f, 0x3f, 0xe7, 0x1c, 0xfe, 0xf0, 0x77, 0xce, 0x03, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0xcf, 0x3f, 0xe7, 0x1c, 0xfe, 0xf8, 0xf3, 0xce, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xe0, 0xef, 0x1f, 0xe7, 0x1c, 0xfe, 0xfe, 0xf1, 0xce, 0x03, 0x80, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xe0, 0xff, 0x0f, 0xcf, 0x1c, 0xfc, 0xff, 0xf0, 0xc0, 0x03, 0x00, 0xff, 0xff, 0xff, 0xff, 0x07, 0xe0, 0xff, 0x03, 0x06, 0x1c, 0xfc, 0x7f, 0x60, 0xc0, 0x01, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x03, 0xe0, 0xff, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };// width: 128, height: 48const unsigned char three_support[] U8X8_PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x80, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x03, 0x00, 0x00, 0x80, 0x0f, 0xf0, 0x01, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0x00, 0xc0, 0xfd, 0xff, 0x00, 0x00, 0xc0, 0x7f, 0xfe, 0x01, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xe0, 0xfd, 0xff, 0x01, 0x00, 0xc0, 0x1f, 0xf8, 0x03, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xe0, 0xfd, 0xff, 0x01, 0x00, 0xc0, 0x0f, 0xf0, 0x03, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0xe0, 0xfd, 0xff, 0x01, 0x00, 0xc0, 0x67, 0xe6, 0x03, 0x00, 0x00, 0xfc, 0xff, 0x03, 0x00, 0x00, 0xe0, 0xfd, 0xff, 0x01, 0x00, 0xc0, 0x67, 0xe6, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x01, 0x00, 0x00, 0xe0, 0xfd, 0xff, 0x00, 0x00, 0xc0, 0x67, 0xe6, 0x03, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0x00, 0xe0, 0xfd, 0xff, 0x00, 0x00, 0xc0, 0x67, 0xee, 0x03, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0xe0, 0xfd, 0xff, 0x00, 0x00, 0x80, 0x7f, 0xfe, 0x01, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0xe0, 0xfd, 0xff, 0x00, 0x00, 0x80, 0x7f, 0xfe, 0x01, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00, 0xe0, 0xfd, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00, 0xe0, 0xfd, 0x7f, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x00, 0xf8, 0xf9, 0x01, 0x00, 0x00, 0xe0, 0xfd, 0x7f, 0x00, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0xf8, 0xf0, 0x00, 0x00, 0x00, 0xe0, 0xfd, 0x1f, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0x00, 0x30, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };void testDrawXBM(u8g2_t *u8g2){int t = 1000;u8g2_ClearBuffer(u8g2);u8g2_DrawStr(u8g2,0, 14, "DrawXBM");u8g2_DrawXBM(u8g2,0, 16, 128, 48, bilibili);SEND_BUFFER_DISPLAY_MS(u8g2,t);u8g2_ClearBuffer(u8g2);u8g2_DrawStr(u8g2,0, 14, "bilibili");u8g2_DrawXBM(u8g2,0, 16, 128, 48, three_support);SEND_BUFFER_DISPLAY_MS(u8g2,t);}void u8g2DrawTest(u8g2_t *u8g2){testDrawProcess(u8g2);testDrawMulti(u8g2);//testDrawFrame(u8g2);//testDrawRBox(u8g2);//testDrawCircle(u8g2);//testDrawFilledEllipse(u8g2);testShowFont(u8g2);testDrawXBM(u8g2);}
4.3 main函数:
int main(void){/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_I2C2_Init();MX_TIM1_Init();/* USER CODE BEGIN 2 */u8g2_t u8g2;u8g2Init(&u8g2);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */ u8g2_FirstPage(&u8g2); do { draw(&u8g2); u8g2DrawTest(&u8g2); } while (u8g2_NextPage(&u8g2));}/* USER CODE END 3 */}
五、实验效果
U8g2移植OLED显示(STM32)HAL库
六、总结
U8g2图形库可以说目前小尺寸OLED首选的GUI,其可以呈现出的图形远不止上述测试中的图形,更多的功能还需要读者朋友们自己去好好发掘。优秀GUI的移植是一名合格嵌入式工程师必须掌握的技能之一,其可以达到大大缩短开发周期,优化UI界面等目的。LCD屏幕也存在类似的优秀开源GUI库,后续笔者会进行更新,感兴趣的读者朋友可以点波关注,感谢!!!
代码开源
链接:https://pan.baidu.com/s/16SCXGKyoBlVZwUR4bse6ug 提取码:93ig