写点什么

STM32 入门开发:编写 XPT2046 电阻触摸屏驱动 (模拟 SPI)

作者:DS小龙哥
  • 2022 年 8 月 17 日
    重庆
  • 本文字数:3768 字

    阅读完需:约 12 分钟

XPT2046 是一颗 12 位的 ADC 芯片,可以当做普通的 ADC 芯片使用,但是一般都是用在电阻触摸屏上,方便定位触摸屏坐标。 这篇文章介绍 XPT2046 芯片使用方法,介绍内部的时序,指令,使用场景,利用 STM32 读取 XPT2046 采集的触摸屏坐标。

一、环境介绍

单片机采用: STM32F103ZET6


编程软件: keil5


编程语言: C 语言


编程风格: 寄存器开发.


目标芯片: XPT2046---标准 SPI 接口时序

二、XPT2046 芯片介绍

2.1 功能

XPT2046 是一颗 12 位的 ADC 芯片,可以当做普通的 ADC 芯片使用,但是一般都是用在电阻触摸屏上,方便定位触摸屏坐标。



图 1: XPT2046 内部原理图



图 2:电阻触摸屏---引出的 4 条线就接在 XPT2046 的 YN\XN\YP\XP 上


(XPT2046 支持笔中断输出--低电平有效,这个引脚可以配置到单片机的中断脚上,或者轮询判断这个引脚状态,判断触摸屏是否已经按下)


可以单独买一个触摸屏+一个 XPT2046 就可以自己做手画板、触摸按键(自己用一张纸在下面画个模型就行)、等等很多小玩意。



图 3:采用的电阻触摸屏的 LCD 屏(上面盖的哪一层薄膜就是触摸用的)


2.2 特性

\1. 工作电压范围为 2.2V~5.25V\2. 支持 1.5V~5.25V 的数字 I/O 口\3. 内建 2.5V 参考电压源\4. 电源电压测量(0V~6)\5. 内建温度测量功能\6. 触摸压力测量\7. 采用 SPI 3 线控制通信接口\8. 具有自动 power-down 功能\9. 封装:QFN-16、 TSSOP-16 和 VFBGA-48 与 TSC2046、 AK4182A 完全兼容\10. XPT2046 在 125KHz 转换速率和 2.7V 电压下的功耗仅为 750 µW。 XPT2046 11. 以其低功耗和高速率等特性,被广泛应用在采用电池供电的小型手持设备上,比如 PDA、手机等。\12. XPT2046 有 TSSOP-16、 QFN-16 和 VFBGA 三种封装形式,温度范围是 - 40 ~ + 85℃ 。

2.3 工作原理

XPT2046 是一种典型的逐次逼近型模数转换器(SAR ADC),包含了采样/保持、模数转换、串口数据输出等功能。同时芯片集成有一个 2.5V 的内部参考电压源、温度检测电路,工作时使用外部时钟。 XPT2046 可以单电源供电,电源电压范围为 2.7V~5.5V。参考电压值直接决定 ADC 的输入范围,参考电压可以使用内部参考电压,也可以从外部直接输入 1V~VCC 范围内的参考电压(要求外部参考电压源输出阻抗低)。 X、 Y、 Z、 VBAT、 Temp 和 AUX 模拟信号经过片内的控制寄存器选择后进入 ADC, ADC 可以配置为单端或差分模式。选择 VBAT、 Temp 和 AUX 时可以配置为单端模式;作为触摸屏应用时,可以配置为差分模式,这可有效消除由于驱动开关的寄生电阻及外部的干扰带来的测量误差,提高转换准确度。


典型的应用:



单端工作模式


SER/DFR 置为高电平时, XPT2046 工作在为单端模式,单端工作模式的应用原理如下图所示。单端模式简单,在采样过程完成后,转换过程中可以关闭驱动开关,降低功耗。但这种模式的缺点是精度直接受参考电压源的精度限制,同时由于内部驱动开关的导通电阻存在,导通电阻与触摸屏电阻的分压作用,也会带来测量误差。


(图片里的 A2 A1 A0 ,还有上面说的 SER/DFR 就是 XPT2046 的配置命令,具体使用方法在后面会讲到)



