【嵌入式】MCU(HC32F460)+SPI接口LCD液晶屏ILI9341 移植emWin记录2----移植emWin

本文主要是介绍【嵌入式】MCU(HC32F460)+SPI接口LCD液晶屏ILI9341 移植emWin记录2----移植emWin,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一 emWin移植准备

        完成了前一文点亮LCD屏之后,考虑到将要设计较为复杂的界面GUI,光用一些基本的绘图、显示字符接口不能满足要求,所以琢磨着再移植一套emWin,用来辅助设计GUI(由emWin的用户手册中可以看到,emWin是可以支持ILI9341的液晶屏驱动芯片的)。

        emWin的移植需要做一些准备:

        【1】首先,在自己的工程目录下建立GUI文件夹,以存放相关的文件,这边衍生出来的子文件夹可以起到归纳分类的作用:

         【2】其次,前往官网下载或者在本地keil路径下(不同人安装路径不一样,我本机的路径在此E:\Pro Software\Keil_v5\ARM\PACK\Keil\MDK-Middleware\7.8.0\emWin\)找到emWin文件,确认版本(我这边用的是emWin V5.42)。找到移植需要的文件,并移入自己工程目录下的GUI文件夹中,具体如下:

 (注:关于库文件的CM3不用太纠结,CM3与CM4的主要区别在于浮点数的处理,某些地方可以通用)

        【3】在keil中添加上面的源文件,并包含上面的头文件路径:

        完成了上述准备工作之后,即可正式进入移植。

二 emWin移植步骤

        【1】修改GUIConf.c文件。这边只要改一下GUI_NUMBYTES 的值,这个定义的是分配内存的大小,太大可能会使得GUI_Init()卡死,修改为合适的值即可:

#define GUI_NUMBYTES ((1024)*56)/*********************************************************************
*
*       Public code
*
**********************************************************************
*/
/*********************************************************************
*
*       GUI_X_Config
*
* Purpose:
*   Called during the initialization process in order to set up the
*   available memory for the GUI.
*/
void GUI_X_Config(void) {//// 32 bit aligned memory area//static U32 aMemory[GUI_NUMBYTES / 4];//// Assign memory to emWin//GUI_ALLOC_AssignMemory(aMemory, GUI_NUMBYTES);//// Set default font//GUI_SetDefaultFont(GUI_FONT_6X8);
}

        【2】修改GUIDRV_Template.c文件。这边需要修改画点函数_SetPixelIndex(),在其中嵌入

自己的打点函数LCD_DrawPoint(x, y),打点函数的具体实现在前一篇文章驱动点亮SPI屏中有记录:

/*********************************************************************
*
*       _SetPixelIndex
*
* Purpose:
*   Sets the index of the given pixel. The upper layers
*   calling this routine make sure that the coordinates are in range, so
*   that no check on the parameters needs to be performed.
*/
static void _SetPixelIndex(GUI_DEVICE * pDevice, int x, int y, LCD_PIXELINDEX PixelIndex) {#ifdef WIN32LCDSIM_SetPixelIndex(x, y, PixelIndex, pDevice->LayerIndex);#else//// Convert logical into physical coordinates (Dep. on LCDConf.h)//#if (LCD_MIRROR_X == 1) || (LCD_MIRROR_Y == 1) || (LCD_SWAP_XY == 1)int xPhys, yPhys;xPhys = LOG2PHYS_X(x, y);yPhys = LOG2PHYS_Y(x, y);#else#define xPhys x#define yPhys y#endifGUI_USE_PARA(pDevice);GUI_USE_PARA(x);GUI_USE_PARA(y);GUI_USE_PARA(PixelIndex);{//// Write into hardware ... Adapt to your system//// TBD by customer...//LCD_DrawPoint(x, y);  //重要:自行添加的画点函数}#if (LCD_MIRROR_X == 0) && (LCD_MIRROR_Y == 0) && (LCD_SWAP_XY == 0)#undef xPhys#undef yPhys#endif#endif
}

        【3】修改GUI_X_RTX.c文件。这个文件是官方已经适配好RTX操作系统的,同理还有GUI_X_uCOS、GUI_X_FreeRTOS等其他操作系统的适配,基本上拿过来就直接用了。主要作用就是用你的操作系统,建立一个时钟任务,来控制GUI的运行。

        【4】修改LCDConf.c文件。这边是最重要的一步,主要目的就是将emWin和LCD显示屏建立连接

        这边先贴出来代码,下面再一一说明:

