基于STM32的TFT

您所在的位置:网站首页 tk6102i屏幕校正方法 基于STM32的TFT

基于STM32的TFT

2024-06-28 23:55| 来源: 网络整理| 查看: 265

        前言:TFT-LCD作为显示终端必不可少的设备,目前大部分的TFT-LCD都具备了触摸功能。无论是在MCU亦或是SOC(MPU)中,触摸屏的使用都是十分常见的。触摸屏LCD通常分为2种:电阻触摸屏,电容触摸屏。两种不同的触摸屏LCD其编程与使用也存在一定的差别,本文将详细介绍电阻触摸屏与电容触摸屏的特点,并就电阻触摸屏进行代码编程讲解——HAL库。(文章结尾会有代码开源)

        实验硬件:STM32F103ZET6;2.4寸TFT-LCD-电阻式触摸屏(240×320)

        硬件实物图:

        效果图:

引脚连接:

LCD显示引脚:

VCC --> 3.3V

GND --> GND

CS --> PB11

Reset --> PB12

DC --> PB10

SDI --> PB15

SCK --> PB13

LED -->  PB9(控制LCD背光,可以同PWM调节改变LCD亮暗)

TOUCH电阻触摸引脚:

IRQ(INT) --> PC1

DOUT(MISO) --> PB4

TDIN(MOSI) --> PB5

TCLK --> PB3

TCS --> PC13

一、LCD触摸屏——Touch  1.1 电阻式触摸屏

        在 Iphone 面世之前,几乎清一色的都是使用电阻式触摸屏,电阻式触摸屏利用压力感应进行触点检测控制,需要直接应力接触,通过检测电阻来定位触摸位置。

        电阻触摸屏的主要部分是一块与显示器表面非常配合的电阻薄膜屏,这是一种多层的复合薄膜,它以一层玻璃或硬塑料平板作为基层,表面涂有一层透明氧化金属(透明的导电电阻)导电层,上面再盖有一层外表面硬化处理、光滑防擦的塑料层、它的内表面也涂有一层涂层、在他们之间有许多细小的(小于 1/1000 英寸)的透明隔离点把两层导电层隔开绝缘。 当手指触摸屏幕时,两层导电层在触摸点位置就有了接触,电阻发生变化,在 X 和 Y 两个方向上产生信号,然后送触摸屏控制器。控制器侦测到这一接触并计算出(X,Y)的位置,再根据获得的位置模拟鼠标的方式运作。这就是电阻技术触摸屏的最基本的原理,具体情况如下图所示:

         笔者使用的这块触摸屏就是电阻式触摸屏,其自带的触摸屏控制芯片为XPT2046(在LCD显示屏的背面U1即是该芯片)。XPT2046 是一款 4 导线制触摸屏控制器(SPI通讯方式),内含 12 位分辨率 125KHz 转换速率逐步逼近型 A/D 转换器。XPT2046 支持从 1.5V到 5.25V 的低电压 I/O 接口。XPT2046 能通过执行两次 A/D 转换查出被按的屏幕位置, 除此之外,还可以测量加在触摸屏上的压力。工作温度范围为-40℃~+85℃。

        该芯片完全是兼容 ADS7843 和 ADS7846 的,关于这个芯片的详细使用,可以参考这两个芯片的 datasheet。

注意事项:

        (1)使用XPT2046芯片时候,直接利用SPI通讯(软硬件皆可)去读取MISO端输出的高12位数据,再将其经过坐标转换与滤波操作进行X,Y坐标读取;(这一点编程过程可以体现出)

        (2)电阻触摸屏因其特殊的物理性质,基本使用都是需要校准一下触摸误差的,但是基本同一类型LCD的电阻屏,其校准数据大致近似;

        (3)由于电阻触摸屏需要校准的机制存在,一般使用前都需要采点校准。当然,我们可以使用24CXX(EEPROM)去保存校准补偿参数,之后每次开机就不需要去重新校准了;(在迫不得已,考虑成本的情况下,其实可以将校准数据保存在flash中——不是很推荐);

