文章目录
一、创建第一个工程
1.1 创建工程
启动 STM32CubeMX 后, 点击如下图标开始选择 MCU:
如下图输入型号“STM32H563RIV”,双击找到的芯片,开始创建工程:
在弹出的窗口, 选择“without TurstZone activated”:
调高 CPU 频率:
配置工程, 如下操作:
指定代码生成方法, 如下:
在弹出的窗口, 点击“Yes”(以后再使能 ICACHE):
1.2 配置GPIO操作LED
根据核心板原理图“项目 1-全场景工业互联设备管理系统解决方案(PC 上位机+中控+ 多传感器)5_硬件资料01_开发板原理图DshanMCU-LiteH5_SCH_V1.pdf”, 可以看到 LED 引脚图如下:
可以双击打开工程里如下文件进行配置:
然后如下配置 PC12 为输出引脚:
-
在 main 函数的循环里,增加如下代码:
/* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* set PC13 output high */ HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_SET); HAL_Delay(500); /* set PC13 output low */ HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_RESET); HAL_Delay(500); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ }
最后编译、烧写、运行, 可以看到开发板的 LED 闪烁
二、使用LCD打印信息
2.1 接口信息
在上一个程序的基础上配置 SPI 。
所涉及引脚列表如下:
原理图引脚名 | 功能 | 引脚 | 描述 |
---|---|---|---|
PWM | 背光控制 | PB11 | 高电平打开背光,也可使用 PWM 波控制 亮度 |
LCD_RESET | 复位 | PB4 | 低电平复位 |
RS | LCD 数据/命令选择 | PD12 | 高电平表示传输数 据,低电平表示传 输命令 |
SPI_CS | SPI LCD 片选 | PD11 | |
SPI_MOSI | SPI MOSI | PC1 | |
SPI_MISO | SPI MISO | PC2 | |
SPI_SCK | SPI1 SCK | PB10 |
2.2 配置SPI
2.2.1 SPI2参数配置
2.2.2 SPI2 GPIO配置
SPI LCD 的 SPI 频率很高, 所涉及的 SPI 引脚速率都要配置为“very high”, 如下:
2.2.3 其他引脚配置
如下图所示:
2.2.4 修改堆的大小
要使用“Draw_ChineseFont”显示汉字,需要把堆调大(因为里面使用到malloc函数
分配比较大的内存),如下:
2.3 添加驱动
在MDK-ARM工程里添加group、文件,如下:
最后添加头文件目录,如下:
2.4 添加代码
-
在 main.c 的 main 函数中,添加如下代码:
/* USER CODE BEGIN 2 */ LCD_Init(1); /* 初始化LCD为横屏 */ Draw_Init(); /* 初始化绘制系统 */ Draw_Clear(0); /* 清屏 */ Draw_String(0, 0, "www.100ask.net\r\n10ask.taobao.com", 0x0000ff00, 0); /* 绘制字符串 */ Draw_ChineseFont(0, 40, "悦己之作方能悦人", 0xff0000, 0); /* 绘制汉字 */ extern const unsigned char gImage_100ask[36968]; Draw_Picture(0, 100, gImage_100ask); /* 绘制图片 */ Draw_Circle(60, 250, 50, 0xffffff); /* 画圆 */ Draw_Rectangle(180, 200, 280, 300, 0xffffff); /* 画矩形 */
编译、烧写、运行即可在 LCD 上看到信息。
2.5 函数使用说明
除了“LCD_Init”在“spi_lcd.h”里声明外,其他函数都在“draw.h”里声明。
2.5.1 初始化函数
有 2 个初始化函数:
- SPI LCD 的初始化函数“LCD_Init”,原型与用法如下:
/**********************************************************************
* 函数名称: LCD_Init
* 功能描述: 初始化LCD
* 输入参数: rotation - 旋转角度, 取值如下
* LCD_DISPLAY_ROTATION_0,
* LCD_DISPLAY_ROTATION_90,
* LCD_DISPLAY_ROTATION_180,
* LCD_DISPLAY_ROTATION_270,
* 输出参数: 无
* 返 回 值: 无
* 修改日期: 版本号 修改人 修改内容
* -----------------------------------------------
* 2024/02/01 V1.0 韦东山 创建
***********************************************************************/ void LCD_Init(lcd_display_rotation_t rotation);
- 绘制系统的初始化函数“Draw_Init”, 原型与用法如下:
/**********************************************************************
* 函数名称: Draw_Init
* 功能描述: Draw初始化,得到LCD的分辨率
* 输入参数: 无
* 输出参数: 无
* 返 回 值: 无
* 修改日期: 版本号 修改人 修改内容
* -----------------------------------------------
* 2024/02/01 V1.0 韦东山 创建
***********************************************************************/ void Draw_Init(void) ;
2.5.2 清屏函数
原型与用法如下:
/**********************************************************************
* 函数名称: Draw_Clear
* 功能描述: 把屏幕清屏为某种颜色
* 输入参数: dwColor, 颜色, 格式为0x00RRGGBB
* 输出参数: 无
* 返 回 值: 无
* 修改日期: 版本号 修改人 修改内容
* -----------------------------------------------
* 2024/02/01 V1.0 韦东山 创建
***********************************************************************/
void Draw_Clear(uint32_t dwColor);
2.5.3 ASCII 字符、字符串绘制函数
在 LCD 上打印 ASCII 字符、字符串的函数:
/**********************************************************************
* 函数名称: Draw_ASCII
* 功能描述: 绘制ASCII字符
* 输入参数: x,y - 左上角坐标
* c - 字符
* front_color - 前景颜色, 格式为0x00RRGGBB
* back_color - 背景颜色, 格式为0x00RRGGBB
* 输出参数: 无
* 返 回 值: 字符宽度(单位:像素)
* 修改日期: 版本号 修改人 修改内容
* -----------------------------------------------
* 2024/02/01 V1.0 韦东山 创建
***********************************************************************/
int Draw_ASCII(uint32_t x, uint32_t y, char c, uint32_t front_color, uint32_t back_color);
/**********************************************************************
* 函数名称: Draw_String
* 功能描述: 绘制ASCII字符串
* 输入参数: x,y - 左上角坐标
* str - 字符串
* front_color - 前景颜色, 格式为0x00RRGGBB
* back_color - 背景颜色, 格式为0x00RRGGBB
* 输出参数: 无
* 返 回 值: 字符串宽度(单位:像素)
* 修改日期: 版本号 修改人 修改内容
* -----------------------------------------------
* 2024/02/01 V1.0 韦东山 创建
***********************************************************************/
int Draw_String(uint32_t x, uint32_t y, char *str, uint32_t front_color, uint32_t back_color);
2.5.4 数值绘制函数
在 LCD 上打印十进制数、十六进制数的函数:
/**********************************************************************
* 函数名称: Draw_Number
* 功能描述: 以十进制显示数字
* 输入参数: (x,y) - 坐标
* num - 数值
* front_color - 前景颜色, 格式为0x00RRGGBB
* 输出参数: 无
* 返 回 值: 显示的字符的总宽度(单位:像素)
* 修改日期: 版本号 修改人 修改内容
* -----------------------------------------------
* 2024/02/01 V1.0 韦东山 创建
***********************************************************************/
int Draw_Number(uint32_t x, uint32_t y, uint32_t num, uint32_t front_color);
/**********************************************************************
* 函数名称: Draw_HexNumber
* 功能描述: 以16进制显示数字
* 输入参数: (x,y) - 坐标
* num - 数值
* front_color - 前景颜色, 格式为0x00RRGGBB
* 输出参数: 无
* 返 回 值: 显示的字符的总宽度(单位:像素)
* 修改日期: 版本号 修改人 修改内容
* -----------------------------------------------
* 2024/02/01 V1.0 韦东山 创建
***********************************************************************/
int Draw_HexNumber(uint32_t x, uint32_t y, uint32_t num, uint32_t front_color);
2.5.5 几何图形绘制函数
可以画线、画矩形、圆形:
/**********************************************************************
* 函数名称: Draw_Line
* 功能描述: 画线
* 输入参数: x1,y1 - 起点坐标
* x2,y2 - 终点坐标
* front_color - 前景颜色, 格式为0x00RRGGBB
* 输出参数: 无
* 返 回 值: 无
* 修改日期: 版本号 修改人 修改内容
* -----------------------------------------------
* 2024/02/01 V1.0 韦东山 创建
***********************************************************************/
void Draw_Line(uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2, uint32_t front_color);
/**********************************************************************
* 函数名称: Draw_Rectangle
* 功能描述: 画矩形
* 输入参数: (x1,y1),(x2,y2):矩形的对角坐标
* front_color - 前景颜色, 格式为0x00RRGGBB
* 输出参数: 无
* 返 回 值: 无
* 修改日期: 版本号 修改人 修改内容
* -----------------------------------------------
* 2024/02/01 V1.0 韦东山 创建
***********************************************************************/
void Draw_Rectangle(uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2, uint32_t front_color);
/**********************************************************************
* 函数名称: Draw_Circle
* 功能描述: 画圆
* 输入参数: (x0,y0) - 中心点
* r - 半径(单位:像素)
* front_color - 前景颜色, 格式为0x00RRGGBB
* 输出参数: 无
* 返 回 值: 无
* 修改日期: 版本号 修改人 修改内容
* -----------------------------------------------
* 2024/02/01 V1.0 韦东山 创建
***********************************************************************/
void Draw_Circle(uint32_t x0, uint32_t y0, uint32_t r, uint32_t front_color);
2.5.6 汉字绘制函数
函数原型如下:
/**********************************************************************
* 函数名称: Draw_Picture
* 功能描述: 绘制图片
* 输入参数: (x,y) - 坐标
* pic - 使用image2lcd生成的图片(水平扫描,包含图像头数据,16位真彩色,高位在前)
* 先使用"image2lcd.EXE"生成图片的点阵,存入picture.c
* 输出参数: 无
* 返 回 值: 无
* 修改日期: 版本号 修改人 修改内容
* -----------------------------------------------
* 2024/02/01 V1.0 韦东山 创建
***********************************************************************/
void Draw_Picture(uint32_t x, uint32_t y, const uint8_t *pic);
使用这个函数的前提是: 先使用"取字模软件.EXE"生成点阵,存入 font_chinese.c 的 CnChar32x29 数组中。这个工具在“4_工具软件9_文字取模软件”目录里,操作示意图如 下:
复制出来的点阵数据,存入 font_chinese.c 的 CnChar32x29 数组中, 如下添加索引:
以后, 就可以使用如下代码显示汉字了:
Draw_ChineseFont(0, 40, "悦己悦人之作", 0xff0000, 0); /* 绘制汉字 */
Draw_ChineseFont”函数里第 3 个参数里只能有汉字, 不能有其他字符,并且这些汉 字必须在“font_chinese.c”的索引里。
注意: 使用“Draw_ChineseFont”函数时, 它所在的文件编码格式必须是“UTF-8”, “font_chinese.c”文件的编码格式也必须是“UTF-8”。
2.5.7 图片绘制函数
函数原型如下:
/**********************************************************************
* 函数名称: Draw_Picture
* 功能描述: 绘制图片
* 输入参数: (x,y) - 坐标
* pic - 使用image2lcd生成的图片(水平扫描,包含图像头数据,16位真彩色,高位在前)
* 先使用"image2lcd.EXE"生成图片的点阵,存入picture.c
* 输出参数: 无
* 返 回 值: 无
* 修改日期: 版本号 修改人 修改内容
* -----------------------------------------------
* 2024/02/01 V1.0 韦东山 创建
***********************************************************************/
void Draw_Picture(uint32_t x, uint32_t y, const uint8_t *pic);
使用这个函数的前提是: 先使用"Image2Lcd"生成图片的点阵,存入 picture.c 中。这 个工具在“4_工具软件\10_图片点阵生成工具”目录里,操作示意图如下:
打开生成的文件,把它的代码全部复制进 picture.c 里, 示例如下:
以后, 就可以使用如下代码显示图片了:
extern const unsigned char gImage_100ask[36968];
Draw_Picture(0, 100, gImage_100ask);
三、使用 FreeRTOS
3.1 添加FreeRTOS
打开工程的 STM32CubeMX 配置,如下使能 FreeRTOS:
3.2 配置FreeRTOS
如下配置:
使用FreeRTOS 时,它的时钟基准来之SysTick 定时器;HAL 库的时钟基准建议更好为其他定时器,如下修改(TIMER6、TIMER7是功能最弱的基础定时器,可以选择它们):
3.3 添加用户代码
在“Core\Src\app_freertos.c”中,有一个默认任务,可以用来点灯,代码如下:
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN defaultTask */
/* Infinite loop */
for(;;)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_RESET);
vTaskDelay(500);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_SET);
vTaskDelay(500);
}
/* USER CODE END defaultTask */
}
然后再创建第2 个任务, 它在 LCD 上不断显示变化的字符。任务的入口函数如下:
static void SPILCDTaskFunction( void *pvParameters )
{
char buf[100];
int cnt = 0;
while (1)
{
sprintf(buf, "LCD Task Test : %d", cnt++);
Draw_String(0, 0, buf, 0x0000ff00, 0);
vTaskDelay(1000);
}
}
在“MX_FREERTOS_Init”函数中, 创建第 2 个任务:
/* USER CODE BEGIN RTOS_THREADS */
/* add threads, ... */
xTaskCreate(
SPILCDTaskFunction, // 函数指针, 任务函数
"spi_lcd_task", // 任务的名字
200, // 栈大小,单位为word,10表示40字节
NULL, // 调用任务函数时传入的参数
osPriorityNormal, // 优先级
NULL); // 任务句柄, 以后使用它来操作这个任务
编译、烧写、运行, 可以看到开发板的 LED 不断闪烁, LCD 上不断显示变化的数值。