0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

STM32移植U8g2图形库的方法 实现OLED图形显示

码农爱学习 来源:码农爱学习 作者:码农爱学习 2022-06-07 08:29 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

之前的文章,介绍过ESP8266Arduino IDE环境中使用U8g2库,实现OLED上的各种图形显示。

本篇,介绍一下U8g2库如何移植到STM32上,进行OLED的图形显示。

本次的实验硬件为:

STM32:型号为最常见的STM32F103C8T6

OLED:0.96寸OLED,IIC接口(如果是SPI接口,文中也有对应的修改介绍)

1 U8g2简介

U8g2 是一个用于嵌入式设备的单色图形库。U8g2支持单色OLED和LCD,并支持如SSD1306等多种类型的OLED驱动。

U8g2源码的开源库地址:https://github.com/olikraus/u8g2

pYYBAGKeIkWAbyNYAADKIaGINn0614.png

2 移植步骤

首先下载U8g2的源码,因为STM32主要是使用C语言编程,所以只需关注源码中的C源码部分,即csrc文件夹下的文件。

2.1 精简c源码

U8g2支持多种显示驱动的屏幕,因为源码中也包含了各个驱动对应的文件,为了减小整个工程的代码体积,在移植U8g2时,可以删除一些无用的文件。

2.1.1 去掉无用的驱动文件

这些驱动文件通常是u8x8_d_xxx.c,xxx包括驱动的型号和屏幕分辨率。ssd1306驱动芯片的OLED,使用u8x8_ssd1306_128x64_noname.c这个文件,其它的屏幕驱动和分辨率的文件可以删掉。

pYYBAGKeIk6Afkk8AAEKVfzfGYc168.png

2.1.2 精简u8g2_d_setup.c

由于我的OLED是IIC接口,只留一个本次要用到的u8g2_Setup_ssd1306_i2c_128x64_noname_f就好(如果是SPI接口,需要使用u8g2_Setup_ssd1306_128x64_noname_f这个函数),其它的可以删掉或注释掉。

#include "u8g2.h"