差分工作模式


SER/DFR 置为低电平时, XPT2046 为差分工作模式.差分模式的优点是: +REF 和-REF 的输入分别直接接到 YP、 YN 上,可消除由于驱动开关的导通电阻引入的坐标测量误差。缺点是:无论是采样还是转换过程中,驱动开关都需要接通,相对单端模式而言,功耗增加了。如果不考虑功耗的话,当前就选择差分工作模式了。


(图片里的 A2 A1 A0 ,还有上面说的 SER/DFR 就是 XPT2046 的配置命令,具体使用方法在后面会讲到)


2.3 XPT2046 采集并转换一次数据的时序介绍

XPT2046 数据接口是串行接口,处理器和转换器之间的通信需要 8 个时钟周期,可采用 SPI、 SSI 和 Microwire 等同步串行接口。一次完整的转换需要 24 个串行同步时钟(DCLK)来完成。


前 8 个时钟用来通过 DIN 引脚输入控制字节。当转换器获取有关下一次转换的足够信息后,接着根据获得的信息设置输入多路选择器和参考源输入,并进入采样模式,如果需要,将启动触摸面板驱动器。 3 个多时钟周期后,控制字节设置完成,转换器进入转换状态。这时,输入采样-保持器进入保持状态,触摸面板驱动器停止工作(单端工作模式)。


接着的 12 个时钟周期将完成真正的模数转换。如果是度量比率转换方式(SER/DFR ——=0),驱动器在转换过程中将一直工作,第 13 个时钟将输出转换结果的最后一位。剩下的 3 个多时钟周期将用来完成被转换器忽略的最后字节(DOUT 置低)。


时序图如下:



时序图里的控制命令字节:



控制字节每个位的含义如下:



注意: 差分模式仅用于 X 坐标、 Y 坐标和触摸压力的测量,其它测量要求采用单端模式。


根据上面表格的介绍,可以得到在差分模式下,选择 12 位分辨率,测量 X 和 Y 坐标的两个命令:0xD0 和 0x90


XPT2046 还有其他模式,可以测量温度,笔中断的开关(默认是开着的),16 时钟周期转换,15 时钟周期转换,这些就不再介绍。 根据前面的介绍用在触摸屏上测量 XY 坐标的功能已经满足了。

2.4 SPI 时序介绍

这里的 XPT2046 支持标准 3 线 SPI 接口,关于 SPI 时序的介绍,在前面文章里有介绍过。

2.5 物理坐标与屏幕坐标的转换

正常在 LCD 屏上使用触摸屏,肯定是需要将采集的原始 X、Y 值转为 LCD 屏的屏幕坐标才好使用。


转换的方法有很多,这里采用最简单的角系数计算方法转换。


比如,我使用的 LCD 屏是 3.5 寸的,分辨率是 320*480。


1. 得到触摸屏左上角和右下角的坐标 XY 极限值 x=3831,y=3934x=155,y=168


2. 转换坐标值 x 坐标:3831~155 --> 3676~0y 坐标:3934~168 --> 3766~0


3. 计算斜率 x 坐标的斜率: 3676/320=11.4875y 坐标的斜率: 3766/480=7.84583


4. 得到实际的像素坐标 x 坐标: 320-(实时采集的当前 X 模拟量-155)/11.4875y 坐标: 480-(实时采集的当前 Y 模拟量-168)/7.84583


这里相减的原因: 因为我测试用的触摸屏采集出来的 X、Y 值大小和 LCD 屏的屏幕坐标值大小是反过来的。

三、示例代码

采用 SPI 模拟时序驱动,其他平台都可以移植。

3.1 xpt2046.c