电阻触摸屏的优点:精度高、价格便宜、抗干扰能力强、稳定性好。电阻触摸屏的缺点:容易被划伤、透光性不太好、不支持多点触摸。(需要进行基准校正,否则偏移量不小)

1.2 电容式触摸屏

        现在几乎所有智能手机,包括平板电脑都是采用电容屏作为触摸屏,电容屏是利用人体感应进行触点检测控制,不需要直接接触或只需要轻微接触,通过检测感应电流来定位触摸坐标。(目前,基本电容式触摸屏为主流)

        电容式触摸屏主要分为两种:

        1、 表面电容式电容触摸屏。

        表面电容式触摸屏技术是利用 ITO(铟锡氧化物,是一种透明的导电材料)导电膜,通过电场感应方式感测屏幕表面的触摸行为进行。但是表面电容式触摸屏有一些局限性,它只能识别一个手指或者一次触摸。(使用较少)

        2、 投射式电容触摸屏。

        投射电容式触摸屏是传感器利用触摸屏电极发射出静电场线。一般用于投射电容传感技术的电容类型有两种:自我电容和交互电容。

        自我电容又称绝对电容,是最广为采用的一种方法,自我电容通常是指扫描电极与地构成的电容。在玻璃表面有用 ITO 制成的横向与纵向的扫描电极,这些电极和地之间就构成一个电容的两极。当用手或触摸笔触摸的时候就会并联一个电容到电路中去,从而使在该条扫描线上的总体的电容量有所改变。

        交互电容又叫做跨越电容,它是在玻璃表面的横向和纵向的 ITO 电极的交叉处形成电容。交互电容的扫描方式就是扫描每个交叉处的电容变化,来判定触摸点的位置。当触摸的时候就会影响到相邻电极的耦合,从而改变交叉处的电容量,交互电容的扫面方法可以侦测到每个交叉点的电容值和触摸后电容变化,因而它需要的扫描时间与自我电容的扫描方式相比要长一些,需要扫描检测 X*Y 根电极。目前智能手机/平板电脑等的触摸屏,都是采用交互电容技术。(笔者的正点原子精英板的LCD就是电容式触摸屏)

        透射式电容触摸屏采用纵横两列电极组成感应矩阵,来感应触摸。以两个交叉的电极矩阵,即: X 轴电极和 Y 轴电极,来检测每一格感应单元的电容变化,如下图所示:

        示意图中的电极,实际是透明的,这里是为了方便大家理解。图中,X、Y 轴的透明电极电容屏的精度、分辨率与 X、Y 轴的通道数有关,通道数越多,精度越高。

电容触摸屏的优点:手感好、无需校准、支持多点触摸、透光性好。电容触摸屏的缺点:成本高、精度不高、抗干扰能力差。

二、24CXX简介

        24CXX系列芯片属于EEPROM(Electrically Erasable Programmable read only memory)即掉电可擦可编程只读存储器,是一种掉电后数据不丢失(不挥发)存储芯片。

        该系列芯片由美国Mcrochip公司出品,1-512K位的支持I2C总线数据传送协议的串行CMOS E2PROM,可用电擦除,可编程自定时写周期(包括自动擦除时间不超过10ms,典型时间为5ms)的。串行E2PROM一般具有两种写入方式,一种是字节写入方式,还有另一种页写入方式。允许在一个写周期内同时对1个字节到一页的若干字节的编程写入,1页的大小取决于芯片内页寄存器的大小。其中,AT24C01具有8字节数据的页面写能力,AT24C02/04/08/16具有16字节数据的页面写能力,AT24C32/64具有32字节数据的页面写能力。

特别说明:

        电容式触摸屏一般不需要进行校准,所以可以不使用EEPROM去保存校准参数。电阻式触摸屏几乎是一定需要进行校准的,可以将校准后得到的参数数值保存在EEPROM中,随后,直接带入原程序进行补偿。(迫不得已的情况下,可以使用flash去代替EEPROM保存校准参数)

        24CXX系列芯片的使用就是利用I2C通讯去在24CXX芯片的地址中进行读写操作,可以参考笔者的Flash读写实验那篇文章,原理大致相同。(当然,本文也会贴出相关代码)

