STM32F1移植U8g2库

STM32移植U8g2库

MCU为STM32F1030C8T6最小系统,使用STM32CubeMX生成HAL库工程模板,采用硬件四线SPI连接0.96寸单色OLED(驱动芯片为SSD1306,128*64分辨率)

移植过程中参考了以下章,对博主的分享表示感谢。
参考文章

1.建立工程模板

建立工程模板主要对时钟,调试端口,IO端口,调试串口和SPI进行初始化,如下图1所示:

请添加图片描述

图1 F103C8T6初始化示意图

时钟,串口,调试接口和IO口初始化很简单,不再介绍。SPI初始化需要根据器件特性进行配置,根据查询到的OLED屏的资料,将SPI初始化为高位在前MSB,32分频后时钟频率为2.25MBit/s,由于只有一个SPI器件 ,所以CPOL选择Low,即为片选信号常有效,CPHA为2Edge,即第二个时钟上升沿进行采样。SSD1306 4线SPI通信时序如下图2所示:
请添加图片描述

图2 SSD1306 4线SPI通信时序

2.获取U8g2源码

源码地址下载源码到本地,解压后将csrc文件夹下复制到MDK工程下面,在MDK工程中新建U8g2文件夹并将csrc文件夹下面的所有文件添加到文件夹下面。
请添加图片描述

3.修改源码

U8g2的源文件中,u8╳8_d_xxxxx.c类型的文件都是兼容的显示器驱动文件,我们只需要使用自己使用的显示器驱动文件即可,不用全部添加,所以需要将没有用到的显示器支持文件从MDK工程U8g2文件夹下Remove掉,只保留我们需要的u8╳8_d_ssd1306_128x64nomane.c文件即可。

由于我们移除了很多显示器兼容文件,所以在编译时会报错,在u8g2_d_setup.c中注释掉我们 不需要使用的构造函数即可,同时注释掉u8g2_d_memory.c中不使用的全局变量,以减小程序占用空间。

在u8g2_d_setup.c中我们仅保留以下函数:

  • void u8g2_Setup_ssd1306_128x64_noname_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb)
  • void u8g2_Setup_ssd1306_128x64_noname_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb)
  • void u8g2_Setup_ssd1306_128x64_noname_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb)
  • void u8g2_Setup_sh1106_128x64_noname_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb)
  • void u8g2_Setup_sh1106_128x64_noname_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb)
  • void u8g2_Setup_sh1106_128x64_noname_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb)

前三个构造函数为0.96寸OLED的初始化构造函数,后三个为1.3寸OLED的初始化构造函数。可以只保留一种OLED的初始化函数,把另外三个也注释掉,我为了以后使用1.3寸OLED方便,全部保留。

u8g2_d_memory.c文件下只保留以下代码,其余代码全部注释掉,保留代码如下:

/* u8g2_d_memory.c */
/* generated code, codebuild, u8g2 project */

#include "u8g2.h"

uint8_t *u8g2_m_16_8_1(uint8_t *page_cnt)
{
  #ifdef U8G2_USE_DYNAMIC_ALLOC
  *page_cnt = 1;
  return 0;
  #else
  static uint8_t buf[128];
  *page_cnt = 1;
  return buf;
  #endif
}
uint8_t *u8g2_m_16_8_2(uint8_t *page_cnt)
{
  #ifdef U8G2_USE_DYNAMIC_ALLOC
  *page_cnt = 2;
  return 0;
  #else
  static uint8_t buf[256];
  *page_cnt = 2;
  return buf;
  #endif
}
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
}

4.添加想要显示代码

我的工程中我建立了OLED显示文件md_oled_driver.c用以在主函数中调用,在md_oled_driver.c的接口函数中添加stm32对底层的操作。代码如下:

/*******************************************************************************
* 文件名称:md_oled_driver.h
*
* 摘	要:STM32F1的OLED中间驱动层头文件
*
* 当前版本:V1.0
* 作    者:yang_xi
* 日    期:2022/01/20
* 编译环境:keil_5

* 历史信息:
*******************************************************************************/
#ifndef __MD_OLED_DRIVER_H
#define __MD_OLED_DRIVER_H

#include "stdlib.h"	  
#include "main.h"
#include "gpio.h"
#include "u8g2.h"
#include "u8x8.h"
//OLED模式设置
//0:4线串行模式
//1:并行8080模式
#define OLED_MODE 0
#define SIZE 16
#define XLevelL		0x00
#define XLevelH		0x00
#define Max_Column	128
#define Max_Row		64
#define	Brightness	0xFF    //亮度
#define X_WIDTH 	128
#define Y_WIDTH 	64	    

//-----------------OLED端口定义----------------  					   
#define MD_OLED_RST_Clr() HAL_GPIO_WritePin(OLED_RES_GPIO_Port,OLED_RES_Pin,GPIO_PIN_RESET) //oled 复位端口操作
#define MD_OLED_RST_Set() HAL_GPIO_WritePin(OLED_RES_GPIO_Port,OLED_RES_Pin,GPIO_PIN_SET)

//OLED控制用函数
uint8_t u8x8_byte_4wire_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int,void *arg_ptr);
uint8_t u8x8_stm32_gpio_and_delay(U8X8_UNUSED u8x8_t *u8x8,U8X8_UNUSED uint8_t msg, U8X8_UNUSED uint8_t arg_int,U8X8_UNUSED void *arg_ptr) ;
void u8g2Init(u8g2_t *u8g2);
void draw(u8g2_t *u8g2);

#endif  
/********************************* end_of_file **********************************/
/*******************************************************************************
* 文件名称:md_oled_driver.c
*
* 摘	要:STM32F1的OLED中间驱动层c文件
*
* 当前版本:V1.0
* 作    者:yang_xi
* 日    期:2022/01/20
* 编译环境:keil_5

* 历史信息:
*******************************************************************************/
//----------------------------------------------------------------
//GND    电源地
//VCC  接5V或3.3v电源
//D0   接PA5(SCL)
//D1   接PA7(SDA)
//RES  接PB0
//DC   接PB1
//CS   接PA4              
//----------------------------------------------------------------

//******************************************************************************/

#include "md_oled_driver.h"
#include "stdlib.h"
#include "md_oled_font.h"
#include "spi.h"
#include "u8g2.h"
#include "u8x8.h"
uint8_t u8x8_byte_4wire_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int,void *arg_ptr)
{
    switch (msg)
    {
        case U8X8_MSG_BYTE_SEND: /*通过SPI发送arg_int个字节数据*/
			HAL_SPI_Transmit(&hspi1,(uint8_t *)arg_ptr,arg_int,200);
            break;
        case U8X8_MSG_BYTE_INIT: /*初始化函数*/
            break;
        case U8X8_MSG_BYTE_SET_DC: /*设置DC引脚,表明发送的是数据还是命令*/
			HAL_GPIO_WritePin(OLED_DC_GPIO_Port,OLED_DC_Pin,arg_int);
            break;
        case U8X8_MSG_BYTE_START_TRANSFER: 
            break;
        case U8X8_MSG_BYTE_END_TRANSFER: 
            break;
        default:
            return 0;
    }
    return 1;
}

uint8_t u8x8_stm32_gpio_and_delay(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_GPIO_AND_DELAY_INIT: /*delay和GPIO的初始化,在main中已经初始化完成了*/
            break;
        case U8X8_MSG_DELAY_MILLI: /*延时函数*/
            HAL_Delay(arg_int);     //调用谁stm32系统延时函数
            break;
        case U8X8_MSG_GPIO_CS: /*片选信号*/ //由于只有一个SPI设备,所以片选信号在初始化时已经设置为为常有效
            break;
        case U8X8_MSG_GPIO_DC: /*设置DC引脚,表明发送的是数据还是命令*/
            HAL_GPIO_WritePin(OLED_DC_GPIO_Port,OLED_DC_Pin,arg_int);
            break;
        case U8X8_MSG_GPIO_RESET:
            break;
    }
    return 1;
}