#include "GUI.h"
#include "GUIDRV_FlexColor.h"extern void LCD_AllInit(void);
extern void LCD_ConfigureREG(void);
extern void LCD_WriteCMD(U8 Command);
extern void LCD_WriteDAT(U8 Command);
/*********************************************************************
*
*       Layer configuration (to be modified)
*
**********************************************************************
*/
//
// Physical display size
//   The display size should be adapted in order to match the size of
//   the target display.
//
#define XSIZE_PHYS 320
#define YSIZE_PHYS 240//
// Color conversion
//   The color conversion functions should be selected according to
//   the color mode of the target display. Detaileds can be found in
//   the chapter "Colors" in the emWin user manual.
//
//#define COLOR_CONVERSION GUICC_8888
#define COLOR_CONVERSION GUICC_565//
// Display driver
//   GUIDRV_WIN32 is for use only within the emWin Simulation
//   environment. In order to use the target display controller, the
//   according emWin display driver should be configured as it is
//   described in the chapter "Display Drivers" in the emWin user
//   manual. Beyond that sample configuration files can be found in
//   The folder "Sample\LCDConf\%DISPLAY_DRIVER%\".
//
//#define DISPLAY_DRIVER GUIDRV_WIN32
#define DISPLAY_DRIVER &GUIDRV_Template_API/*********************************************************************
*
*       Configuration checking
*
**********************************************************************
*/
#ifndef   XSIZE_PHYS#error Physical X size of display is not defined!
#endif
#ifndef   YSIZE_PHYS#error Physical Y size of display is not defined!
#endif
#ifndef   COLOR_CONVERSION#error Color conversion not defined!
#endif
#ifndef   DISPLAY_DRIVER#error No display driver defined!
#endif/*********************************************************************
*
*       Public code
*
**********************************************************************
*/
static void LcdWriteReg(U8 Data) {LCD_WriteCMD(Data);
}static void LcdWriteData(U8 Data) {LCD_WriteDAT(Data);
}static void LcdWriteDataMultiple(U8 * pData, int NumItems) {while(NumItems--){LCD_WriteDAT(*pData);}
}static void LcdReadDataMultiple(U8 * pData, int NumItems) {return ;
}/*********************************************************************
*
*       LCD_X_Config
*
* Function description
*   Called during the initialization process in order to set up the
*   display driver configuration.
*/
void LCD_X_Config(void) {
//    //1.这种初始化用不了颜色
//    GUI_DEVICE_CreateAndLink(DISPLAY_DRIVER, COLOR_CONVERSION, 0, 0);
//    if (LCD_GetSwapXY()) {
//    LCD_SetSizeEx (0, YSIZE_PHYS, XSIZE_PHYS);
//    LCD_SetVSizeEx(0, YSIZE_PHYS, XSIZE_PHYS);
//    } else {
//    LCD_SetSizeEx (0, XSIZE_PHYS, YSIZE_PHYS);
//    LCD_SetVSizeEx(0, XSIZE_PHYS, YSIZE_PHYS);
//    }//2.这种初始化可以使用颜色GUI_DEVICE * pDevice;GUI_PORT_API PortAPI = {0};pDevice = GUI_DEVICE_CreateAndLink(&GUIDRV_FlexColor_API, COLOR_CONVERSION, 0, 0);if (LCD_GetSwapXY()) {LCD_SetSizeEx (0, YSIZE_PHYS, XSIZE_PHYS);LCD_SetVSizeEx(0, YSIZE_PHYS, XSIZE_PHYS);} else {LCD_SetSizeEx (0, XSIZE_PHYS, YSIZE_PHYS);LCD_SetVSizeEx(0, XSIZE_PHYS, YSIZE_PHYS);}PortAPI.pfWrite8_A0  = LcdWriteReg;PortAPI.pfWrite8_A1  = LcdWriteData;PortAPI.pfWriteM8_A1 = LcdWriteDataMultiple;PortAPI.pfReadM8_A1  = LcdReadDataMultiple;GUIDRV_FlexColor_SetFunc(pDevice, &PortAPI, GUIDRV_FLEXCOLOR_F66709, GUIDRV_FLEXCOLOR_M16C0B8);
}/*********************************************************************
*
*       LCD_X_DisplayDriver
*
* Function description
*   Display driver callback function. This function is called by the
*   Display driver for certain purposes. Using GUIDRV_Win32 it is not
*   required to react to any command.
*/
int LCD_X_DisplayDriver(unsigned LayerIndex, unsigned Cmd, void * pData) {GUI_USE_PARA(LayerIndex);GUI_USE_PARA(Cmd);GUI_USE_PARA(pData);//    LCD_AllInit();//重要:添加初始化函数LCD_ConfigureREG();return 0;
}/*************************** End of file ****************************/

        (1)首先是定义LCD的屏幕尺寸、颜色格式以及驱动配置(这边定义的驱动GUIDRV_Template_API来自于上面第二步中的配置,因为不是触摸屏,这边只定义了打点函数,没有定义读点函数)

         (2)LCD_X_Config配置。这边提供两种连接驱动(GUI_DEVICE_CreateAndLink)的方法,一开始用方法一,连接的是上面定义好打点函数的驱动&GUIDRV_Template_API,测试emWin可以绘图,但是颜色只能显示黑白的。遂换用第二种方法,连接GUIDRV_FlexColor.h中定义的驱动&GUIDRV_FlexColor_API,写命令/数据接口全部都自己定义,具体的实现也可以参考上一篇文章驱动点亮SPI屏。

        这两种方法的区别,本质在于一个是直接把打点函数传递给&GUIDRV_FlexColor_API,另一个是把写命令/数据的接口传递给&GUIDRV_FlexColor_API,让其自己在内部实现打点。感觉两种方法本质上是一样的,导致方法一颜色用不了的区别可能在于下面GUIDRV_FlexColor_SetFunc接口的使用,这边我就没有继续细究了,如果有大佬看到的话,希望能够在评论区给我解个惑(20211108追更关于这个问题的解答:参考这篇帖子方法一:直接线性访问驱动和方法二:间接访问驱动)。

        (3)LCD_X_DisplayDriver配置。加入自己的LCD初始化函数。这边的LCD_ConfigureREG()同样参考上一篇文章,这边就不在赘述了:

        总上,配置完尺寸、颜色、驱动、初始化接口几项内容之后,emWin就实现与LCD的联系(LCDConf.c),再结合前面的自身内存的配置(GUIConf.c),以及与操作系统的关联(GUI_X_RTX.c),emWin就移植成功了。