#include "xpt2046_touch.h"struct XPT2046_TOUCH xpt2046_touch;
/*函数功能: 初始化硬件连接:T_MOSI--PF9T_MISO--PB2T_SCK---PB1T_PEN---PF10T_CS----PF11*/void XPT2046_TouchInit(void){ /*1. 时钟初始化*/ RCC->APB2ENR|=1<<3; //PB RCC->APB2ENR|=1<<7; //PF /*2. 初始化GPIO口*/ GPIOB->CRL&=0xFFFFF00F; GPIOB->CRL|=0x00000830; GPIOF->CRH&=0xFFFF000F; GPIOF->CRH|=0x00003830; /*3. 上拉*/ GPIOB->ODR|=0x3<<1; GPIOF->ODR|=0x7<<9;}

/*函数功能: SPI底层写一个字节*/void XPT2046_SPI_WriteOneByte(u8 cmd){ u8 i; for(i=0;i<8;i++) { XPT2046_SCK=0; //低电平写 if(cmd&0x80)XPT2046_MOSI=1; else XPT2046_MOSI=0; cmd<<=1; XPT2046_SCK=1; //高电平读,保证数据线稳定 }}

/*函数功能: 读2个字节说明: 读取16位数据,最低4位数据无效,有效数据是高12位
*/u16 XPT2046_ReadData(u8 cmd){ u16 data; u8 i; XPT2046_CS=0; //选中XPT2046 XPT2046_MOSI=0; XPT2046_SCK=0; XPT2046_SPI_WriteOneByte(cmd); DelayUs(8); //0.008ms ,等待XPT2046转换完成。 //消除忙信号 XPT2046_SCK=0; DelayUs(1); XPT2046_SCK=1; //连续读取16位的数据 for(i=0;i<16;i++) { XPT2046_SCK=0; //通知XPT2046,主机需要数据 XPT2046_SCK=1; data<<=1; if(XPT2046_MISO)data|=0x01; } data>>=4; //丢弃最低4位 XPT2046_CS=1; //取消选中 return data;}
/*XPT2046的命令:
10010000 :测试Y的坐标 0x9011010000 :测试X的坐标 0xD0
返回值: 0表示没有读取到坐标,1表示读取到当前坐标
//1. 得到左上角和右下角的坐标XY极限值 x=3831,y=3934 x=155,y=168
//2. 转换坐标值 x坐标:3831~155 --> 3676~0 y坐标:3934~168 --> 3766~0
//3. 计算斜率 x坐标的斜率: 3676/320=11.4875 y坐标的斜率: 3766/480=7.84583
//4. 得到实际的像素坐标 x坐标: 320-(模拟量-155)/11.4875 y坐标: 480-(模拟量-168)/7.84583*/u8 XPT2046_ReadXY(void){ if(XPT2046_PEN==0) //判断触摸屏是否按下 { /*1. 得到物理坐标*/ xpt2046_touch.x0=XPT2046_ReadData(0xD0); xpt2046_touch.y0=XPT2046_ReadData(0x90); /*2. 得到像素坐标*/ xpt2046_touch.x=320-(xpt2046_touch.x0-155)/11.4875; xpt2046_touch.y=480-(xpt2046_touch.y0-168)/7.84583; return 1; } return 0;}
复制代码

3.2 xpt2046.h

#ifndef XPT2046_TOUCH_H#define XPT2046_TOUCH_H#include "stm32f10x.h"#include "sys.h"#include "delay.h"
//触摸屏引脚定义#define XPT2046_MOSI PFout(9)#define XPT2046_MISO PBin(2)#define XPT2046_SCK PBout(1)#define XPT2046_CS PFout(11)#define XPT2046_PEN PFin(10)
//函数声明void XPT2046_TouchInit(void);void XPT2046_SPI_WriteOneByte(u8 cmd);u8 XPT2046_ReadXY(void);
//存放触摸屏信息的结构体struct XPT2046_TOUCH{ u16 x0; //物理坐标x u16 y0; //物理坐标y u16 x; //像素坐标x u16 y; //像素坐标y};extern struct XPT2046_TOUCH xpt2046_touch;#endif
复制代码


发布于: 刚刚阅读数: 3
用户头像

DS小龙哥

关注

之所以觉得累,是因为说的比做的多。 2022.01.06 加入

熟悉C/C++、51单片机、STM32、Linux应用开发、Linux驱动开发、音视频开发、QT开发. 目前已经完成的项目涉及音视频、物联网、智能家居、工业控制领域

评论

发布
暂无评论
STM32入门开发:编写XPT2046电阻触摸屏驱动(模拟SPI)_8月月更_DS小龙哥_InfoQ写作社区