void u8g2Init(u8g2_t *u8g2)
{
	
/********************************************     
U8G2_R0     //不旋转,不镜像     
U8G2_R1     //旋转90度
U8G2_R2     //旋转180度   
U8G2_R3     //旋转270度
U8G2_MIRROR   //没有旋转,横向显示左右镜像
U8G2_MIRROR_VERTICAL    //没有旋转,竖向显示镜像
********************************************/
//    u8g2_Setup_sh1106_128x64_noname_2(u8g2, U8G2_R0, u8x8_byte_4wire_hw_spi, u8x8_stm32_gpio_and_delay);  // 初始化1.3寸OLED u8g2 结构体
	u8g2_Setup_ssd1306_128x64_noname_f(u8g2, U8G2_R0, u8x8_byte_4wire_hw_spi, u8x8_stm32_gpio_and_delay);  // 初始化0.96寸OLED u8g2 结构体
	u8g2_InitDisplay(u8g2);     //初始化显示
	u8g2_SetPowerSave(u8g2, 0); //开启显示
}

void draw(u8g2_t *u8g2)
{
    u8g2_DrawLine(u8g2, 0, 0, 127, 0);  //画直线
    u8g2_DrawLine(u8g2, 0, 0, 0, 63);
    u8g2_DrawLine(u8g2, 0, 63, 127, 63);    
    u8g2_DrawLine(u8g2, 127, 0, 127, 63);
    
    u8g2_DrawLine(u8g2, 0, 0, 127, 63); //画直线
    u8g2_DrawLine(u8g2, 0, 63, 127, 0);

    u8g2_DrawPixel(u8g2, 115, 32); //画点
    u8g2_DrawBox(u8g2,56,44,14,10);   //画实心矩形
    u8g2_DrawCircle(u8g2,62,13,10,U8G2_DRAW_ALL); //画空心矩形
    u8g2_DrawFrame(u8g2,5,24,18,16);  //画空心圆形

    u8g2_SetFont(u8g2, u8g2_font_6x12_tf);  //设定字体
    u8g2_DrawStr(u8g2, 80,36,"YYDS");    //显示字符
}
/********************************* end_of_file **********************************/


在主函数中定义初始化结构体

u8g2_t u8g2; // 显示器初始化结构体

并调用显示器初始化函数完成初始化

  MD_OLED_RST_Set(); //复位拉高
  u8g2Init(&u8g2);  //显示器调用初始化函数

在while(1)中进行显示

u8g2_FirstPage(&u8g2);
       do
       {
   			draw(&u8g2);
           
       } while (u8g2_NextPage(&u8g2));

显示效果如下:

请添加图片描述
整个工程文件可以从以下链接下载
工程文件

版权声明:本文为CSDN博主「yang__xi」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yangxishigehaoren/article/details/122701811

生成海报
点赞 0

yang__xi

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

STM32F4最小系统硬件设计

对于硬件工程师来讲,想要入门STM32相关的开发,我想除了深入阅读一下STM32的数据手册外,最实用且有效的方法就是自己实际做一个STM32的最小系统板了。本文将以一个小的STM32F427VG的电路最

STM32智能小车------PWM驱动直流电机

大家好哇!我是小光,嵌入式爱好者,一个想要成为系统架构师的普通大学生。进入正题,最近在做小车,目前已经可以跑起来了,然后就是加入各种各样的传感器,

STM32F103C8基于Modbus协议读取温湿度

一、任务 stm32f103通过串口二向485总线轮询发送问答帧访问所有modbus温湿度传感器模块,并且把得到的应答帧进行解析,得到对应的温湿度的值,再通过串口一发送至PC端。 二、代码 1.通