前言
最近在B站上刷到了一位up主设计的oled丝滑界面WouoUI,一个优雅得比较像话的UI框架,128 * 64 经过询问,得知up用的是U8G2库,U8G2多用于arduino编译器上,但是我们学校常用的是stm32。
所以经过一段时间的研究,我将U8G2库移植到了stm32f103c8t6上进行使用。
一、U8G2是什么?
关于U8G2的使用,可以参考一下这个博主的文章:深入学习Arduino u8g2 OLED库,一篇就够,写的非常详细。但是他介绍的是arduino平台的使用,stm32用法也差不多。
二、移植步骤
1.软件i2c移植
移植参考了以下两篇文章:U8G2库移植到STM32平台上
U8g2图形库与STM32移植(I2C,软件与硬件)
(1).U8G2库的下载
U8G2库是一个开源的github项目,通过github可以直接下载 。U8G2下载地址
(2).新建一个工程STM32工程
新建一个工程,并且初始化一个IIC。
建立oled.h和oled.c文件
oled.c
#include "sys.h"
#include "oled.h"
//初始化IIC
void IIC_Init(void)
{
RCC->APB2ENR|=1<<3; //使能IO PORTBA时钟
GPIOB->CRL&=0X00FFFFFF; //PB6/7 推挽输出
GPIOB->CRL|=0X33000000;
}
oled.h
#ifndef __OLED_H
#define __OLED_H
#include "sys.h"
void IIC_Init(void);
#endif
(3).修改U8G2库
打开下载的u8g2库,我们用到的只有crsc这个文件夹。
打开csrc文件夹,可以看到里面有许多.c文件。有许多U8x8_d_*****类型的c文件,这是针对不同的驱动芯片所写的驱动程序,我们只需要选择我们需要的就行了,其他的在移植到自己的工程的时候可以都删除。我们此次使用的是ssd1306,因此在移植的时候,只保留U8x8_d_ssd1306_128x64_noname.c相关的驱动程序就可以了。
然后将csrc文件夹下面的文件都复制到stm32的工程中,建立好的工程如下图。
修改u8g2_d_setup.c中的函数,这里只保留u8g2_Setup_ssd1306_i2c_128x64_noname_f()这个函数,其他的可以注释或者删除。
/* ssd1306 f */
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)
{
uint8_t tile_buf_height;
uint8_t *buf;
u8g2_SetupDisplay(u8g2, u8x8_d_ssd1306_128x64_noname, u8x8_cad_ssd13xx_fast_i2c, byte_cb, gpio_and_delay_cb);
buf = u8g2_m_16_8_f(&tile_buf_height);
u8g2_SetupBuffer(u8g2, buf, tile_buf_height, u8g2_ll_hvline_vertical_top_lsb, rotation);
}
注意,与这个函数看起来十分相似的函数的有:
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字节
再修改u8g2_d_memory.c中的函数,由于用到的u8g2_Setup_ssd1306_i2c_128x64_noname_f()函数中,只调用了u8g2_m_16_8_f()这个函数,所以留下这个函数,其它的函数一定要删掉或注释掉,否则编译时很可能会提示内存不足。
uint8_t *u8g2_m_16_8_f(uint8_t *page_cnt)
{
#ifdef U8G2_USE_DYNAMIC_ALLOC
*page_cnt = 8;
return 0;
#else
static uint8_t buf[1024];
*page_cnt = 8;
return buf;
#endif
}
接下来修改字库u8g2_fonts.c,选择要使用的字库,否则会提示内存不足。这里我们保留
uint8_t u8g2_font_inb30_mn[807]
uint8_t u8g2_font_inb24_mf[8821]
uint8_t u8g2_font_4x6_tr[723]
这三个字库。
(4).编写配置函数
U8g2 已经包含了 SSD1306 的驱动,只需要添加一个函数u8x8_gpio_and_delay() 用于模拟时序即可。官方文件给出了一个函数的编写模板为:
uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) {
switch (msg) {
case U8X8_MSG_GPIO_AND_DELAY_INIT: // called once during init phase of u8g2/u8x8
break; // can be used to setup pins
case U8X8_MSG_DELAY_NANO: // delay arg_int * 1 nano second
break;
case U8X8_MSG_DELAY_100NANO: // delay arg_int * 100 nano seconds
break;
/* and many other cases */
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;
}
以下是一个写法案例:
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
arg_int ? (GPIOB->BSRR=1<<6) : (GPIOB->BRR=1<<6);
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
arg_int ? (GPIOB->BSRR=1<<7) : (GPIOB->BRR=1<<7);
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;
u8x8_SetGPIOResult(u8x8, 1); // default return value
break;
default:
return 0;
}
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_sw_i2c, u8x8_gpio_and_delay);// 初始化 u8g2 结构体
u8g2_InitDisplay(u8g2);// 根据所选的芯片进行初始化工作,初始化完成后,显示器处于关闭状态
u8g2_SetPowerSave(u8g2, 0);// 打开显示器
u8g2_ClearBuffer(u8g2);
}
至此,我们的U8G2已经移植好了,oled.h和oled.c应该是这样的:
oled.c
#include "sys.h"
#include "delay.h"
#include "u8g2.h"
#include "oled.h"
//初始化IIC
//SCL->PB6 ; SDA->PB7
void IIC_Init(void)
{
RCC->APB2ENR|=1<<3; //使能IO PORTB时钟
GPIOB->CRL&=0X00FFFFFF; //PB6/7 推挽输出
GPIOB->CRL|=0X33000000;
}
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
arg_int ? (GPIOB->BSRR=1<<6) : (GPIOB->BRR=1<<6);
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
arg_int ? (GPIOB->BSRR=1<<7) : (GPIOB->BRR=1<<7);
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;
default:
return 0;
}
return 1;
}
void u8g2Init(u8g2_t *u8g2)
{
u8g2_Setup_ssd1306_i2c_128x64_noname_f(u8g2, U8G2_R0, u8x8_byte_sw_i2c, u8x8_gpio_and_delay);
u8g2_InitDisplay(u8g2);
u8g2_SetPowerSave(u8g2, 0);
u8g2_ClearBuffer(u8g2);
}
oled.h
#ifndef __OLED_H
#define __OLED_H
#include "sys.h"
#include "u8g2.h"
void IIC_Init(void);
uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
void u8g2Init(u8g2_t *u8g2);
#endif
(5).测试代码
这是一个U8G2的测试代码,显示出来U8G2的logo:
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);
delay_ms(1000);
}
(6).主函数代码
main.c
#include "sys.h"
#include "delay.h"
#include "oled.h"
int main(void)
{
u8g2_t u8g2;
Stm32_Clock_Init(9);
delay_init(72);
IIC_Init();
u8g2Init(&u8g2);
draw(&u8g2);
while(1)
{
}
}
或者:文章来源:https://www.toymoban.com/news/detail-680555.html
#include "delay.h"
#include "sys.h"
#include "u8g2.h"
int main(void)
{
delay_init();
IIC_Init();
u8g2_t u8g2;
u8g2Init(&u8g2);
while(1)
{
u8g2_FirstPage(&u8g2);
do
{
draw(&u8g2);
} while (u8g2_NextPage(&u8g2));
}
}
2.实验现象
(1)proteus中查看实验现象
文章来源地址https://www.toymoban.com/news/detail-680555.html
到了这里,关于【U8G2库移植到STM32F103C8T6上】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!