三、CubexMX配置

1、RCC配置外部高速晶振(精度更高)——HSE;

2、SYS配置:Debug设置成Serial Wire(否则可能导致芯片自锁);

3、TIM1配置:SPI读取电阻式触摸屏,进行AD转换的时候,需要us级别的延迟去让芯片转换数据;

 4、I2C1配置:利用I2C通讯去对AT24CXX进行读写操作;

 5、SPI2配置:利用HAL库的SPI2去点亮操作TFT-LCD屏幕;

 6、GPIO模拟SPI配置:这里没有直接在CubeMX中启用软件SPI通讯,因为发现了HAL库自带SPI的一点BUG,转而直接GPIO去模拟SPI;

 7、GPIO配置:(1)将PB9,PB10,PB11,PB12都设置为GPIO_OUTPUT,速度为:Hight。(2)PC1配置为Touch的中断引脚,PC13配置为片选引脚;

 8、时钟树配置:

9、工程配置 

四、代码

        下面的代码是基于HAL库的电阻式触摸屏代码,讲解也是基于电阻式进行分析的。(文末的代码里面也含有电容式的,需要的朋友自取)

4.1 TFT-LCD显示部分代码

        由于篇幅有限,这部分代码和讲解读者朋友可以参考本人的这篇文章,内容十分详尽。

【强烈推荐】基于STM32的TFT-LCD各种显示实现(内容详尽含代码)_混分巨兽龙某某的博客-CSDN博客_stm32lcd显示波形程序https://blog.csdn.net/black_sneak/article/details/125583293?spm=1001.2014.3001.5501

 4.2 AT24CXX代码

        AT24CXX主要是保存电阻式触摸屏校准的参数数据,利用I2C进行通讯。(电容屏可以忽略)

24cxx.h代码:

#ifndef __24CXX_H__ #define __24CXX_H__ /***************************************** 本驱动文件仅适配HAL库版本 ******************************************/ #include "stm32f1xx_hal.h" //链接HAL库 typedef enum { false, true, }bool; #define AT24C01 127 #define AT24C02 255 #define AT24C04 511 #define AT24C08 1023 #define AT24C16 2047 #define AT24C32 4095 #define AT24C64 8191 #define AT24C128 16383 #define AT24C256 32767 //我使用的是AT24C128 #define EE_TYPE AT24C02 uint8_t HAL_AT24CXX_ReadOneByte(uint16_t ReadAddr); uint8_t HAL_AT24CXX_WriteOneByte(uint16_t WriteAddr,uint8_t WriteData); void HAL_AT24CXX_WriteLenByte(uint16_t WriteAddr,uint8_t *pData,uint8_t dataLen); void HAL_AT24CXX_ReadLenByte(uint16_t ReadAddr,uint8_t *pData,uint8_t dataLen); bool HAL_AT24CXX_Check(void); #endif

24cxx.h代码:

/*********************************** 适用范围:仅HAL适用 ***********************************/ #include "24cxx.h" #include "i2c.h" #include #define IICx hi2c1 //IIC接口 #define AT24C_DEV_WRITEADDR 0xA0 //设备地址 #define AT24C_DEV_READADDR 0xA1 //设备地址 /***************************************** 函数名:void HAL_AT24CXX_WriteOneByte(uint16_t WriteAddr,uint8_t WriteData) 参数:WriteAddr :要写入数据的地址 WriteData:要写入的数据 功能描述:在指定地址写入一个字节数据 返回值:无 *****************************************/ uint8_t HAL_AT24CXX_WriteOneByte(uint16_t WriteAddr,uint8_t WriteData) { uint8_t res = 0xff; if(EE_TYPE < AT24C16) { if(HAL_I2C_Mem_Write(&IICx,AT24C_DEV_WRITEADDR,WriteAddr,I2C_MEMADD_SIZE_8BIT,&WriteData,1,0xff) == HAL_OK) res = 0; } else if(HAL_I2C_Mem_Write(&IICx,AT24C_DEV_WRITEADDR,WriteAddr,I2C_MEMADD_SIZE_16BIT,&WriteData,1,0xff) == HAL_OK) res = 0; HAL_Delay(10); return res; } /***************************************** 函数名:uint8_t HAL_AT24CXX_ReadOneByte(uint16_t ReadAddr) 参数: ReadAddr:要读取数据的地址 功能描述:在指定地址读取一个字节数据 返回值:返回读取地址的数据 *****************************************/ uint8_t HAL_AT24CXX_ReadOneByte(uint16_t ReadAddr) { uint8_t rxData = 0; if(EE_TYPE < AT24C16) { HAL_I2C_Mem_Read(&IICx,AT24C_DEV_READADDR,ReadAddr,I2C_MEMADD_SIZE_8BIT,&rxData,1,0xff); } else HAL_I2C_Mem_Read(&IICx,AT24C_DEV_READADDR,ReadAddr,I2C_MEMADD_SIZE_16BIT,&rxData,1,0xff); HAL_Delay(10); return rxData; } /***************************************** 函数名:void HAL_AT24CXX_WriteLenByte(uint16_t WriteAddr,uint8_t *pData,uint8_t dataLen) 参数:WriteAddr :要写入数据的地址 pData:要写入的数据的首地址 datalen:要写入数据的长度 功能描述:从指定地址开始写入多个字节数据 返回值:无 *****************************************/ void HAL_AT24CXX_WriteLenByte(uint16_t WriteAddr,uint8_t *pData,uint8_t dataLen) { while(dataLen--) { HAL_AT24CXX_WriteOneByte(WriteAddr,*pData); WriteAddr++; pData++; } } /***************************************** 函数名:void HAL_AT24CXX_ReadLenByte(uint16_t ReadAddr,uint8_t *pData,uint8_t dataLen) 参数: ReadAddr:要读取数据的地址 pData:回填数据首地址 dataLen:数据长度 功能描述:从指定地址开始读取多个个字节数据 返回值:无 *****************************************/ void HAL_AT24CXX_ReadLenByte(uint16_t ReadAddr,uint8_t *pData,uint8_t dataLen) { while(dataLen--) { *pData++ = HAL_AT24CXX_ReadOneByte(ReadAddr++); } } /***************************************** 函数名:uint8_t HAL_AT24CXX_Check(void) 参数:无 功能描述:检查AT24CXX是否正常,这里用了24XX的最后一个地址(255)来存储标志字.如果用其他24C系列,这个地址要修改 返回值:检测成功返回0 失败返回1 *****************************************/ bool HAL_AT24CXX_Check(void) { uint8_t temp; temp = HAL_AT24CXX_ReadOneByte(EE_TYPE);//避免每次开机都写AT24CXX if(temp == 0XAB) return true; else//排除第一次初始化的情况 { HAL_AT24CXX_WriteOneByte(EE_TYPE,0XAB); temp = HAL_AT24CXX_ReadOneByte(EE_TYPE); if(temp == 0XAB) return true; } return false; } 4.3 TOUCH代码

        这部分代码主要分为2个部分:

        (1)一个部分是SPI通讯之后读取XPT2046的数据,之后将AD数据转换成X,Y坐标信息;

        (2)另一部分是电阻式触摸屏的校准程序;

touch.h代码:

#ifndef __TOUCH_H__ #define __TOUCH_H__ #include "main.h" //=========================================触摸屏触接线=========================================// #define u16 unsigned int #define u8 unsigned char #define TP_PRES_DOWN 0x80 //触屏被按下 #define TP_CATH_PRES 0x40 //有按键按下了 //触摸屏控制器 typedef struct { // u8 (*init)(void); //初始化触摸屏控制器 u8 (*scan)(u8); //扫描触摸屏.0,屏幕扫描;1,物理坐标; // void (*adjust)(void); //触摸屏校准 u16 x0; //原始坐标(第一次按下时的坐标) u16 y0; u16 x; //当前坐标(此次扫描时,触屏的坐标) u16 y; u8 sta; //笔的状态 //b7:按下1/松开0; //b6:0,没有按键按下;1,有按键按下. 触摸屏校准参数/ float xfac; float yfac; short xoff; short yoff; //新增的参数,当触摸屏的左右上下完全颠倒时需要用到. //touchtype=0的时候,适合左右为X坐标,上下为Y坐标的TP. //touchtype=1的时候,适合左右为Y坐标,上下为X坐标的TP. u8 touchtype; }_m_tp_dev; extern _m_tp_dev tp_dev; //触屏控制器在touch.c里面定义 //与触摸屏芯片连接引脚 //#define PEN PCin(1) //PC1 INT //#define DOUT PCin(2) //PC2 MISO //#define TDIN PCout(3) //PC3 MOSI //#define TCLK PCout(0) //PC0 SCLK //#define TCS PCout(13) //PC13 CS //与触摸屏芯片连接引脚 #define PEN_SET HAL_GPIO_WritePin(GPIOC,GPIO_PIN_1,GPIO_PIN_SET) //PC1 INT #define PEN_CLR HAL_GPIO_WritePin(GPIOC,GPIO_PIN_1,GPIO_PIN_RESET) #define DOUT_SET HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_SET) //PB4 MISO #define DOUT_CLR HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_RESET) #define TDIN_SET HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET) //PB5 MOSI #define TDIN_CLR HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_RESET) #define TCLK_SET HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3,GPIO_PIN_SET) //PB3 SCLK #define TCLK_CLR HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3,GPIO_PIN_RESET) #define TCS_SET HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET) //PC13 CS #define TCS_CLR HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET) void TP_Write_Byte(u8 num); //向控制芯片写入一个数据 u16 TP_Read_AD(u8 CMD); //读取AD转换值 u16 TP_Read_XOY(u8 xy); //带滤波的坐标读取(X/Y) u8 TP_Read_XY(u16 *x,u16 *y); //双方向读取(X+Y) u8 TP_Read_XY2(u16 *x,u16 *y); //带加强滤波的双方向坐标读取 void TP_Drow_Touch_Point(u16 x,u16 y,u16 color);//画一个坐标校准点 void TP_Draw_Big_Point(u16 x,u16 y,u16 color); //画一个大点 u8 TP_Scan(u8 tp); //扫描 void TP_Save_Adjdata(void); //保存校准参数 u8 TP_Get_Adjdata(void); //读取校准参数 void TP_Adjust(void); //触摸屏校准 u8 TP_Init(void); //初始化 void TP_Adj_Info_Show(u16 x0,u16 y0,u16 x1,u16 y1,u16 x2,u16 y2,u16 x3,u16 y3,u16 fac);//显示校准信息 #endif

touch.c代码:

第一部分:读取X,Y坐标部分:这里部分读者朋友可能好奇为什么,没有直接使用CubeMX里面自带的HAL库函数进行SPI通讯读取XPT2046的数值,这里是因为笔者在做相关实验的时候发现了自带函数的一些bug问题。为了规避出现的BUG,这里还是利用HAL库去使用GPIO模拟SPI。

#include "touch.h" #include "lcd.h" #include "stdlib.h" #include "math.h" #include "24cxx.h" #include "gui.h" #include "gpio.h" #include "tim.h" _m_tp_dev tp_dev= { // TP_Init, TP_Scan, // TP_Adjust, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; //默认为touchtype=0的数据. //u8 CMD_RDX=0XD0; //u8 CMD_RDY=0X90; u8 CMD_RDX=0X90; u8 CMD_RDY=0XD0; //SPI写数据 //向触摸屏IC写入1byte数据 //num:要写入的数据 void TP_Write_Byte(u8 num) { u8 count=0; for(count=0;count


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3