U8g2库的STM32硬件SPI移植教程(HAL、OLED显示、四线SPI)
前言
- 本文教你把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(或其他)
- 引脚连接:
//----------------------------------------------------------------
本次用的是SPI1、DMA、全双工(当然半双工也没什么问题、CS、DC、RS是普通GPIO,自行切换)
GND -----------> 电源地
VCC -----------> 接5V或3.3v电源
D0 -----------> 接PA5(SCL)
D1 -----------> 接PA7(SDA)
RES -----------> 接PB0
DC -----------> 接PB1
CS -----------> 接PA4
//----------------------------------------------------------------
U8g2简介
出自此篇基于STM32移植U8g2图形库——OLED显示
U8g2是什么
U8g2是GitHub上一款十分优秀的开源图形库(GUI库),其本质是嵌入式设备的单色图形库。在 Github 上超过3.2K Star,2.6K Commit。其开发语言90%为C语言,且代码简洁干练便于移植与后期修改。
U8g2支持的显示控制器
U8g2支持单色OLED和LCD,包括以下控制器:
SSD1305 | SSD1306 | SSD1309 | SSD1312 | SSD1316 | SSD1320 |
SSD1322 | SSD1325 | SSD1327 | SSD1329 | SSD1606 | SSD1607 |
SH1106 | SH1107 | SH1108 | SH1122 | T6963 | RA8835 |
LC7981 | PCD8544 | PCF8812 | HX1230 | UC1601 | UC1604 |
UC1608 | UC1610 | UC1611 | UC1617 | UC1638 | UC1701 |
ST7511 | ST7528 | ST7565 | ST7567 | ST7571 | ST7586 |
ST7588 | ST75256 | ST75320 | NT7534 | ST7920 | IST3020 |
IST7920 | LD7032 | KS0108 | KS0713 | HD44102 | T7932 |
SED1520 | SBN1661 | IL3820 | MAX7219 |
可以说,基本上主流的显示控制器都支持,比如我们常见的SSD1306等,读者在使用该库之前请查阅自己的OLED显示控制器是否处于支持列表中。
U8g2的优势
- U8g2库平台支持性好,基本上支持绝大部分Arduino与STM32开发板,也包含物联网比较常用的esp8266;
- U8g2库显示控制器支持性好,基本上市面上的OLED都完美支持;
- U8g2库 API函数众多,特别支持了中文,支持了不同字体,这是一个对于开发者俩说不小的福利;
- U8g2 库移植简单,容易使用(这一点也是笔者比较钟意的);
其实,我们可以把U8g2当作一个工具箱,需要使用的时候就去打开工具箱,使用里面的已经写好的API函数去实现我们需要达到的显示效果。(当然,前提是需要熟悉U8g2的使用,这一点网上有很多用法博客写得都很详细,感兴趣的读者朋友可以去看看这篇:深入学习Arduino u8g2 OLED库,一篇就够)
CubexMX的配置
RCC配置外部高速晶振(精度更高)——HSE:
SYS配置:Debug设置成Serial Wire(否则可能导致芯片自锁):
时钟树配置:
SPI1配置半双工(全双工):作为OLED的通讯方式:(注意这里的配置)
半双工:
全双工:
DMA配置:
工程配置:
这里我们不用的库不加,减小代码体积
然后生成
U8g2移植
准备U8g2库文件
准备U8g2库文件---------->U8g2下载地址: https://github.com/olikraus/u8g2 下载压缩包
Git用---------->git clone https://ghproxy.com/https://github.com/olikraus/u8g2.git
精简U8g2库文件
- U8g2支持多种显示驱动的屏幕,因为源码中也包含了各个驱动对应的文件(因此不需要自己去写屏幕底层驱动了),为了减小整个工程的代码体积和芯片资源占用,在移植U8g2时,可以删除一些无用的文件。
- 这里我们主要关注的是U8g2库文件中的csrc文件夹
去掉csrc文件夹中无用的驱动文件
这些驱动文件通常是u8x8_d_xxx.c,xxx包括驱动的型号和屏幕分辨率。ssd1306驱动芯片的OLED,使用u8x8_ssd1306_128x64_noname.c这个文件,其它的屏幕驱动和分辨率的文件可以删掉。
u8x8_d_xxx.c文件中留下u8x8_ssd1306_128x64_noname.c即可
精简u8g2_d_setup.c(注意不是u8x8_setup.c)
由于本文使用的OLED是SPI接口,只留一个本次要用到u8g2_Setup_ssd1306_128x64_noname_f就好(如果是IIC接口,需要使用u8g2_Setup_ssd1306_i2c_128x64_noname_f这个函数,多了i2c注意区分),其它的可以删掉或注释掉。
注意,与这个函数看起来十分相似的函数的有:
- 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用的,后面3个,是给I2C用的函数最后的数字或字母,代表显示时的buf大小:
- 1:128字节
- 2:256字节
- f:1024字节
精简u8g2_d_memory.c
u8g2_d_memory.c文件中,由于用到的u8g2_Setup_ssd1306_128x64_noname_f函数中,只调用了u8g2_m_16_8_f这个函数,所以只用留下这个函数,如果你用的其他函数,在u8g2_d_memory.c留下它相对应调用到的函数即可,其它的函数要删掉或注释,否则编译时很可能会导致内存不足。
将精简后的U8g2库添加至Keil
Keil工程目录添加精简后U8g2库文件中的csrc文件夹,然后再添加U8g2的头文件搜寻目录(U8g2_lib里都是csrc文件里面的文件,可以根据自己的需要删减),如下:
代码
Oled回调函数
oled_driver.c:
#include "oled_driver.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取消上一行注释即可*/
HAL_SPI_Transmit(&hspi1,(uint8_t *)arg_ptr,arg_int,200);
/*这是CubeMX生成的初始化*/
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)
{
/********************************************
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); //开启显示
}
/*官方logo的Demo*/
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");
}
/********************************* end_of_file **********************************/
GPIO定义的时候在CubeMX设置别名能更容易的切换IO口,CS拉高,如下
oled_driver.h:
#ifndef __MD_OLED_DRIVER_H
#define __MD_OLED_DRIVER_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);
void draw(u8g2_t *u8g2);
#endif
上述编写的移植函数代码属于HAL库下的代码,标准库的代码其实差不多,有个别地方需要注意修改。有一定MCU编程基础的朋友应该很简单就可以做到仿写。移植代码的本质:这些函数代码就是对应的U8g2图形库的接口函数,通过这些函数去启用U8g2图形库。
main函数
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_SPI1_Init();
/* Initialize interrupts */
MX_NVIC_Init();
/* USER CODE BEGIN 2 */
u8g2_t u8g2; // 显示器初始化结构体
MD_OLED_RST_Set(); //显示器复位拉高
u8g2Init(&u8g2); //显示器调用初始化函数
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
u8g2_FirstPage(&u8g2);
do
{
draw(&u8g2);
} while (u8g2_NextPage(&u8g2));
}
/* USER CODE END 3 */
}
最终效果
文章来源:https://www.toymoban.com/news/detail-487032.html
总结
U8g2图形库可以说目前小尺寸OLED首选的GUI,其可以呈现出的图形远不止上述中的图形,更多的功能还需要读者朋友们自己去好好发掘。优秀GUI的移植是一名合格嵌入式工程师必须掌握的技能之一,其可以达到大大缩短开发周期,优化UI界面等目的。LCD屏幕也存在类似的优秀开源GUI库,后续笔者会进行更新,感兴趣的读者朋友可以点波关注,感谢!!!
————————————————
原文链接:https://blog.csdn.net/black_sneak/article/details/126312657文章来源地址https://www.toymoban.com/news/detail-487032.html
- 开源代码:https://gitee.com/ljs_ice/STM32_u8g2
到了这里,关于U8g2库的STM32硬件SPI(DMA)移植教程(HAL、OLED显示、四线SPI、DMA)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!