一、前言
想要你的OLED显示丝滑,试试移植u8g2吧。我分享了两种u8g2的移植过程,一个是标准库移植,一个是cubemx移植,此文章介绍cubemx配置u8g2,需要标准库配置的可在我的上篇文章有介绍。
二、cubemx配置文件
在cubemx下创建工程并配置相关属性。这里我使用的是stm32f103c8t6,使用7针SPI的OLED。
配置外部时钟。
OLED引脚接线:
SCK-----PA5
SDA-----PA7
RES-----PA4
DC-------PB0
CS-------PB1
配置GPIO
硬件SPI1的配置
时钟树配置
工程文件配置(栈空间给大点,不然后续容易卡死)
三、u8g2移植到,cubemx生成的文件
对于github得到的u8g2文件的裁剪,网上多有此介绍,这里我直接给出裁剪后的u8g2文件,大家解压即可,方便快速移植。
u8g2裁剪后的文件:
链接:https://pan.baidu.com/s/1s2Oqgs7NqtwfXcNySExyWA
提取码:8836
进入keil中:
将文件路径加入C/C++
加上 --no-multibyte-chars 这个标识
在OLED.c文件中写入这些初始化代码
#include "oled.h"
#include "stdlib.h"
#include "spi.h"
//#include "dma.h"
#include "u8g2.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_DMA(&hspi1, (uint8_t *)arg_ptr, arg_int);while(hspi1.TxXferCount);
//使用DMA可以将上面的注释解除,把下面不带DMA的给注释掉
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:
u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_enable_level);
u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->post_chip_enable_wait_ns, NULL);
break;
case U8X8_MSG_BYTE_END_TRANSFER:
u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->pre_chip_disable_wait_ns, NULL);
u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);
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设备,所以片选信号在初始化时已经设置为为常有效
HAL_GPIO_WritePin(OLED_CS_GPIO_Port, OLED_CS_Pin, arg_int);
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)
{
MD_OLED_RST_Set(); //显示器复位拉高
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); //开启显示
}
OLED.h中写入:
#ifndef __OLED_H
#define __OLED_H
#include "stdlib.h"
#include "main.h"
#include "gpio.h"
#include "u8g2.h"
//---------------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);
#endif
不要忘记了在main.h中在用户可写代码段处定义以下宏定义:
#define OLED_CS_Pin GPIO_PIN_1
#define OLED_CS_GPIO_Port GPIOB
#define OLED_SCK_Pin GPIO_PIN_5
#define OLED_SCK_GPIO_Port GPIOA
#define OLED_MOSI_Pin GPIO_PIN_7
#define OLED_MOSI_GPIO_Port GPIOA
#define OLED_RES_Pin GPIO_PIN_4
#define OLED_RES_GPIO_Port GPIOA
#define OLED_DC_Pin GPIO_PIN_0
#define OLED_DC_GPIO_Port GPIOB
至此移植和配置已经全部完成,接下来我们可以在main.c中测试以下
这里我删除了一些cubemx生成的不必要的注释,只是为了给大家演示,大家不用删,只需加入相关代码即可。
#include "main.h"
//#include "dma.h"
#include "spi.h"
#include "gpio.h"
#include "u8g2.h"
#include "OLED.h"
#include "menu.h"
void SystemClock_Config(void);
void draw(u8g2_t *u8g2)
{
u8g2_SetFont(u8g2, u8g2_font_6x12_tf); //设定字体
u8g2_DrawStr(u8g2, 80,36,"YYDS"); //显示字符
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");
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
//MX_DMA_Init();
MX_SPI1_Init();
u8g2_t u8g2; // 显示器初始化结构体
u8g2Init(&u8g2); //显示器调用初始化函数
while (1)
{
u8g2_FirstPage(&u8g2);
do
{
draw(&u8g2);
} while (u8g2_NextPage(&u8g2));
}
}
最后向大家提供能运行完整的工程文件:
链接:https://pan.baidu.com/s/1GCtnIc_pLxe0hnLN75ufXg
提取码:jklv
四、结语
自此stm32的硬件SPI移植u8g2Cubemx版也完美结束,谢谢大家。