打印
[STM32N6]

STM32移植U8g2图形库

[复制链接]
361|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
U8G2图形库介绍
U8g2 是一个用于嵌入式设备的简易图形库,可以在多种 OLED 和 LCD 屏幕上,支持包括 SSD1306 (新版型号为SSD1315)等多种类型的底层驱动,并可以很方便地移植到 Arduino 、树莓派、NodeMCU 和 ARM 上。
U8g2 库同时包含了 U8x8 绘图库,两者的区别为:
U8g2 包含各种简单及复杂图形的绘制,并支持各种形式的字体,但需要占用一定单片机的内存作为绘图缓存
U8x8 只包含简单的显示文本功能,且只支持简单、定宽的字体。它直接绘制图形,没有缓存功能
U8g2 库的 GitHub 地址为:https://github.com/olikraus/u8g2 ,可以从中获取到源码与文档帮助

移值
本次以将 U8g2 移植到 STM32 单片机与 SSD1306 通过 I2C 驱动的 128x64 OLED 为例,介绍移植的方法。不同单片机和驱动的移植可以参考这一过程,也可以参考 U8g2 的官方移植教程。
https://github.com/olikraus/u8g2/wiki/Porting-to-new-MCU-platform 首先下载或克隆 U8g2 的源码,这里主要是使用 C 语言编写,所以只需要用到 csrc 目录下的文件。
下载完成后,将 csrc 目录拷贝或移动到工程目录里,并重命名为合适的目录名例如 u8g2lib 。
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/angers11/article/details/138435346

使用特权

评论回复
沙发
远芳侵古道|  楼主 | 2025-1-31 01:43 | 只看该作者
精简c源码
U8g2支持多种显示驱动的屏幕,因为源码中也包含了各个驱动对应的文件,为了减小整个工程的代码体积,在移植U8g2时,可以删除一些无用的文件。
去掉无用的驱动文件



使用特权

评论回复
板凳
远芳侵古道|  楼主 | 2025-1-31 01:44 | 只看该作者
精简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字节
f:1024字节



精简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
}



使用特权

评论回复
地板
远芳侵古道|  楼主 | 2025-1-31 01:44 | 只看该作者
编写移植函数
精简源码之后,还需要编写如下的配置函数。

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);
}
1
2
3
4
5
6
7
8
9
10
11
12
如果是SPI接口,则初始化对应的SPI接口即可。

使用特权

评论回复
5
远芳侵古道|  楼主 | 2025-1-31 01:45 | 只看该作者
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 u8g2_gpio_and_delay_stm32(U8X8_UNUSED u8x8_t *u8x8, U8X8_UNUSED uint8_t msg, U8X8_UNUSED uint8_t arg_int, U8X8_UNUSED void *arg_ptr)
{
   switch(msg)
           {
                   case U8X8_MSG_DELAY_MILLI:
                           delay_ms(arg_int);
                           break;
                   case U8X8_MSG_DELAY_10MICRO:
                           delay_us(10);
                           break;
                   case U8X8_MSG_DELAY_100NANO:
                           __NOP();
                           break;
                   case U8X8_MSG_GPIO_I2C_CLOCK:
                           if (arg_int) I2C_OLED_SCL_H();
                           else I2C_OLED_SCL_L();
                           break;
                   case U8X8_MSG_GPIO_I2C_DATA:
                           if (arg_int) I2C_OLED_SDA_H();
                           else I2C_OLED_SDA_L();
                           break;
                   default:
                           return 0;
   }
   return 1;
}`

使用特权

评论回复
6
远芳侵古道|  楼主 | 2025-1-31 01:45 | 只看该作者
如果是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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
可以看出,对于IIC与SPI接口,只有分别进行对应的配置即可。

使用特权

评论回复
7
远芳侵古道|  楼主 | 2025-1-31 01:45 | 只看该作者
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)
{
        OLED12864_I2C_Init();
        u8g2_Setup_ssd1306_i2c_128x64_noname_f(u8g2, U8G2_R0, u8x8_byte_sw_i2c, u8g2_gpio_and_delay_stm32);
        u8g2_InitDisplay(u8g2);     //初始化
        u8g2_SetPowerSave(u8g2, 0);
        u8g2_ClearBuffer(u8g2);//清屏
}

使用特权

评论回复
8
远芳侵古道|  楼主 | 2025-1-31 01:45 | 只看该作者
显示测试函数
使用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");
}

使用特权

评论回复
9
远芳侵古道|  楼主 | 2025-1-31 01:46 | 只看该作者
源码加入到MDK编译

使用特权

评论回复
10
远芳侵古道|  楼主 | 2025-1-31 01:46 | 只看该作者
主函数
主函数中,首先是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));
    }
}

使用特权

评论回复
11
远芳侵古道|  楼主 | 2025-1-31 01:46 | 只看该作者

使用特权

评论回复
12
远芳侵古道|  楼主 | 2025-1-31 01:47 | 只看该作者
总结
本篇介绍了如何将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接口进行类似的修改即可。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

83

主题

845

帖子

0

粉丝