【U8G2库移植到STM32F103C8T6上】

这篇具有很好参考价值的文章主要介绍了【U8G2库移植到STM32F103C8T6上】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


前言

最近在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相关的驱动程序就可以了。
u8g2移植stm32,stm32,单片机,嵌入式硬件

然后将csrc文件夹下面的文件都复制到stm32的工程中,建立好的工程如下图。
u8g2移植stm32,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)
	{
		
  } 
}

或者:

#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中查看实验现象

u8g2移植stm32,stm32,单片机,嵌入式硬件文章来源地址https://www.toymoban.com/news/detail-680555.html

到了这里,关于【U8G2库移植到STM32F103C8T6上】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32移植u8g2玩转oled 用软件iic实现驱动oled

    移植u8g2到stm 这里是驱动iic 这里可以驱动u8g2 具体作用后续学习 下面就基本上可以驱动成功 最主要是修改后的u8g2的图

    2024年02月11日
    浏览(55)
  • 全网最简单的stm32f103c8t6移植ucosiii教程(附移植好的工程)

       最近在做一个机器人项目,需要使用到stm32f103c8t6核心板。考虑程序中的多任务特性,因此决定使用ucosiii用于多任务管理。ucosiii移植可能对于一些嵌入式老鸟来说,可能是信手拈来,但是对于很多新手特别是刚入门的小白来说还是有一定的难度的。尤其是全网的移植教程

    2024年02月16日
    浏览(40)
  • 正点原子stmf103zet6代码移植为stm32f103c8t6(库函数版)

    目录 1、打开正点原子的工程模板template, 点击魔术棒  2、 修改芯片型号 为stm32f103c8

    2024年02月01日
    浏览(56)
  • U8g2库的STM32硬件SPI(DMA)移植教程(HAL、OLED显示、四线SPI、DMA)

    本文教你把U8g2图形库移植到STM32上,基于STM32的硬件SPI、CubeMX U8g2库Github网址:https://github.com/olikraus/u8g2 U8g2库CSDN镜像网址:https://gitcode.net/mirrors/olikraus/u8g2?utm_source=csdn_github_accelerator 硬件准备:STM32C8T6(STM32系列芯片)、0.96寸OLED(128×64)、J-Link(或其他) 引脚连接: 出自此

    2024年02月09日
    浏览(49)
  • [低端局][cx32L003] 移植U8G2

    在低端芯片上使用U8G2 U8g2:单色显示库,版本2 U8g2是一个用于嵌入式设备的单色图形库。U8g2支持单色oled和lcd,其中包括以下控制器:Ssd1305、ssd1306、ssd1309、ssd1312、ssd1316、ssd1318、ssd1320、ssd1322、ssd1325、ssd1327、ssd1327、ssd1327、ssd1327、ssd1327、ssd1327、ssd1106、sh1107、sh1108、ssd1607、

    2024年02月13日
    浏览(43)
  • STM32 使用 U8g2 显示自定义图像

    首先移植 U8g2 图形库到 STM32,本文不赘述了。 本问针对 SSD1306 128*64 屏幕 采用 PCtoLCD2002完美版 字模软件对图像取模,具体操作如下: 新建图像: 图像长宽分别为 128 , 64 根据需要绘制图像,例如: 设置字模格式: 需要注意:取模方式 取模走向 C51格式 生成字模,将字模保

    2024年02月04日
    浏览(73)
  • stm32f103VET6和stm32f103c8t6有什么区别?

    我来终结下这个问题。 这两款单片机我都用过,其中无际单片机特训营其中一款wifi报警主机项目就是用了stm32f103c8t6。  stm32f103VET6和stm32f103c8t6都是STMicroelectronics公司推出基于ARM Cortex-M3内核的单片机。 它们在硬件规格和性能上存在一些差异,下面我详细讲解下它们的差异之处

    2024年02月15日
    浏览(65)
  • STM32F103C8T6板子介绍

    STM32简介 STM32是ST公司基于ARM Cortex-M内核开发的32位微控制器 STM32常应用在嵌入式领域,如智能车、无人机、机器人、无线通信、物联网、工业控制、娱乐电子产品等 STM32功能强大、性能优异、片上资源丰富、功耗低,是一款经典的嵌入式微控制器。  STM32F103C8T6 F1XX片上资源

    2024年02月11日
    浏览(56)
  • STM32F103C8T6系统板

    1.电源部分 2.复位 3.晶振 4. 电源电路——防反接 有关二极管 漫谈二极管防电源反接电路 本次采用上图右下角的NMOS防反接电路。 电源电路——电源芯片 AMS1117是AMS公司的 ,LM1117是NS(美国国家半导体)的,LM1117要贵很多,所以一般的用AMS1117就可以了。 (以下分析参考STM32F10

    2024年02月02日
    浏览(72)
  • STM32F103C8T6串口通信

      首先来看一下需要操作的函数,以及配置的步骤: 图1                                                  图2   Code: usart.c #include \\\"usart.h\\\" void ustart_Init(void ) { GPIO_InitTypeDef GPIO_Init_Ustar ; // 定义输出端口TX的结构体对象 USART_InitTypeDef USTART_Init; // 定义串口初始化结构体对象

    2024年02月16日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包