这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
icore4t_63 [2020/10/16 17:40] fmj |
icore4t_63 [2022/04/01 10:59] (当前版本) sean |
||
---|---|---|---|
行 2: | 行 2: | ||
|技术支持电话|**0379-69926675-801**||| | |技术支持电话|**0379-69926675-801**||| | ||
|技术支持邮件|Gingko@vip.163.com||| | |技术支持邮件|Gingko@vip.163.com||| | ||
- | |技术论坛|http://www.eeschool.org||| | ||
^ 版本 ^ 日期 ^ 作者 ^ 修改内容 ^ | ^ 版本 ^ 日期 ^ 作者 ^ 修改内容 ^ | ||
| V1.0 | 2020-10-16 | gingko | 初次建立 | | | V1.0 | 2020-10-16 | gingko | 初次建立 | | ||
+ | \\ | ||
+ | \\ | ||
+ | \\ | ||
+ | \\ | ||
+ | \\ | ||
+ | \\ | ||
+ | \\ | ||
+ | \\ | ||
===== STM32CubeMX教程六十三——TOUCH实验 ===== | ===== STM32CubeMX教程六十三——TOUCH实验 ===== | ||
行 59: | 行 65: | ||
16.然后点击GENERATE CODE 创建工程 | 16.然后点击GENERATE CODE 创建工程 | ||
{{ :icore4t:icore4t_cube_63_20.png?direct |}} | {{ :icore4t:icore4t_cube_63_20.png?direct |}} | ||
- | {{ :icore4t:icore4t_cube_63_21.png?direct |}} | + | |
创建成功,打开工程。 | 创建成功,打开工程。 | ||
\\ | \\ | ||
\\ | \\ | ||
\\ | \\ | ||
- | ===== 实验六十:LCD实验驱动4.3寸液晶屏 ===== | + | ===== 实验六十三:TOUCH实验——电容触摸 ===== |
==== 一、 实验目的与意义 ==== | ==== 一、 实验目的与意义 ==== | ||
- 了解STM32 LTDC结构 | - 了解STM32 LTDC结构 | ||
- 了解STM32 LTDC特征 | - 了解STM32 LTDC特征 | ||
- | - 掌握LCD液晶屏的使用方法 | + | - 掌握LTDC液晶屏的使用方法 |
- | - 掌握STM32 HAL库中LTDC属性的配置方法 | + | - 掌握LTDC应用之LCD电容触摸芯片GT911的使用方法 |
- 掌握KEIL MDK 集成开发环境使用方法 | - 掌握KEIL MDK 集成开发环境使用方法 | ||
==== 二、 实验设备及平台 ==== | ==== 二、 实验设备及平台 ==== | ||
- iCore4T 双核心板 | - iCore4T 双核心板 | ||
+ | - 转接板和40P的FPC连接线。 | ||
- iCore4T 扩展底板 | - iCore4T 扩展底板 | ||
- iCore 4.3寸液晶屏底板 | - iCore 4.3寸液晶屏底板 | ||
- | - JLINK(或相同功能)仿真器 | + | - Blaster(或相同功能)仿真器 |
- Micro USB线缆 | - Micro USB线缆 | ||
- Keil MDK 开发平台 | - Keil MDK 开发平台 | ||
行 83: | 行 90: | ||
==== 三、 实验原理 ==== | ==== 三、 实验原理 ==== | ||
- | === LCD-TFT显示控制器(LTDC) 简介 === | + | === 1. LTDC基础知识 === |
- | LCD-TFT(液晶显示器——薄膜晶体管)显示器控制器提供并行数字 RGB(红色、绿色、 蓝色)以及水平同步、垂直同步、像素时钟和数据使能信号,这些信号直接输出到不同 LCD 和 TFT 面板的接口。STM32H750xx 的 LTDC 主要特性如下: | + | * (一)LTDC关键知识点: |
- | * 24 位 RGB 并行像素输出;每像素 8 位数据(RGB888) | + | * 1)STM32H7的LTDC最大支持1024*768分辨率,且支持硬件双图层。实际支持的分辨率可能比1024*768要高一点,因为最 终可以支持的最大分辨率是芯片后期定标的。 |
- | * 2 个带有专用 FIFO 的显示层(FIFO 深度 64x64 位) | + | * 2)支持32位色,24位色,16位色和8位色。 |
- | * 支持查色表 (CLUT),每层高达 256 种颜色(256x24 位) | + | * 3)可编程窗口位置和大小,可编程行同步,场同步和数据使能信号的极性。 |
- | * 可针对不同显示面板编程时序 | + | * 4)查色表 (CLUT,Color look-up table),每个图层最高可记录256种24位色。 |
- | * 可编程背景色 | + | * 5)支持如下8种颜色格式: |
- | * 可编程 HSync、VSync 和数据使能(DE)信号的极性 | + | * **ARGB8888** |
- | * 每层有多达 8 种颜色格式可供选择:ARGB8888、RGB888、RGB565、ARGB1555、ARGB4444、L8(8 位 Luminance 或 CLUT)、AL44(4 位 alpha+4 位 luminance)和 AL88(8 位 alpha+8位 luminance) | + | * 32位颜色格式,一个像素点占用4字节,其中低位 3 字节用于颜色分量,高位字节用于 Alpha 混合。红、绿、蓝和 Alpha通道(0x00表示完全透明,0xFF表示完全不透明)都是 8 位表示。 |
- | * 每通道的低位采用伪随机抖动输出(红色、绿色、蓝色的抖动宽度为 2 位) | + | * 普通列表项目颜色格式:AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB。 |
- | * 使用 alpha 值(每像素或常数)在两层之间灵活混合 | + | * **RGB888** |
- | * 色键(透明颜色) | + | * 普通列表项目24位颜色格式,一个像素点占用3字节,分别用于红、绿、蓝。 |
- | * 可编程窗口位置和大小 | + | * 普通列表项目颜色格式:RRRRRRRRGGGGGGGGBBBBBBBB。 |
- | * 支持薄膜晶体管 (TFT) 彩色显示器 | + | * **RGB565** |
- | * AXI 主接口支持 16 个双字的突发 | + | * 16位颜色格式,一个像素点占用2字节,分别用于红、绿、蓝。 |
- | * 高达 4 个可编程中断事件 | + | * 颜色格式:RRRRRGGGGGGBBBBB。 |
- | LTDC 控制器主要包含:信号线、图像处理单元、AXI 接口、配置和状态寄存器以及时钟部分,其框图如下所示: | + | * **ARGB1555** |
- | {{ :icore4t:iCore4T_ARM_HAL_60_1.png?direct |}} | + | * 16位颜色格式,一个像素点占用2字节,Alpha通道使用1个位表示,等于0的时候表示完全透明,等于1的时候表示完全不透明。红、绿、蓝都是用5个位表示。 |
+ | * 颜色格式:ARRRRRGGGGGBBBBB。 | ||
+ | * **ARGB4444** | ||
+ | * 16位颜色格式,一个像素点占用2字节,Alpha通道使用2个位表示(0x0表示完全透明,0x3表示完全不透明)。红、绿、蓝都是用4个位表示。 | ||
+ | * 颜色格式:ARRRRRGGGGGBBBBB。 | ||
+ | * **L8 (8-bit luminance or CLUT)** | ||
+ | * 8位颜色格式,实际上仅仅是8位索引值,范围0–255,而每个索引值的具体颜色值在查色表CLUT里面存储。 | ||
+ | * **AL44 (4-bit alpha + 4-bit luminance)** | ||
+ | * 8位颜色格式,实际上是4位Alpha通道(0x0表示完全透明,0xF表示完全不透明)和4位的索引值,索引范围0–15,而每个索引值的具体颜色值在查色表CLUT里面存储。 | ||
+ | * **AL88 (8-bit alpha + 8-bit luminance)** | ||
+ | * 16位颜色格式,实际上是8位Alpha通道(0x00表示完全透明,0xFF表示完全不透明)和8位的索引值,索引范围0–255,而每个索引值的具体颜色值在查色表CLUT里面存储。 | ||
- | === 2.LCD的DE同步模式和HV同步模式 === | ||
- | 通常,STM32H7都是用SDRAM作为LCD的显存,LTDC控制器会从SDRAM读取数据刷新到LCD显示屏上。刷新模式有DE同步模式和HV同步模式两种。一般大分辨率显示屏用DE同步模式,小分辨率的显示屏用HV同步模式。 | + | * (二)LTDC 硬件框图: |
+ | {{ :icore4t:iCore4T_ARM_HAL_63_1.png?direct |}} | ||
+ | * ltdc_aclk :为LTDC寄存器提供时钟,时钟来自AXI时钟域。 | ||
+ | * ltdc_pclk :LTDC寄存器接口时钟。 | ||
+ | * ltdc_ker_ck :用于生成LCD_CLK(像素时钟输出)的LTDC内核时钟。 | ||
+ | * ltdc_li_it :LTDC行中断,用于触发MDMA。 | ||
+ | * ltdc_it :LTDC全局中断请求。 | ||
+ | * ltdc_err_it :LTDC全局错误中断请求。 | ||
+ | * 下面是LCD接口引脚,用于外接显示屏: | ||
+ | * LCD_CLK :像素时钟输出。 | ||
+ | * LCD_HSYNC :水平同步信号。 | ||
+ | * LCD_VSYN :垂直同步信号。 | ||
+ | * LCD_DE :数据使能信号。 | ||
+ | * LCD_R[7:0] :8位红色数据。 | ||
+ | * LCD_G[7:0] :8 位绿色数据。 | ||
+ | * LCD_B[7:0] :8位蓝色数据。 | ||
- | * DE同步模式 | + | === 2.电阻触摸、电容触摸相关知识=== |
+ | * 有了TFT裸屏后还要配套电阻触摸板或者电容触摸板才可以获取触摸信息。触摸板是贴到TFT屏上面的,然后再通过电阻触摸芯片就可以获取电阻触摸板的信息,通过电容触摸芯片采集电容触摸板的信息。目前市面上常用的电阻触摸IC是STMPE811,电容触摸IC是GT811、GT911和FT5X06。其中,电阻触摸和电容触摸两者的区别如下: | ||
+ | * 电阻触摸芯片STMPE811其实就是ADC,返回的是ADC数值,而电容触摸芯片GT811、GT911和FT5X06返回的是显示屏实际的坐标值。 | ||
+ | * 使用电阻触摸芯片STMPE811需要做触摸校准,而使用电容触摸芯片GT811、GT911和FT5X06是自动校准的,无需手动校准。 | ||
- | DE模式需要LCD_DE和LCD_CLK信号来控制刷新。比如一个800x480分辨率的裸屏,在DE有效信号的时候(高电平或低电平),就有800个LCD_CLK输出时钟来确认行中800个点。每个时钟有效的时候,从显存读取一次RGB数据。因为存在回扫信号,所以DE是个方波。一个周期的LCD_DE信号,裸屏就扫描一行。扫描480行后,又从第一行扫描开始。这个规律由裸屏的驱动IC所决定的。 | + | === 3.电容触摸芯片GT911介绍=== |
+ | * 在本实验中,选用电容触摸芯片GT911来实现电容触摸功能。 | ||
+ | * 电容触摸相比电阻触摸简单,因为电容触摸不需要做触摸校准,而且用的是触摸板和触摸芯片一体的,也不需要做寄存器初始化配置,上电后直接读取参数即可。 | ||
+ | * GT911、GT928、GT9147都属于GT9系列非单层多点触控芯片,他们支持的触控点数不同(GT928支持10个点、GT911支持5个点)、驱动和感应通道也可能不同。可是他们的寄存器和IIC通讯时序是相同的,也就是说驱动程序是兼容的。 | ||
+ | * GT911是专为7”~8”设计的新一代5点电容触控方案,拥有26个驱动通道和14个感应通道,以满足更高的touch精度要求。GT911可同时识别5个触摸点位的实时准确位置,移动轨迹及触摸面积。并可根据主控需要,读取相应点数的触摸信息。 | ||
+ | * 与主机的接口共有6PIN,分别为:VDD、GND、SCL、SDA、INT、RESET。 | ||
+ | * INT、RESET不需要接上下拉电阻,可与主机直连。 | ||
+ | * SCL、SDA需要接上拉电阻4.7K,毕竟400KHz的通信频率,没有上拉可能导致SCL、SDA边沿不够陡峭。 | ||
+ | * RST是复位引脚,拉低100us以上,即可复位。正常工作时,应该保持拉高。 | ||
+ | * INT是GT9xx的触摸信号输出引脚,在正常工作时,主机端要设置为悬浮输入,即不上下拉(GT9xx的驱动能力有限,如果外部上下拉,GT9xx可能驱动不了)。当有触摸发生时,INT引脚会输出上升沿或下降沿(内部寄存器可以配置),主机端可以一直读取INT脚的电平信号,也可以用端口外部中断检测。 | ||
- | * HV同步模式 | + | === 4.电容触摸芯片GT911的I2C通讯=== |
- | HV模式需要LCD_CLK时钟信号,行同步信号LCD_HSYNC和场同步信号LCD_VSYNC来控制刷新。比如一个480x272分辨率的裸屏,有一个行同步信号LCD_HSYNC产生时(高电平或者低电平脉冲),就有480个LCD_CLK输出时钟来确认行中480个点。每个时钟有效的时候,从显存读取一次RGB数据。再来一个行同步信号LCD_HSYNC产生时(高电平或者低电平脉冲),切换到下一行,继续行同步和时钟输出,扫描272行后,发送一个场同步信号LCD_VSYNC,又重新从第一行扫描开始。 | + | * GT911提供标准的I2C通讯接口,由SCL和SDA与主CPU进行通讯。在系统中GT911始终作为从设备,所有通讯都是由主CPU发起,建议通讯速度为400Kbps或以下。其支持的I2C硬件电路支持时序如下: |
+ | {{ :icore4t:iCore4T_ARM_HAL_63_2.png?direct |}} | ||
+ | * GT911的I2C从设备地址有两组,分别为0xBA/0xBB和0x28/0x29。主控在上电初始化时控制Reset和INT口状态进行设定,设定方法及时序图如下: | ||
+ | * 上电时序图: | ||
+ | {{ :icore4t:iCore4T_ARM_HAL_63_3.png?direct |}} | ||
+ | {{ :icore4t:iCore4T_ARM_HAL_63_4.png?direct |}} | ||
- | === 3.LTDC的时序配置 === | + | * **1)数据传输(以设备地址为0xBA/0xBB为例)** |
- | {{ :icore4t:iCore4T_ARM_HAL_60_2.png?direct |}} | + | |
- | LTDC的时序控制就是下面几个参数的设置,这几个参数都可以通过寄存器进行配置。 | + | |
- | + | ||
- | * HSYNC width水平同步宽度设置,以LCD_CLK的像素时钟输出为单位。 | + | |
- | * HBP(horizontal back porch period)水平后沿周期设置,以LCD_CLK的像素时钟输出为单位。 | + | |
- | * Active width有效宽度设置,以LCD_CLK的像素时钟输出为单位。以480*272分辨率为例,Active width = 480。 | + | |
- | * HFP(horizontal front porch period)水平前沿周期设置,以LCD_CLK的像素时钟输出为单位。 | + | |
- | * VSYNC width垂直同步宽度设置,以LCD_CLK的像素时钟输出为单位。 | + | |
- | * VBP(vertical back porch period)垂直后沿周期设置,以LCD_CLK的像素时钟输出为单位。 | + | |
- | * Active height有效高度设置,以LCD_CLK的像素时钟输出为单位。以480*272分辨率为例,Active height = 272。 | + | |
- | * VFP(vertical front porch period)垂直前沿周期设置,以LCD_CLK的像素时钟输出为单位。 | + | |
- | === 4.窗口 === | + | * 通讯总是由主 CPU 发起,有效的起始信号为:在 SCL 保持为“1”时,SDA 上发生由“1”到“0”的跳变。地址信息或数据流均在起始信号之后传输。 |
+ | * 所有连接在I2C总线上的从设备,都要检测总线上起始信号之后所发送的8位地址信息, | ||
+ | * 并做出正确反应。在收到与自己相匹配的地址信息时,GT911在第9个时钟周期,将SDA改为输出口,并置“0”,作为应答信号。若收到不与自己匹配的地址信息,即非0XBA或0XBB,GT911将保持闲置状态。 | ||
+ | * SDA口上的数据按9个时钟周期串行发送9位数据:8位有效数据+1位接收方发送的应答信号ACK或非应答信号NACK。数据传输在SCL为“1”时有效。 | ||
+ | * 当通讯完成时,由主CPU发送停止信号。停止信号是当SCL为“1”时,SDA状态由“0”到“1”的跳变。 | ||
- | 可为每个层定位和调整大小,各个层必须位于有效显示区域内。 | + | * **2)对GT911写操作(以设备地址为0xBA/0xBB为例)** |
- | 窗口位置和大小通过左上和右下的 X/Y 位置以及包含同步、后沿大小和有效数据区域的内部时序发生器配置。 | + | {{ :icore4t:iCore4T_ARM_HAL_63_5.png?direct |}} |
- | 可编程层位置和大小定义了一行中的第一个/最后一个可见像素和窗口中的第一个/最后一个可见行。它允许显示完整的图像帧,也允许只显示图像帧的一部分。 | + | * 上图为主CPU对GT911进行的写操作流程图。首先主CPU产生一个起始信号,然后发送地址信息及读写位信息“0”表示写操作:0XBA。在收到应答后,主CPU发送寄存器的16位地址,随后是8位要写入到寄存器的数据内容GT911寄存器的地址指针会在写操作后自动加1,所以当主CPU需要对连续地址的寄存器进行写操作时,可以在一次写操作中连续写入。写操作完成,主CPU发送停止信号结束当前写操作。 |
- | * 层中的第一个和最后一个可见像素通过配置 LTDC_LxWHPCR 寄存器中WHSTPOS[11:0] 和WHSPPOS[11:0] 进行设置。 | + | |
- | * 层中的第一个和最后一个可见行通过配置 LTDC_LxWVPCR 寄存器中的 WVSTPOS[10:0] 和 WVSPPOS[10:0] 进行设置。 | + | |
- | {{ :icore4t:iCore4T_ARM_HAL_60_3.png?direct |}} | + | |
- | === 5.LTDC层混合 === | + | * **3)对GT911读操作(以设备地址为0xBA/0xBB为例)** |
+ | {{ :icore4t:iCore4T_ARM_HAL_63_6.png?direct |}} | ||
+ | * 上图为主CPU对GT911进行的读操作流程图。首先主CPU产生一个起始信号,然后发送设备地址信息及读写位信息“0”表示写操作:0XBA。在收到应答后,主CPU发送首寄存器的16位地址信息,设置要读取的寄存器地址。在收到应答后,主CPU重新发送一次起始信号,发送读操作:0XBB。收到应答后,主CPU开始读取数据。 | ||
+ | * GT911同样支持连续的读操作,默认为连续读取数据。主CPU在每收到一个Byte数据后需发送一个应答信号表示成功接收。在接收到所需的最后一个Byte数据后,主CPU发送“非应答信号NACK”,然后再发送停止信号结束通讯。 | ||
- | LTDC除了图层1和图层2两个硬件图层以外,还有一个背景层。由于背景层的刷新不需要显存空间,所以可以用这个图层验证LTDC时序配置是否有问题。 | + | ===5.电容触摸芯片GT911功能描述=== |
- | {{ :icore4t:iCore4T_ARM_HAL_60_4.png?direct |}} | + | * (一)工作模式 |
+ | {{ :icore4t:iCore4T_ARM_HAL_63_7.png?direct |}} | ||
+ | * **a)Normal Mode** | ||
+ | * GT911在Normal Mode时,最快的坐标刷新周期为7ms-10ms间(依赖于配置信息的设定,配置信息可控周期步进长度为1ms)。 | ||
+ | * Normal mode状态下,一段时间无触摸事件发生,GT911将自动转入Green mode,以降低功耗。GT911无触摸自动进入Green mode的时间可通过配置信息设置,范围为0~15s,步进为1s。 | ||
+ | * **b)Green Mode** | ||
+ | * 在Green mode下,GT911扫描周期约为40ms,若检测到有触摸动作发生,自动进入Normal mode。 | ||
+ | * **c)Sleep Mode** | ||
+ | * 主CPU通过I2C命令,使GT911进入Sleep mode(需要先将INT脚输出低电平)。当需要GT911退出Sleep mode时,主机输出一个高电平到INT脚(主机打高INT脚2~5ms),唤醒后GT911将进入Normal mode。 | ||
+ | {{ :icore4t:iCore4T_ARM_HAL_63_8.png?direct |}} | ||
- | 背景层仅支持单色设置,固定颜色格式RGB888(LTDC_HandleTypeDef hltdc)我们这里将背景设置为白色: | + | * (二)中断触发方式 |
- | hltdc.Init.Backcolor.Blue = 255 | + | * 当有触摸时,GT911 每个扫描周期均会通过 INT 脚发出脉冲信号,通知主 CPU 读取坐标信息。主CPU可以通过相关的寄存器位“INT”来设置触发方式。设为“0”表示上升沿触发,即在有用户操作时,GT911会在INT口输出上升沿跳变,通知 CPU;设为“1”表示下降沿触发,即在有用户操作时,GT911会在INT口输出下降沿跳变。 |
- | hltdc.Init.Backcolor.Green = 255 | + | |
- | hltdc.Init.Backcolor.Red = 255 | + | |
- | 对于图层1和图层2来说,支持如下8种颜色格式: | ||
- | |||
- | - ARGB8888 | ||
- | - RGB888 | ||
- | - RGB565 | ||
- | - ARGB1555 | ||
- | - ARGB4444 | ||
- | - L8(8 位 Luminance 或 CLUT) | ||
- | - AL44(4 位 alpha + 4 位 luminance) | ||
- | - AL88(8 位 alpha + 8 位 luminance) | ||
- | |||
- | 实现Alpha混合的关键是要有一个变量可以设置各种透明度。对此,STM32H7准备了两个Alpha供使用: | ||
- | * 一个是常数Alpha(0x00表示完全透明,0xFF表示完全不透明),所有颜色格式都可以使用。 | ||
- | * 另一个是像素Alpha,也就是ARGB8888,ARGB1555,ARGB4444等颜色格式的Alpha通道数值,也就是我们为图层每个位置绘制的实际颜色值。 | ||
- | |||
- | STM32H7的参考手册给出了具体的混合公式: | ||
- | BC = BF1 x C + BF2 x Cs | ||
- | 混合后的颜色= 混合系数1 x 当前层颜色 + 混合系数2 x 底层混合后的颜色 | ||
==== 四、 实验程序 ==== | ==== 四、 实验程序 ==== | ||
行 171: | 行 201: | ||
int main(void) | int main(void) | ||
{ | { | ||
- | int i; | + | FATFS fatfs; |
- | HAL_Init(); | + | HAL_Init(); |
- | /* Configure the system clock */ | + | SystemClock_Config(); |
- | SystemClock_Config(); | + | i2c.initialize(); |
- | /* USER CODE BEGIN SysInit */ | + | axp152.initialize(); |
- | i2c.initialize(); //I2C初始化 | + | axp152.set_dcdc1(3500);//[ARM & FPGA BK1/2/6 &OTHER] |
- | axp152.initialize(); //电源芯片配置 | + | axp152.set_dcdc2(1200);//[FPGA INT & PLL D] |
- | axp152.set_dcdc1(3500);//[ARM & FPGA BK1/2/6 &OTHER] | + | axp152.set_aldo1(2500);//[FPGA PLL A] |
- | axp152.set_dcdc2(1200);//[FPGA INT & PLL D] | + | axp152.set_dcdc4(3300);//[POWER_OUTPUT] |
- | axp152.set_aldo1(2500);//[FPGA PLL A] | + | axp152.set_dcdc3(3300);//[FPGA BK4][Adjustable] |
- | axp152.set_dcdc4(3300);//[POWER_OUTPUT] | + | axp152.set_aldo2(3300);//[FPGA BK3][Adjustable] |
- | axp152.set_dcdc3(3300);//[FPGA BK4][Adjustable] | + | axp152.set_dldo1(3300);//[FPGA BK7][Adjustable] |
- | axp152.set_aldo2(3300);//[FPGA BK3][Adjustable] | + | axp152.set_dldo2(3300);//[FPGA BK5][Adjustable] |
- | axp152.set_dldo1(3300);//[FPGA BK7][Adjustable] | + | MX_GPIO_Init(); |
- | axp152.set_dldo2(3300);//[FPGA BK5][Adjustable] | + | MX_CRC_Init(); |
- | HAL_Delay(500); | + | MX_LTDC_Init(); |
- | /* USER CODE END SysInit */ | + | MX_TIM12_Init(); |
- | /* Initialize all configured peripherals */ | + | MX_SDMMC1_SD_Init(); |
- | MX_GPIO_Init(); //GPIO初始化 | + | MX_FATFS_Init(); |
- | MX_FMC_Init(); //FMC初始化 | + | MX_FMC_Init(); |
- | MX_LTDC_Init(); //LTDC初始化 | + | |
- | MX_TIM12_Init(); //TIM12初始化 | + | |
- | BSP_SDRAM_Init(); //SDRAM初始化 | + | |
- | HAL_TIM_PWM_Start(&htim12,TIM_CHANNEL_1); //定时器使能,通道1 | + | BSP_SDRAM_Init(); |
+ | lcd.initialize(); | ||
+ | |||
+ | HAL_TIM_PWM_Start(&htim12,TIM_CHANNEL_1); | ||
LED_ON; | LED_ON; | ||
- | + | GUI_Init(); | |
- | //帧缓冲区地址映射二维数组 | + | GUI_SetBkColor(GUI_BLACK); |
- | for(i = 0;i < LCD_HEIGHT;i ++)address_sdram[i] = LCD_SDRAM_ADDRESS + (i * LCD_WIDTH) * 2; | + | GUI_Clear(); |
- | + | ||
- | demo(); //运行弹球demo | + | |
LCD_ON; | LCD_ON; | ||
- | while (1) | + | |
- | { } | + | frame.process(); //界面处理 |
- | } | + | |
</code> | </code> | ||
- | === 2.弹球demo函数 === | + | ===2.LTDC参数初始化结构体LTDC_InitTypeDef === |
+ | * 此结构体用于配置LTDC的基本参数,具体定义如下: | ||
<code c> | <code c> | ||
- | void demo(void){ | + | typedef struct |
- | int bg = WHITE; //背景色 | + | { |
- | int colo[7] = {RED,BLUE,YELLOW,GREEN,0x7BEF,0x0000,0x03E0};//颜色列表 | + | uint32_t HSPolarity; |
- | int x=35,y=35,xs=1,ys=2; //圆心起始坐标,速度的xy分量 | + | uint32_t VSPolarity; |
- | int oldx,oldy,co=0,i,j; | + | uint32_t DEPolarity; |
- | int r=30; //圆半径 | + | uint32_t PCPolarity; |
- | clear_screen(bg); | + | uint32_t HorizontalSync; |
- | draw_circle(x, y, r, RED, 1); | + | uint32_tVerticalSync; |
- | + | uint32_t AccumulatedHBP; | |
- | while(1){ | + | uint32_t AccumulatedVBP; |
- | oldx = x; | + | uint32_t AccumulatedActiveW; |
- | oldy = y; | + | uint32_t AccumulatedActiveH; |
- | x = x + xs; | + | uint32_t TotalWidth; |
- | y = y + ys; | + | uint32_t TotalHeigh; |
- | if((x+r)>=480 || (x-r)<=0){ | + | LTDC_ColorTypeDef Backcolor; |
- | xs=-1*xs; | + | } LTDC_InitTypeDef; |
- | x = x + 2*xs; | + | |
- | co++; | + | |
- | if(co==7)co=0; | + | |
- | } | + | |
- | if((y+r)>=272 || (y-r)<=0){ | + | |
- | ys=-1*ys; | + | |
- | y = y + 2*ys; | + | |
- | co++; | + | |
- | if(co==7)co=0; | + | |
- | } | + | |
- | draw_circle(x, y, r, colo[co], 1); //画圆 | + | |
- | for(j = oldx-r-2;j < oldx+r+2;j ++){ | + | |
- | for(i = oldy-r-2;i < oldy+r+2;i ++){ | + | |
- | if(j<1 || j>479 || i<1 || i>271)continue; | + | |
- | if( (int)(x-j)*(x-j) + (int)(y-i)*(y-i) > (int)r*r ){ | + | |
- | *(volatile unsigned short int *) (address_sdram[i] + (j << 1)) = bg; | + | |
- | }}} | + | |
- | HAL_Delay(6); //延时 | + | |
- | } | + | |
- | } | + | |
</code> | </code> | ||
- | === 3.LTDC驱动配置 === | + | |
+ | * uint32_t HSPolarity | ||
+ | 此参数用于设置水平同步信号极性,具体支持的参数如下: | ||
+ | #define LTDC_HSPOLARITY_AL (0x00000000U) 水平同步极性低电平有效 | ||
+ | #define LTDC_HSPOLARITY_AH LTDC_GCR_HSPOL 水平同步极性高电平有效 | ||
+ | * uint32_t VSPolarity | ||
+ | 此参数用于设置垂直同步信号极性,具体支持的参数如下 | ||
+ | #define LTDC_VSPOLARITY_AL (0x00000000U) /* 垂直同步极性低电平有效 | ||
+ | #define LTDC_VSPOLARITY_AH LTDC_GCR_VSPOL /* 垂直同步极性高电平有效 | ||
+ | * uint32_t DEPolarity | ||
+ | 此参数用于设置数据使能极性,具体支持的参数如下: | ||
+ | #define LTDC_DEPOLARITY_AL (0x00000000U) /* 数据使能极性低电平有效 | ||
+ | #define LTDC_DEPOLARITY_AH LTDC_GCR_DEPOL /* 数据使能极性高电平有效 | ||
+ | * uint32_t PCPolarity | ||
+ | 此参数用于设置像素时钟极性,具体支持的参数如下: | ||
+ | #define LTDC_PCPOLARITY_IPC (0x00000000U) 像素时钟极性低电平有效 | ||
+ | #define LTDC_PCPOLARITY_IIPC LTDC_GCR_PCPOL 像素时钟极性高电平有效 | ||
+ | * uint32_t HorizontalSync | ||
+ | 此参数用于设置水平同步宽度,范围 0 x 000 0xFFF 单位像素时钟个数 。 | ||
+ | * uint32_t VerticalSync | ||
+ | 此参数用于设置垂直同步宽度,范围 0 x 000 0x 7 FF 单位像素时钟个数。 | ||
+ | * uint32_t AccumulatedHBP | ||
+ | 此参数用于设置 HSYNC水平同步宽度+ HBP水平后沿之和,范围HSYNC水平同步宽度到0 xFFF,单位像素时钟个数。 | ||
+ | * uint32_t AccumulatedVBP | ||
+ | 此参数用于设置VSYNC垂直同步宽度+ VBP垂直后沿之和,范围VSYNC垂直同步宽度到0x7FF,单位像素时钟个数。 | ||
+ | * uint32_t AccumulatedActiveW | ||
+ | 此参数用于设置HSYNC水平同步宽度+ HBP水平后沿+ 有效宽度之和,范围AccumulatedHBP到0xFFF,单位像素时钟个数。 | ||
+ | * uint32_t AccumulatedActiveH | ||
+ | 此参数用于设置VSYNC垂直同步宽度+ VBP垂直后沿+ 有效高度之和,范围AccumulatedVBP到0x7FF,单位像素时钟个数。 | ||
+ | * uint32_t TotalWidth | ||
+ | 此参数用于设置HSYNC水平同步宽度+ HBP水平后沿+ 有效宽度+ HFP水平前沿之和,范围AccumulatedActiveW到0xFFF,单位像素时钟个数。 | ||
+ | * uint32_t TotalHeigh | ||
+ | 此参数用于设置VSYNC垂直同步宽度+ VBP垂直后沿+ 有效高度+VFP垂直前沿之和,范围AccumulatedActiveH到0x7FF,单位像素时钟个数。 | ||
+ | * LTDC_ColorTypeDef Backcolor | ||
+ | 此参数用于设置背景层颜色,结构体LTDC_ColorTypeDef的定义如下: | ||
<code c> | <code c> | ||
- | void MX_LTDC_Init(void) | + | typedef struct |
{ | { | ||
- | LTDC_LayerCfgTypeDef pLayerCfg = {0}; | + | uint8_t Blue; |
- | LTDC_LayerCfgTypeDef pLayerCfg1 = {0}; | + | uint8_t Green; |
- | hltdc.Instance = LTDC; | + | uint8_t Red; |
- | hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AL; //水平同步极性 | + | uint8_t Reserved; |
- | hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AL; //垂直同步极性 | + | } LTDC_ColorTypeDef; |
- | hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL; //数据使能极性 | + | |
- | hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IPC; //像素时钟极性 | + | </code> |
- | hltdc.Init.HorizontalSync = 0; //水平同步宽度 | + | * Bule用于设置蓝色值,范围0x00到0xFF。 |
- | hltdc.Init.VerticalSync = 0; //垂直同步宽度 | + | * Green用于设置绿色值,范围0x00到0xFF。 |
- | hltdc.Init.AccumulatedHBP = 20; //水平同步后沿宽度 | + | * Red用于设置红色值,范围0x00到0xFF。 |
- | hltdc.Init.AccumulatedVBP = 9; //垂直同步后沿高度 | + | |
- | hltdc.Init.AccumulatedActiveW = 500;//有效宽度 | + | === 3.进行GUI界面处理 === |
- | hltdc.Init.AccumulatedActiveH = 281;//有效高度 | + | <code c> |
- | hltdc.Init.TotalWidth = 524; //总宽度 | + | static void frame_process(void) |
- | hltdc.Init.TotalHeigh = 287; //总高度 | + | { |
- | hltdc.Init.Backcolor.Blue = 255; //背景RGB数值,白色 | + | gt911.initialize(); |
- | hltdc.Init.Backcolor.Green = 255; | + | GUI_CURSOR_Show(); |
- | hltdc.Init.Backcolor.Red = 255; | + | WM_SetCreateFlags(WM_CF_MEMDEV); |
- | if (HAL_LTDC_Init(&hltdc) != HAL_OK) | + | GUI_CreateDialogBox(_aDialogCreate,GUI_COUNTOF(_aDialogCreate), _cbDialog, WM_HBKWIN, 0, 0); |
- | {Error_Handler();} | + | while(1){ |
- | pLayerCfg.WindowX0 = 0; //屏幕像素宽 | + | if(systick._20ms_flag == 1){ |
- | pLayerCfg.WindowX1 = 480; | + | systick._20ms_flag = 0; |
- | pLayerCfg.WindowY0 = 0; //屏幕像素高 | + | GUI_TOUCH_Exec(); |
- | pLayerCfg.WindowY1 = 272; | + | GUI_Exec(); |
- | pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565; //屏幕格式 | + | } |
- | pLayerCfg.Alpha = 0xff; //透明度,不透明 | + | if(touch_flag == 1){ |
- | pLayerCfg.Alpha0 = 0; //默认透明度 | + | touch_flag = 0; |
- | pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA; | + | EDIT_SetValue(h_edit_0,gt911.x[0]); |
- | pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_CA; | + | EDIT_SetValue(h_edit_1,gt911.y[0]); |
- | pLayerCfg.FBStartAdress = 0xC0000000; //帧缓冲区起始地址 | + | GUI_Exec(); |
- | pLayerCfg.ImageWidth = 480; //图层宽 | + | } |
- | pLayerCfg.ImageHeight = 272; //图层高 | + | GUI_Exec(); |
- | pLayerCfg.Backcolor.Blue = 255; //图层背景RGB数值,白色 | + | } |
- | pLayerCfg.Backcolor.Green = 255; | + | |
- | pLayerCfg.Backcolor.Red = 255; | + | |
- | if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg, 0) != HAL_OK) | + | |
- | { Error_Handler();} | + | |
} | } | ||
</code> | </code> | ||
- | === 4.画点函数 === | + | ===4.gui_frame函数实现GUI图形界面坐标设置 === |
<code c> | <code c> | ||
- | int set_pixel(int x, int y, int color) { | + | static int gui_frame(int startx,int starty,int endx,int endy) |
- | if(x<0 || x>480 || y<0 || y>272)return 0; | + | { |
- | *(volatile unsigned short int *) (address_sdram[y] + (x << 1)) = color; | + | GUI_SetColor(GUI_GRAY); |
- | return 1; | + | GUI_DrawRect(startx,starty,endx,endy); |
+ | GUI_SetColor(GUI_WHITE); | ||
+ | GUI_DrawHLine(starty + 1,startx + 1,endx - 1); | ||
+ | GUI_DrawHLine(endy + 1,startx,endx + 1); | ||
+ | GUI_DrawVLine(startx + 1,starty + 1,endy - 1); | ||
+ | GUI_DrawVLine(endx + 1,starty,endy + 1); | ||
+ | |||
+ | return 0; | ||
} | } | ||
+ | |||
</code> | </code> | ||
- | === 5.清屏函数 === | + | === 5.GT911写数据函数 === |
<code c> | <code c> | ||
- | void clear_screen(int color) | + | unsigned char GT911_WR_Reg(unsigned short int reg,unsigned char *buf,unsigned char len) |
{ | { | ||
- | int i,j; | + | unsigned char i; |
- | for(j = 0;j < LCD_WIDTH;j ++){ | + | unsigned char ret=0; |
- | for(i = 0;i < LCD_HEIGHT;i ++){ | + | |
- | *(volatile unsigned short int *) (address_sdram[i] + (j << 1)) = color; | + | i2c_touch.IIC_Start(); |
- | }}} | + | i2c_touch.IIC_Send_Byte(GT_CMD_WR); |
+ | i2c_touch.IIC_Wait_Ack(); | ||
+ | i2c_touch.IIC_Send_Byte(reg>>8); | ||
+ | i2c_touch.IIC_Wait_Ack(); | ||
+ | i2c_touch.IIC_Send_Byte(reg&0XFF); | ||
+ | i2c_touch.IIC_Wait_Ack(); | ||
+ | for(i=0;i<len;i++) | ||
+ | { | ||
+ | i2c_touch.IIC_Send_Byte(buf[i]); | ||
+ | ret=i2c_touch.IIC_Wait_Ack(); | ||
+ | if(ret)break; | ||
+ | } | ||
+ | i2c_touch.IIC_Stop(); | ||
+ | |||
+ | return ret; | ||
+ | } | ||
</code> | </code> | ||
- | === 6.画圆函数 === | + | === 6.GT911读数据函数 === |
<code c> | <code c> | ||
- | int draw_circle(int x, int y, int r, int color, int fill) { | + | void GT911_RD_Reg(unsigned short int reg,unsigned char *buf,unsigned char len) |
- | int i,j; | + | { |
- | if(x<0 || x>480 || y<0 || y>272)return 0; | + | unsigned char i; |
- | for(j = x-r;j < x+r;j ++){ | + | |
- | for(i = y-r;i < y+r;i ++){ | + | i2c_touch.IIC_Start(); |
- | if(fill == 1){ | + | i2c_touch.IIC_Send_Byte(GT_CMD_WR); |
- | if( (int)(x-j)*(x-j) + (int)(y-i)*(y-i) <= (int)r*r ){ | + | i2c_touch.IIC_Wait_Ack(); |
- | *(volatile unsigned short int *) (address_sdram[i] + (j << 1)) = color; | + | i2c_touch.IIC_Send_Byte(reg>>8); |
- | } | + | i2c_touch.IIC_Wait_Ack(); |
+ | i2c_touch.IIC_Send_Byte(reg&0XFF); | ||
+ | i2c_touch.IIC_Wait_Ack(); | ||
+ | |||
+ | i2c_touch.IIC_Start(); | ||
+ | i2c_touch.IIC_Send_Byte(GT_CMD_RD); | ||
+ | i2c_touch.IIC_Wait_Ack(); | ||
+ | |||
+ | for(i=0;i<len;i++) | ||
+ | { | ||
+ | buf[i]=i2c_touch.IIC_Read_Byte(i==(len-1)?0:1); | ||
+ | } | ||
+ | |||
+ | i2c_touch.IIC_Stop(); //产生一个停止条件 | ||
+ | |||
+ | |||
+ | </code> | ||
+ | |||
+ | === 7.scan函数:实现读取GT911触摸数据功能。 === | ||
+ | * 芯片GT911返回的就是实际的坐标值,比如显示屏的分辨率是480*272,那么返回的就是在这个分辨率范围内的实际坐标值。 | ||
+ | <code c> | ||
+ | int scan(unsigned char mode) | ||
+ | { | ||
+ | unsigned char buf[4]; | ||
+ | unsigned char i=0; | ||
+ | unsigned char temp; | ||
+ | GT911_RD_Reg(GT_GSTID_REG,&mode,1);//读取触摸点的状态 | ||
+ | if(mode&0X80&&((mode&0XF)<6)) | ||
+ | { | ||
+ | temp=0; | ||
+ | GT911_WR_Reg(GT_GSTID_REG,&temp,1);//清标志 | ||
+ | } | ||
+ | if((mode&0XF)&&((mode&0XF)<6)) | ||
+ | { | ||
+ | temp=0XFF<<(mode&0XF);//将点的个数转换为1的位数,匹配tp_dev.sta定义 | ||
+ | gt911.sta=(~temp); | ||
+ | for(i=0;i<5;i++) | ||
+ | { | ||
+ | if(gt911.sta&(1<<i)) | ||
+ | { | ||
+ | GT911_RD_Reg(GT911_TPX_TBL[i],buf,4);//读取XY坐标值 | ||
+ | gt911.x[i]=(((unsigned short int)buf[1]<<8)+buf[0]); | ||
+ | gt911.y[i]=(((unsigned short int)buf[3]<<8)+buf[2]); | ||
} | } | ||
- | else{ | + | } |
- | if( (x-i)*(x-i) + (y-j)*(y-j) >= (r-2)*(r) && (x-i)*(x-i) + (y-j)*(y-j) <= (r+1)*(r) ){ | + | }else{//设置XY坐标默认值 |
- | *(volatile unsigned short int *) (address_sdram[i] + (j << 1)) = color; | + | gt911.x[0]=480; |
- | } | + | gt911.y[0]=272; |
- | } | + | gt911.x[1]=480; |
- | } | + | gt911.y[1]=272; |
+ | gt911.x[2]=480; | ||
+ | gt911.y[2]=272; | ||
+ | gt911.x[3]=480; | ||
+ | gt911.y[3]=272; | ||
+ | gt911.x[4]=480; | ||
+ | gt911.y[4]=272; | ||
} | } | ||
- | return 1; | + | return 0; |
} | } | ||
- | </code> | ||
+ | </code> | ||
==== 五、 实验步骤 ==== | ==== 五、 实验步骤 ==== | ||
- 把仿真器与iCore4T的SWD调试口相连(直接相连或者通过转接器相连); | - 把仿真器与iCore4T的SWD调试口相连(直接相连或者通过转接器相连); | ||
行 342: | 行 455: | ||
==== 六、 实验现象 ==== | ==== 六、 实验现象 ==== | ||
- | 有一个小球在屏幕中来回弹,触碰到边界时小球颜色改变。 | + | 触摸iCore4T(4.3寸TFT_LCD)液晶屏即显示当前触摸位置的坐标值。 |