三 emWin效果实现

        emWin移植成功之后,再结合LCD显示屏,就可以显示一些复杂的界面和内容了,这边测试仅试用一下emWin画⚪以及显示字符的功能(其中,字符显示部分,参考文章【嵌入式】emwin中插入中文字体——FontCvt的使用):

/**************************************************************************
* 函数名称: GUI_Task
* 功能描述: GUI子任务
* 输入参数: 
* 输出参数: 
* 返 回 值: 
* 其它说明: 
**************************************************************************/
void GUI_Task(void)
{//使用emwin来绘图LCD_InitGPIO();  //初始化几个GPIO口,包括BL、DC、RES以及SPI的CSLCD_InitSPI1();  //初始化SPI的几个口,包括SCK、MOSI以及MISOLCD_HardwareReset();  //LCD复位GUI_Init();  //emwin初始化LCD_DisplayDir(1);  //默认为横屏LCD_Clear(WHITE);  //清屏白色GUI_SetBkColor(GUI_WHITE);GUI_AA_SetFactor(4);GUI_EnableAlpha(1);GUI_UC_SetEncodeUTF8();GUI_SetFont(&GUI_FontFont32);GUI_SetColor(BLACK); GUI_SetTextMode(GUI_TM_TRANS);GUI_DispStringAt("Hello LCD!", 160, 120);GUI_DispStringAt("欢迎!", 160, 60);GUI_DrawCircle(80, 60, 40);while(1){os_dly_wait(1000);}
}

        

四 汇总几个遇到的坑

        (1)欢迎两个字明明加到字库中了,但是屏幕上始终显示不了

        【问题解决】:查阅资料发现问题在于,执行中文显示的语句GUI_DispStringAt("欢迎!", 160, 60)所在的源文件,没有转化为UTF-8编码格式,照这下面帖子的方法即可解决:emWin—显示汉字。

        (2)GUI内存配置的GUI_NUMBYTES不宜过大,一开始用的默认0x200000,程序挂死,后面改小为1024*56即可。

        (3)颜色显示仍然有问题,使用GUI自带的颜色库,例如GUI_GREEN等,实际显示的颜色与设置的不一致,具体原因没搞清楚,猜测可能跟LCD支持的颜色为GUICC_565(0xFFFF),而GUI库中的颜色为GUICC_888(0xFFFFFF)有关。

