觸摸屏又稱觸控面板,它是一種把觸摸位置轉(zhuǎn)化成坐標(biāo)數(shù)據(jù)的輸入設(shè)備觸摸屏可以分為電阻式觸摸屏和電容式觸摸屏。這里用電阻式觸摸屏來實(shí)現(xiàn)觸摸控制。
電阻式觸摸屏結(jié)構(gòu)如下圖所示,主要由表面硬涂層、兩個 ITO 層、間隔點(diǎn)以及玻璃底層構(gòu)成,這些結(jié)構(gòu)層都是透明的,整個觸摸屏覆蓋在液晶面板上,透過觸摸屏可看到液晶面板。表面涂層起到保護(hù)作用,玻璃底層起承載的作用,而兩個 ITO 層是觸摸屏的關(guān)鍵結(jié)構(gòu),它們是涂有銦錫金屬氧化物的導(dǎo)電層。兩個 ITO 層之間使用間隔點(diǎn)使兩層分開,當(dāng)觸摸屏表面受到壓力時,表面彎曲使得上層 ITO 與下層 ITO 接觸,在觸點(diǎn)處連通電路。
兩個 ITO 涂層的兩端分別引出 X-、X+、Y-、Y+四個電極,通過這些電極,外部電路向這兩個涂層可檢測電壓。
當(dāng)觸摸屏被按下時,兩個 ITO 層相互接觸,從觸點(diǎn)處把 ITO 層分為兩個電阻,且由于ITO 層均勻?qū)щ?,兩個電阻的大小與觸點(diǎn)離兩電極的距離成比例關(guān)系,利用這個特性,可通過以下過程來檢測坐標(biāo),這也正是電阻觸摸屏名稱的由來。
計算 X 坐標(biāo)時,在 X+電極施加驅(qū)動電壓 V ref ,X-極接地,所以 X+與 X-處形成了勻強(qiáng)電場,而觸點(diǎn)處的電壓通過 Y+電極采集得到,由于 ITO 層均勻?qū)щ?,觸點(diǎn)電壓與 V ref之比等于觸點(diǎn) X坐標(biāo)與屏寬度之比,從而:
x =Vy+/ V ref *Width
計算 Y 坐標(biāo)時,在 Y+電極施加驅(qū)動電壓 V ref ,Y-極接地,所以 Y+與 Y-處形成了勻強(qiáng)電場,而觸點(diǎn)處的電壓通過 X+電極采集得到,由于 ITO 層均勻?qū)щ?,觸點(diǎn)電壓與 V ref之比等于觸點(diǎn) Y坐標(biāo)與屏高度之比,從而:
y =Vy+/ V ref *Height
這里采用XPT2046芯片作為觸摸控制芯片,XPT2046芯片控制4線電阻觸摸屏,STM32與XPT2046采用SPI通訊獲取采集得到的電壓,然后轉(zhuǎn)換成坐標(biāo)。
XPT2046原理框
XPT2046 典型應(yīng)用圖
XPT2046 是一種典型的逐次逼近型模數(shù)轉(zhuǎn)換器(SAR ADC),包含了采樣/保持、模數(shù)轉(zhuǎn)換、串口數(shù)據(jù)輸出等功能。同時芯片集成有一個 2.5V的內(nèi)部參考電壓源、溫度檢測電路,工作時使用外部時鐘。XPT2046 可以單電源供電,電源電壓范圍為 2.7V~5.5V。參考電壓值直接決定ADC的輸入范圍,參考電壓可以使用內(nèi)部參考電壓,也可以從外部直接輸入1V~VCC范圍內(nèi)的參考電壓(要求外部參考電壓源輸出阻抗低)。X、Y、Z、VBAT、Temp和AUX模擬信號經(jīng)過片內(nèi)的控制寄存器選擇后進(jìn)入ADC,ADC可以配置為單端或差分模式。選擇VBAT 、Temp和AUX時可以配置為單端模式;作為觸摸屏應(yīng)用時,可以配置為差分模式,這可有效消除由于驅(qū)動開關(guān)的寄生電阻及外部的干擾帶來的測量誤差,提高轉(zhuǎn)換準(zhǔn)確度。
XPT2046 的內(nèi)部 2.5V 參考電壓源可通過控制位 PD1進(jìn)行關(guān)閉或者打開。一般地,內(nèi)部參考電壓只用于單端模式下 Vbatt、Temp 和 AUX 輸入測量。使用差分模式,觸摸屏可以獲得最佳性能。
外部參考電壓
+REF 和-REF之間的電壓差決定了模擬輸入的電壓范圍。XPT2046 的參考電壓輸入范圍為 1V~ VCC。參考電壓越低,則 ADC 輸出的二進(jìn)制數(shù)據(jù)結(jié)果每一個數(shù)字位所代表的模擬電壓也越低。
在 12 位工作方式下,數(shù)據(jù)結(jié)果的最低位所代表的模擬電壓為 VREF/4096,其余位依此類推。因此,參考電壓越低,干擾引入的誤差會越大,此時要求盡可能使用低噪聲、低波動的參考電壓源;在設(shè)計電路板時,盡可能減少干擾,輸入的信號噪音也不能太高,否則會直接影響轉(zhuǎn)換精度。
單端工作模式
SER/ DFR 置為高電平時,XPT2046 工作在為單端模式,單端工作模式的應(yīng)用原理如下圖所示。
單端模式簡單,在采樣過程完成后,轉(zhuǎn)換過程中可以關(guān)閉驅(qū)動開關(guān),降低功耗。但這種模式的缺點(diǎn)是精度直接受參考電壓源的精度限制,同時由于內(nèi)部驅(qū)動開關(guān)的導(dǎo)通電阻存在,導(dǎo)通電阻與觸摸屏電阻的分壓作用,也會帶來測量誤差。
差分工作模式
SER/ DFR 置為低電平時,XPT2046 為差分工作模式,如下圖所示。
差分模式的優(yōu)點(diǎn)是:+REF 和-REF 的輸入分別直接接到 YP、YN 上,可消除由于驅(qū)動開關(guān)的導(dǎo)通電阻引入的坐標(biāo)測量誤差。
缺點(diǎn)是:無論是采樣還是轉(zhuǎn)換過程中,驅(qū)動開關(guān)都需要接通,相對單端模式而言,功耗增加了。
XPT2046模擬輸入簡圖
差分模式輸入配置
表中說明了A2、A1、A0 和SER/DFR 控制位與XPT2046 的配置關(guān)系。這些控制位來自DIN腳的串行數(shù)據(jù)。
XPT2046是用來采集觸摸屏觸摸點(diǎn)的水平位置與垂直位置的。由表可知,測量Y位置時,需將A2A1A0設(shè)置為001,此時驅(qū)動的模擬輸入為YP和YN:測量X位置時,需將A2A1A0設(shè)置為101,此時驅(qū)動的模擬輸入為XP和XN。其他兩行用于測量觸模時作用于屏幕上的壓力,這里忽略。
控制字的控制位命令
控制字節(jié)各位描述
如果采用單端模式測量 X 坐標(biāo)、Y 坐標(biāo)和觸摸壓力,則需要添加一個外部參考電壓,并且 XPT2046 的電源也必須來自這個外部參考源。需要特別注意的一點(diǎn)是,當(dāng)使用單端模式時,輸入 ADC 的電壓不能超過內(nèi)部參考電壓,尤其是當(dāng)工作電壓大于 2.7V 的時候。
注意 :差分模式僅用于 X 坐標(biāo)、Y 坐標(biāo)和觸摸壓力的測量,其它測量要求采用單端模式。
XPT2046的數(shù)據(jù)接口是串行的,通過該接口可輕易地與單片機(jī)或處理器完成互連,處理器和轉(zhuǎn)換器之間的通信需要8個時鐘周期,通過這8個時鐘周期來確定XPT72046轉(zhuǎn)換的模擬通道及采用的轉(zhuǎn)換模式。一次完整的轉(zhuǎn)換需要24個串行同步時鐘來完成。
前8個時鐘用來通過DIN引腳輸入控制命令(字節(jié)),當(dāng)轉(zhuǎn)換器獲取有關(guān)下一次轉(zhuǎn)換的足夠信息后,接著根據(jù)獲得的信息設(shè)置輸入多路選擇器和參考源輸入,并進(jìn)入采樣模式,如果需要,將啟動觸摸面板驅(qū)動器,3個多時鐘周期后,控制字節(jié)設(shè)置完成,轉(zhuǎn)換器進(jìn)入轉(zhuǎn)換狀態(tài)。這時,輸入采樣保持器進(jìn)入保持狀態(tài),觸摸面板驅(qū)動器停止工作(單端工作模式)。接著的12個時鐘周期將完成真正的模數(shù)轉(zhuǎn)換。在差分模式時,驅(qū)動器在轉(zhuǎn)換過程中將一直工作,第13個時鐘將輸出轉(zhuǎn)換結(jié)果的最后一位。剩下的3個多時鐘周期將用來完成被轉(zhuǎn)換器忽略的最后字節(jié)(DOUT輸出0)。XPI2046 24周期的轉(zhuǎn)換時序如圖所示:
由圖可知??刂谱止?jié)由DIN送入XPT2046,其包括啟動轉(zhuǎn)換位、尋址位,ADC分辨率設(shè)置位,單端/差分設(shè)置位和掉電控制位,起始位是拉制字的首位,取值恒為1,在DIN引腳檢測到起始位前,所有的輸入都將被忽略。尋址位即A2A1A0,由表可知,當(dāng)A2A1A0為001時,XPT2046采集Y位置,當(dāng)A2A1A0為101時,XPT2046采集X位置。MODE位為模式選擇位,其用于設(shè)置ADC分辨率,當(dāng)MODE為0時,下一次轉(zhuǎn)換將是12位模式:當(dāng)MODE為1時,下一次轉(zhuǎn)換將是8位模式。SER/DFR位用于選擇參考源的模式,當(dāng) SER/DFR為1時,選擇單端模式;當(dāng) SER/DFR為0時,選擇差分模式,為提高AD轉(zhuǎn)換的精度并消除測量誤差,這里選擇12位轉(zhuǎn)換模式和差分模式。最后兩位用于掉電控制,這里將之配置為00,即在兩次AD轉(zhuǎn)換之間掉電,下次轉(zhuǎn)換一開始,芯片立即進(jìn)入完全上電狀態(tài),而無需額外延時,另外,此時 PENIRQ是一直使能的。
分析可得轉(zhuǎn)換X通道時所對應(yīng)的控制字為0xD0,轉(zhuǎn)換Y通道時所對應(yīng)的控制字為0x90。為方便使用,將這兩個控制字定義為宏:
#define X_CMD 0XD0
#define Y_CMD 0X90
接著開始編寫觸摸屏程序,原理圖如下:
引腳分別是T_MOSI:PF11、T_MISO:PB2 、T_CS:PC13、T_CLK:PB0、T_PEN:PB1。
為方便調(diào)用對引腳進(jìn)行的控制進(jìn)行宏定義,。
#define T_CS_H() do{GPIOC- >BSRRL = 1< 13;}while(0)
#define T_CS_L() do{GPIOC- >BSRRH = 1< 13;}while(0)
#define T_CLK_H() do{GPIOB- >BSRRL = 1< 0;}while(0)
#define T_CLK_L() do{GPIOB- >BSRRH = 1< 0;}while(0)
#define T_MOSI_H() do{GPIOF- >BSRRL = 1< 11;}while(0)
#define T_MOSI_L() do{GPIOF- >BSRRH = 1< 11;}while(0)
初始化引腳:
void Touch_gpio_Init()
{
//1.開時鐘
RCC- >AHB1ENR |= 1< 1 | 1< 2 | 1< 5;
//2. 模式、類型、速度、上下拉
//PB1/2:輸入
GPIOB- >MODER &= ~(0XF< 2);
GPIOB- >PUPDR &= ~(0XF< 2);
GPIOB- >PUPDR |= (0x1< 2);
//PB0:
GPIOB- >MODER &= ~(0X3< 0);
GPIOB- >MODER |= 1< 0;
GPIOB- >OTYPER &= ~(1< 0); //推挽
GPIOB- >OSPEEDR &= ~(0X3< 0);//2mHZ
GPIOB- >PUPDR &= ~(0X3< 0); //無上下拉
//PC13
GPIOC- >MODER &= ~(0X3< 26);
GPIOC- >MODER |= 1< 26;
GPIOC- >OTYPER &= ~(1< 13); //推挽
GPIOC- >OSPEEDR &= ~(0X3< 26);//2mHZ
GPIOC- >PUPDR &= ~(0X3< 26); //無上下拉
//PF11
GPIOF- >MODER &= ~(0X3< 22);
GPIOF- >MODER |= 1< 22;
GPIOF- >OTYPER &= ~(1< 11); //推挽
GPIOF- >OSPEEDR &= ~(0X3< 22);//2mHZ
GPIOF- >PUPDR &= ~(0X3< 22); //無上下拉
//3. 初始狀態(tài)
T_CS_H(); //片選信號低電平有效,初始時不片選
T_CLK_L();
}
初始化完成,根據(jù)時序編寫對X或Y通道完成一次轉(zhuǎn)換的函數(shù)實(shí)現(xiàn)
u16 Touch_GetADC(u8 cmd)
{
u8 i = 0;
u16 res = 0;
T_CLK_L();
T_CS_L();
Delay_us(1);
for(i=0;i< 8;i++)
{
if(cmd & 0x80)
T_MOSI_H(); //數(shù)據(jù)有效輸出高電平
else
T_MOSI_L(); //數(shù)據(jù)有效輸出低電平
Delay_us(1);
T_CLK_H();
Delay_us(1);
T_CLK_L();
Delay_us(1);
cmd < <= 1;
}
T_CLK_H(); //ADC需要一個周期
Delay_us(1);
res = 0;
for(i=0;i< 15;i++)
{
res < <= 1; //空出最低位,準(zhǔn)備接收
T_CLK_L();
Delay_us(1);
T_CLK_H();
Delay_us(1);
if(GPIOB- >IDR & (1< 2))
res |= 1;
Delay_us(1);
}
T_CLK_L();
Delay_us(1);
T_CS_H();
res > >= 3; //最低3位是補(bǔ)充的0,移掉不要
return res;
}
有了上面的函數(shù),只需依次送入X通道的控制字節(jié)和Y通道的控制字節(jié),即可在一次接觸后,獲取接觸點(diǎn)x、y方向的AD值。但針對AD轉(zhuǎn)換,為了提高轉(zhuǎn)換的準(zhǔn)確性,這里采用中值平均濾波算法進(jìn)行濾波。中值平均算法即將獲取的AD值通過冒泡法排序,然后掐頭去尾,取平均值并返回。具體如下:
u16 Touch_GetAvgADC(u8 cmd, u16 * buf,u8 size)
{
u8 i = 0,j=0;
u16 temp = 0;
float res = 0;
for(i=0;i< size;i++)
buf[i] = Touch_GetADC(cmd);
for(i=0;i< size-1;i++)
{
for(j=i+1;j< size;j++)
{
if(buf[i]
接著,就可以用這個函數(shù)得到一個點(diǎn)的坐標(biāo)。先把點(diǎn)的坐標(biāo)定義為結(jié)構(gòu)體:
typedef struct
{
u16 x;
u16 y;
}Point_Typedef;
通過筆中斷引腳判斷是否有觸摸動作,然后分別讀出X和Y的ADC值并返回出一個點(diǎn)的坐標(biāo)ADC。
Point_Typedef Touch_GetPointADC()
{
Point_Typedef ts = {0xffff,0xffff};
if((GPIOB- >IDR & (1< 1))==0) //有觸摸動作
{
ts.x = Touch_GetAvgADC(X_CMD, Point_buf[0],10);
ts.y = Touch_GetAvgADC(Y_CMD, Point_buf[1],10);
}
return ts;
}
現(xiàn)在已經(jīng)可以獲得點(diǎn)的坐標(biāo)ADC,開始進(jìn)行測試程序是否正確。
主函數(shù)
#include "stm32f4xx.h"
#include "usart.h"
#include "delay.h"
#include "stdio.h"
#include "touch.h"
int main()
{
Point_Typedef ts = {0xffff,0xffff};
Usart1_Init(115200);
Touch_gpio_Init();
while(1)
{
ts = Touch_GetPointADC();
printf("(%d,%d)rn",ts.x,ts.y);
Delay_ms(2000);
}
}
運(yùn)行程序,發(fā)現(xiàn)沒有觸摸時點(diǎn)的坐標(biāo)是獲取不到的,有觸摸動作時,點(diǎn)的ADC坐標(biāo)就是在12位ADC的范圍內(nèi),獲取點(diǎn)的坐標(biāo)ADC測試成功。
評論
查看更多