赞
踩
在STM32F407上移植好了LVGL图形库,LCD屏幕型号是MSP3526,想换其他屏幕可以自己修改LCD的驱动程序,项目工程包含FreeRTOS版和裸机版。使用SPI+DMA驱动屏幕。
这款LCD屏分辨率为320x480,尺寸为3.5寸,LCD驱动芯片为ST7796,接口为SPI,电容触摸屏驱动芯片为FT6336U,接口为IIC。
MCU超频后全屏刷新时帧率为9FPS左右,局部刷新时帧率为30+FPS,对于SPI来说这个帧率应该算可以了吧。
电子/单片机技术交流群:820537762
效果演示视频:https://www.bilibili.com/video/BV1Ni421S7ta/
LVGL(轻量级和通用图形库)是一个免费和开源的图形库,它提供了创建嵌入式GUI所需的一切,具有易于使用的图形元素,美丽的视觉效果和低内存占用。
主要特性:
配置要求:
基本上,每个能够驱动显示器的现代控制器都适合运行 LVGL。 最低要求是:
16、32 或 64 位微控制器或处理器
建议使用 >16 MHz 时钟速度
闪存/ROM: > 64 kB 用于非常重要的组件 (> 建议使用 180 kB)
RAM:
C99 或更新的编译器
LVGL官网:https://lvgl.io/
LCD屏 | MCU/开发板 | 功能描述 |
---|---|---|
GND | GND | LCD屏电源地 |
VCC | 5V或3.3V | LCD屏电源正极 |
LCD_CS | PE6 | LCD屏SPI片选 |
LCD_RST | PC1 | LCD屏复位 |
LCD_RS | PC0 | LCD屏命令/数据选择 |
SDI(MOSI) | PB5 | LCD屏SPI数据线,主机输出从机输入 |
SCK | PB3 | LCD屏SPI时钟线 |
LED | 3.3V | 背光LED(可以自己接IO口,用软件控制背光) |
SDO(MISO) | PB4 | LCD屏SPI数据线,主机输入从机输出 |
CTP_SCL | PB8 | 电容触摸屏控制器I2C时钟线 |
CTP_RST | PB7 | 电容触摸屏控制器复位 |
CTP_SDA | PB9 | 电容触摸屏控制器I2C数据线 |
CTP_INT | PB6 | 电容触摸屏控制器中断信号 |
注意一下,我效果图里用的这款开发板的PB4引脚是没有在两边的排针里的,是在上面的JTAG接口里。
屏幕资料在线文档:https://url.zeruns.tech/68x3Y
屏幕资料打包下载地址1:https://www.123pan.com/s/2Y9Djv-rZevH.html
屏幕资料打包下载地址2:https://url.zeruns.tech/gzBO4
裸机版STM32F407+LVGL工程下载地址1:https://url.zeruns.tech/X242k
裸机版STM32F407+LVGL工程下载地址2:https://pan.baidu.com/s/1vAhHijYd_aWvRr3_c1_WtA?pwd=ry4g
FreeRTOS版STM32F407+LVGL工程下载地址1:https://www.123pan.com/s/2Y9Djv-CzevH.html
FreeRTOS版STM32F407+LVGL工程下载地址2:https://url.zeruns.tech/0iOHF
求点个Star
程序Gitee开源地址:https://gitee.com/zeruns/STM32F407_LVGL_Template_MSP3526
程序GitHub开源地址:https://github.com/zeruns/STM32F407_LVGL_Template_MSP3526
Gitee和GitHub开源里的最新版程序是用了FreeRTOS的,裸机版在发行版那里,版本号为0.1.3。FreeRTOS版的基本功能已经实现,还差优化。
使用STM32CubeMX生成的工程,用Keil5+VScode+EIDE来开发的。
我是参照正点原子的教程来移植的。
正点原子的 LVGL使用和移植 视频教程下载地址1:https://www.123pan.com/s/2Y9Djv-0ZevH.html
正点原子的 LVGL使用和移植 视频教程下载地址2:https://www.alipan.com/s/Pd6TDfT2rBL
将代码下载下来直接编译下载就能用。
如果需要关闭帧率和内存占用显示就将 lv_conf.h
文件里的下面这两个宏定义的1改成0。
/*1: Show CPU usage and FPS count*/
#define LV_USE_PERF_MONITOR 1
#if LV_USE_PERF_MONITOR
#define LV_USE_PERF_MONITOR_POS LV_ALIGN_BOTTOM_RIGHT
#endif
/*1: Show the used memory and the memory fragmentation
* Requires LV_MEM_CUSTOM = 0*/
#define LV_USE_MEM_MONITOR 1
#if LV_USE_MEM_MONITOR
#define LV_USE_MEM_MONITOR_POS LV_ALIGN_BOTTOM_LEFT
#endif
如果用的是FreeRTOS版的就在 freertos.c
文件里写代码,可以用STM32CubeMX软件新建线程和信号量这些,然后生成代码,代码都是按照规范写在指定位置的,重新生成不会影响自己写的代码。裸机版就直接在 main.c
文件里写代码就行。
如果需要关闭Demo程序就将下图中的代码注释掉就行。
主要就是在lv_port_disp.c
文件里disp_flush
函数中调用下面这段填充LCD的函数。LCD驱动是在屏幕官方给的例程基础上改的。
/** * @brief 填充LCD屏幕指定矩形区域 * 使用LVGL库的颜色值填充LCD指定区域。 * @param sx 起始X坐标 * @param sy 起始Y坐标 * @param ex 结束X坐标 * @param ey 结束Y坐标 * @param color_p 指向要填充的颜色的指针 */ void LCD_Fill_LVGL(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, lv_color_t *color_p) { uint32_t i, j; uint16_t width = ex - sx + 1; // 计算填充区域的宽度 uint16_t height = ey - sy + 1; // 计算填充区域的高度 uint32_t Pixel = width * height; // 计算填充区域像素个数 LCD_SetWindows(sx, sy, ex, ey); // 设置LCD的显示窗口为指定的区域 // for (i = 0; i < height; i++) // { // for (j = 0; j < width; j++){ // Lcd_WriteData_16Bit(color_p->full); // 写入数据 // } // } // 数据分割值, 用于分批发送数据 #define data_split 3000 uint8_t data[Pixel * 2]; // 创建一个数组用于存储颜色数据 for (i = 0; i < Pixel; i++) { // 将颜色数据从16位转换为两个8位的数据 data[i * 2] = (color_p->full) >> 8; // 获取高8位数据 data[i * 2 + 1] = (uint8_t)(color_p->full); // 获取低8位数据 color_p++; // 指向下一个颜色值 // 判断数据量是否大于10000,如果大于则分批发送数据 if (Pixel > 10000) { if ((i + 1) % data_split == 0) { if ((i + 1) == data_split) { Lcd_WriteData_DMA(data, data_split * 2); // 以DMA方式发送数据 } else { while (HAL_SPI_GetState(LCD_SPI) != HAL_SPI_STATE_READY); // 等待SPI总线空闲 uint8_t *temp = &data[((uint16_t)((i + 1) / data_split) - 1) * data_split * 2]; // 获取剩余数据 Lcd_WriteData_DMA(temp, data_split * 2); // 以DMA方式发送数据 } } else if (((i + 1) % data_split > 0) && ((i + 1) > data_split) && (i == (Pixel - 1))) { if ((uint16_t)((i + 1) / data_split) == 1) { while (HAL_SPI_GetState(LCD_SPI) != HAL_SPI_STATE_READY) ; // 等待SPI总线空闲 uint8_t *temp = &data[data_split * 2]; // 获取剩余数据 Lcd_WriteData_DMA(temp, ((i + 1) % data_split) * 2); // 以DMA方式发送数据 } else { while (HAL_SPI_GetState(LCD_SPI) != HAL_SPI_STATE_READY) ; // 等待SPI总线空闲 uint8_t *temp = &data[(uint16_t)((i + 1) / data_split) * data_split * 2]; // 获取剩余数据 Lcd_WriteData_DMA(temp, ((i + 1) % data_split) * 2); } } } } if (Pixel <= 10000) { // 要发送的数据小于10000*2字节时一次全部发送 Lcd_WriteData_DMA(data, Pixel * 2); } LCD_SetWindows(0, 0, lcddev.width - 1, lcddev.height - 1); // 恢复窗口设置为全屏 }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。