/* 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字节

f1024字节

2.1.3 精简u8g2_d_memory.c

由于用到的u8g2_Setup_ssd1306_i2c_128x64_noname_f函数中,只调用了u8g2_m_16_8_f这个函数,所以留下这个函数,其它的函数一定要删掉或注释掉,否则编译时很可能会提示内存不足!!!

#include "u8g2.h"

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
}

2.2 编写移植函数

精简源码之后,还需要编写如下的配置函数。

2.2.1 GPIO初始化

对OLED用到的IIC接口进行GPIO的初始化配置:

#define SCL_Pin GPIO_Pin_6
#define SDA_Pin GPIO_Pin_7
#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);
}

如果是SPI接口,则初始化对应的SPI接口即可。

2.2.2 u8x8_gpio_and_delay

这个函数也需要自己写,主要的修改包括:

赋予U8g2相应的延时函数,比如下面的delay_ms和delay_us

为U8g2提供IIC接口的高低电平调用:

U8X8_MSG_GPIO_I2C_CLOCK:IIC的SCL

U8X8_MSG_GPIO_I2C_DATA:IIC的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;
}

如果是SPI接口,可以参考如下写法:

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_SPI_DATA:
            lcd_sdin((uint8_t)arg_int); //SPI - MOSI
            break;
        case U8X8_MSG_GPIO_SPI_CLOCK: //SPI - CLK
            lcd_sclk(arg_int);
            break;
        case U8X8_MSG_GPIO_AND_DELAY_INIT:
            oled_init(); //OLED初始化
            Delay(1);
            break;
        case U8X8_MSG_DELAY_MILLI:
            Delay(arg_int); //延时
            break;
        case U8X8_MSG_GPIO_CS: //SPI - CS
            lcd_cs((uint8_t)arg_int);
        case U8X8_MSG_GPIO_DC:
            lcd_dc((uint8_t)arg_int); //SPI - MISO
            break;
        case U8X8_MSG_GPIO_RESET:
            break;
    }
    return 1;
}

可以看出,对于IIC与SPI接口,只有分别进行对应的配置即可。

2.2.3 u8g2Init

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

2.2.4 显示测试函数

使用U8g2提供的测试函数,用于查看显示效果

void draw(u8g2_t *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");
}

2.3 源码加入到MDK编译

在一个STM32的基础例程上进行修改。

2.3.1添加u8g2源码到工程

左侧工程目录添加U8g2源码,然后再添加U8g2的头文件搜寻目录,如下:

pYYBAGKeIlqAS42_AAG_sD-BLpY254.png

2.3.2 主函数

主函数中,首先是IIC的初始化和U8g2的初始化,然后就可以测试U8g2的图形显示功能了:

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

3 测试效果

pYYBAGKeImaAbklYAAES8Ep9QH8703.png

4 总结

本篇介绍了如何将U8g2图形库移植到STM32中,其中主要的修改包括:

精简源码中的u8g2_d_setup.c和u8g2_d_memory.c

OLED所用IIC接口的GPIO初始化

编写u8x8_gpio_and_delay和u8g2Init

其中,u8g2_d_memory.c文件一定要去掉无用的函数,否则编译时会提示内存不足;对于SPI接口的OLED,参考IIC接口进行类似的修改即可。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 单片机
    +关注

    关注

    6074

    文章

    45334

    浏览量

    663294
  • 嵌入式
    +关注

    关注

    5186

    文章

    20143

    浏览量

    328643
  • OLED
    +关注

    关注

    121

    文章

    6331

    浏览量

    232466
  • STM32
    +关注

    关注

    2305

    文章

    11120

    浏览量

    371046
  • u8g2
    +关注

    关注

    0

    文章

    18

    浏览量

    2266
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    STM32标准在Keil5移植rtthread nano后无法显示oled内容是怎么回事?

    STM32F103VET6使用标准,在Keil5上移植rtthread nano后OLED_Update()函数在Sys_Init()中放在board.c中可以执行并且
    发表于 09-22 08:28

    RA-Eco-RA6M4部分功能测评3

    RA-Eco-RA6M4开发板实战:基于I2C驱动OLEDu8g2图形移植
    发表于 09-05 20:47

    【RA-Eco-RA6M4开发板评测】2、I2C外设驱动OLED屏幕和移植u8g2

    ssd1306(兼容ssd1315)设备的初始化函数,这里使用该函数是可以点亮屏幕的,使用其他的则有问题。 OLED的屏幕显示效果如下。 总结 移植现有的u8g2
    发表于 07-23 13:51

    RT-Thread Nano硬核移植指南:手把手实现VGLite图形驱动适配 | 技术集结

    VGLite是NXP提供的轻量级2D图形API,本文将手把手带你实现VGLite图形驱动适配RT-Thread。文章分为上、下两篇,将手把手教您移植
    的头像 发表于 07-17 14:40 3039次阅读
    RT-Thread Nano硬核<b class='flag-5'>移植</b>指南:手把手<b class='flag-5'>实现</b>VGLite<b class='flag-5'>图形</b>驱动适配 | 技术集结

    零知开源——STM32F4结合BMP581气压传感器实现ST7789中文显示教程

    传感器数据采集。通过U8g2实现高质量中文渲染,混合Adafruit_GFX进行高效数据显示,实时展示温度、压力和高度数据。教程详细介绍了硬件连接方案(I
    的头像 发表于 07-09 09:21 1236次阅读
    零知开源——<b class='flag-5'>STM32</b>F4结合BMP581气压传感器<b class='flag-5'>实现</b>ST7789中文<b class='flag-5'>显示</b>教程

    零知开源——STM32F4结合BMP581气压传感器实现ST7789中文显示教程

    ;gt;使用U8g2实现高质量中文渲染 >混合使用Adafruit_GFX和U8g2实现高效显示
    发表于 07-08 18:55

    改善光刻图形线宽变化的方法及白光干涉仪在光刻图形的测量

    引言 在半导体制造与微纳加工领域,光刻图形线宽变化直接影响器件性能与集成度。精确控制光刻图形线宽是保障工艺精度的关键。本文将介绍改善光刻图形线宽变化的方法,并探讨白光干涉仪在光刻
    的头像 发表于 06-30 15:24 592次阅读
    改善光刻<b class='flag-5'>图形</b>线宽变化的<b class='flag-5'>方法</b>及白光干涉仪在光刻<b class='flag-5'>图形</b>的测量

    Micro OLED 阳极像素定义层制备方法及白光干涉仪在光刻图形的测量

      引言   Micro OLED 作为新型显示技术,在微型显示领域极具潜力。其中,阳极像素定义层的制备直接影响器件性能与显示效果,而光刻图形
    的头像 发表于 05-23 09:39 549次阅读
    Micro <b class='flag-5'>OLED</b> 阳极像素定义层制备<b class='flag-5'>方法</b>及白光干涉仪在光刻<b class='flag-5'>图形</b>的测量

    关于stm32u8g2菜单之间切换(三)用u8g2写一个菜单无限左右循环

    u8g2_DrawXBMP();  函数画图需要的是我们图片的地址而不是整个图片数组。 下面是源码:   int ui_run(int *a,int *a_tag,uint8_
    的头像 发表于 03-11 09:10 1097次阅读

    关于stm32u8g2菜单之间切换(三)写u8g2的一些必要函数

    要想stm应用u8g2绘制界面需要对u8g2原函数 u8g2_Setup_ssd1306_i2c_128x128_f (u8g2_t *u8g2
    的头像 发表于 03-07 12:53 1044次阅读
    关于<b class='flag-5'>stm32</b>,<b class='flag-5'>u8g2</b>菜单之间切换(三)写<b class='flag-5'>u8g2</b>的一些必要函数

    关于stm32u8g2菜单之间切换(1)

    移植U8g2
    的头像 发表于 03-05 16:43 933次阅读

    关于stm32u8g2菜单之间切换(二)u8g2移植

    移植是基于stm32cubeide,oled屏是1306驱动128x64的。接口用iic软件模拟,haliic硬件貌似有bug。 1,先在网上下载
    的头像 发表于 03-04 09:52 1514次阅读
    关于<b class='flag-5'>stm32</b>,<b class='flag-5'>u8g2</b>菜单之间切换(二)<b class='flag-5'>u8g2</b>的<b class='flag-5'>移植</b>

    深入了解U8g2与LVGL图形

    在单片机开发领域,图形显示功能变得越来越重要。无论是工业控制界面、智能家居设备,还是手持仪器仪表,都需要一个高效且易用的图形实现丰富的可
    的头像 发表于 02-13 11:01 3455次阅读

    Stellaris图形用户指南

    电子发烧友网站提供《Stellaris图形用户指南.pdf》资料免费下载
    发表于 12-23 16:19 0次下载
    Stellaris<b class='flag-5'>图形</b><b class='flag-5'>库</b>用户指南

    【敏矽微ME32G070开发板免费体验】开箱+点灯+点亮OLED

    ME32G070 支持硬件 I2C,这里偷个懒,不想使用繁琐的跳线,直接在开发板上随意插入 OLED 显示屏的引脚,如下: 直接插上 OLED
    发表于 12-19 00:25