五 附录

        【1】【嵌入式】MCU(HC32F460)+SPI接口LCD液晶屏ILI9341 移植emWin记录1----点亮LCD屏

        【2】【嵌入式】emwin中插入中文字体——FontCvt的使用

        【3】HC32F460资料汇总

        【4】emWin V5.42中文说明书

这篇关于【嵌入式】MCU(HC32F460)+SPI接口LCD液晶屏ILI9341 移植emWin记录2----移植emWin的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/212608

相关文章

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

Node.js学习记录(二)

目录 一、express 1、初识express 2、安装express 3、创建并启动web服务器 4、监听 GET&POST 请求、响应内容给客户端 5、获取URL中携带的查询参数 6、获取URL中动态参数 7、静态资源托管 二、工具nodemon 三、express路由 1、express中路由 2、路由的匹配 3、路由模块化 4、路由模块添加前缀 四、中间件

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

荣耀嵌入式面试题及参考答案

在项目中是否有使用过实时操作系统? 在我参与的项目中,有使用过实时操作系统。实时操作系统(RTOS)在对时间要求严格的应用场景中具有重要作用。我曾参与的一个工业自动化控制项目就采用了实时操作系统。在这个项目中,需要对多个传感器的数据进行实时采集和处理,并根据采集到的数据及时控制执行机构的动作。实时操作系统能够提供确定性的响应时间,确保关键任务在规定的时间内完成。 使用实时操作系统的

嵌入式Openharmony系统构建与启动详解

大家好,今天主要给大家分享一下,如何构建Openharmony子系统以及系统的启动过程分解。 第一:OpenHarmony系统构建      首先熟悉一下,构建系统是一种自动化处理工具的集合,通过将源代码文件进行一系列处理,最终生成和用户可以使用的目标文件。这里的目标文件包括静态链接库文件、动态链接库文件、可执行文件、脚本文件、配置文件等。      我们在编写hellowor

Java 后端接口入参 - 联合前端VUE 使用AES完成入参出参加密解密

加密效果: 解密后的数据就是正常数据: 后端:使用的是spring-cloud框架,在gateway模块进行操作 <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>30.0-jre</version></dependency> 编写一个AES加密

记录每次更新到仓库 —— Git 学习笔记 10

记录每次更新到仓库 文章目录 文件的状态三个区域检查当前文件状态跟踪新文件取消跟踪(un-tracking)文件重新跟踪(re-tracking)文件暂存已修改文件忽略某些文件查看已暂存和未暂存的修改提交更新跳过暂存区删除文件移动文件参考资料 咱们接着很多天以前的 取得Git仓库 这篇文章继续说。 文件的状态 不管是通过哪种方法,现在我们已经有了一个仓库,并从这个仓

嵌入式方向的毕业生,找工作很迷茫

一个应届硕士生的问题: 虽然我明白想成为技术大牛需要日积月累的磨练,但我总感觉自己学习方法或者哪些方面有问题,时间一天天过去,自己也每天不停学习,但总感觉自己没有想象中那样进步,总感觉找不到一个很清晰的学习规划……眼看 9 月份就要参加秋招了,我想毕业了去大城市磨练几年,涨涨见识,拓开眼界多学点东西。但是感觉自己的实力还是很不够,内心慌得不行,总怕浪费了这人生唯一的校招机会,当然我也明白,毕业

FreeRTOS-基本介绍和移植STM32

FreeRTOS-基本介绍和STM32移植 一、裸机开发和操作系统开发介绍二、任务调度和任务状态介绍2.1 任务调度2.1.1 抢占式调度2.1.2 时间片调度 2.2 任务状态 三、FreeRTOS源码和移植STM323.1 FreeRTOS源码3.2 FreeRTOS移植STM323.2.1 代码移植3.2.2 时钟中断配置 一、裸机开发和操作系统开发介绍 裸机:前后台系

学习记录:js算法(二十八):删除排序链表中的重复元素、删除排序链表中的重复元素II

文章目录 删除排序链表中的重复元素我的思路解法一:循环解法二:递归 网上思路 删除排序链表中的重复元素 II我的思路网上思路 总结 删除排序链表中的重复元素 给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。 图一 图二 示例 1:(图一)输入:head = [1,1,2]输出:[1,2]示例 2:(图