1)實(shí)驗(yàn)平臺(tái):正點(diǎn)原子MPSoC開(kāi)發(fā)板
2)平臺(tái)購(gòu)買地址:https://detail.tmall.com/item.htm?id=692450874670
3)全套實(shí)驗(yàn)源碼+手冊(cè)+視頻下載地址: http://www.openedv.com/thread-340252-1-1.html
第二十章 LCD觸摸屏實(shí)驗(yàn)
現(xiàn)在幾乎所有智能手機(jī),包括平板電腦都是采用電容屏作為觸摸屏,電容屏是利用人體感應(yīng)進(jìn)行觸點(diǎn)檢測(cè)控制,不需要直接接觸或只需要輕微接觸,通過(guò)檢測(cè)感應(yīng)電流來(lái)定位觸摸坐標(biāo)。在本章中,我們將向大家介紹 FPGA控制LCD 電容觸摸模塊,實(shí)現(xiàn)觸摸屏驅(qū)動(dòng),即用手指觸碰LCD屏幕時(shí),對(duì)應(yīng)觸摸點(diǎn)的坐標(biāo)會(huì)顯示在LCD屏幕上。
本章包括以下幾個(gè)部分:
2020.1簡(jiǎn)介
20.2實(shí)驗(yàn)任務(wù)
20.3硬件設(shè)計(jì)
20.4程序設(shè)計(jì)
20.5下載驗(yàn)證
20.1簡(jiǎn)介
目前最常用的觸摸屏有兩種:電阻式觸摸屏和電容式觸摸屏。下面,我們來(lái)分別介紹這兩種觸摸屏。
1)電阻式觸摸屏
在Iphone面世之前,幾乎清一色的都是使用電阻式觸摸屏,電阻式觸摸屏利用壓力感應(yīng)進(jìn)行觸點(diǎn)檢測(cè)控制,需要直接應(yīng)力接觸,通過(guò)檢測(cè)電阻來(lái)定位觸摸位置。
正點(diǎn)原子2.8/3.5寸LCD模塊自帶的觸摸屏都屬于電阻式觸摸屏,下面簡(jiǎn)單介紹下電阻式觸摸屏的原理。
電阻觸摸屏的主要部分是一塊與顯示器表面非常配合的電阻薄膜屏,這是一種多層的復(fù)合薄膜,它以一層玻璃或硬塑料平板作為基層,表面涂有一層透明氧化金屬(透明的導(dǎo)電電阻)導(dǎo)電層,上面再蓋有一層外表面硬化處理、光滑防擦的塑料層、它的內(nèi)表面也涂有一層涂層、在它們之間有許多細(xì)小的(小于1/1000英寸)的透明隔離點(diǎn)把兩層導(dǎo)電層隔開(kāi)絕緣。當(dāng)手指觸摸屏幕時(shí),兩層導(dǎo)電層在觸摸點(diǎn)位置就有了接觸,電阻發(fā)生變化,在X和Y兩個(gè)方向上產(chǎn)生信號(hào),然后送達(dá)觸摸屏控制器??刂破鱾蓽y(cè)到這一接觸并計(jì)算出(X,Y)的位置,再根據(jù)獲得的位置模擬鼠標(biāo)的方式運(yùn)作。這就是電阻技術(shù)觸摸屏的最基本的原理。
電阻觸摸屏的優(yōu)點(diǎn):精度高、價(jià)格便宜、抗干擾能力強(qiáng)、穩(wěn)定性好。
電阻觸摸屏的缺點(diǎn):容易被劃傷、透光性不太好、不支持多點(diǎn)觸摸。
從以上介紹可知,觸摸屏都需要一個(gè)AD轉(zhuǎn)換器,一般來(lái)說(shuō)是需要一個(gè)控制器的。正點(diǎn)原子LCD模塊選擇的是四線電阻式觸摸屏,這種觸摸屏的控制芯片有很多,包括:ADS7843、ADS7846、TSC2046、XPT2046和AK4182等。這幾款芯片的驅(qū)動(dòng)基本上是一樣的,也就是你只要寫出了ADS7843的驅(qū)動(dòng),這個(gè)驅(qū)動(dòng)對(duì)其他幾個(gè)芯片也是有效的,而且封裝也有一樣的,完全PIN TO PIN兼容。所以在替換起來(lái),很方便。
正點(diǎn)原子LCD模塊自帶的觸摸屏控制芯片為XPT2046。XPT2046是一款4導(dǎo)線制觸摸屏控制器,內(nèi)含12位分辨率125KHz轉(zhuǎn)換速率逐步逼近型A/D轉(zhuǎn)換器。XPT2046支持從1.5V到5.25V的低電壓I/O接口。XPT2046能通過(guò)執(zhí)行兩次A/D轉(zhuǎn)換查出被按的屏幕位置,除此之外,還可以測(cè)量加在觸摸屏上的壓力。內(nèi)部自帶2.5V參考電壓可以作為輔助輸入、溫度測(cè)量和電池監(jiān)測(cè)模式之用,電池監(jiān)測(cè)的電壓范圍可以從0V到6V。XPT2046片內(nèi)集成有一個(gè)溫度傳感器。在2.7V的典型工作狀態(tài)下,關(guān)閉參考電壓,功耗可小于0.75mW。XPT2046采用微小的封裝形式:TSSOP-16,QFN-16(0.75mm厚度)和VFBGA-48。工作溫度范圍為-40℃~+85℃。
該芯片完全是兼容ADS7843和ADS7846的,關(guān)于這個(gè)芯片的詳細(xì)使用,可以參考這兩個(gè)芯片的datasheet。
電阻式觸摸屏就介紹到這里。
2)電容式觸摸屏
現(xiàn)在幾乎所有智能手機(jī),包括平板電腦都是采用電容屏作為觸摸屏,電容屏是利用人體感應(yīng)進(jìn)行觸點(diǎn)檢測(cè)控制,不需要直接接觸或只需要輕微接觸,通過(guò)檢測(cè)感應(yīng)電流來(lái)定位觸摸坐標(biāo)。
正點(diǎn)原子4.3/7/10.1寸LCD模塊自帶的觸摸屏采用的是電容式觸摸屏,下面簡(jiǎn)單介紹下電容式觸摸屏的原理。
電容式觸摸屏主要分為兩種:
1、表面電容式電容觸摸屏。
表面電容式觸摸屏技術(shù)是利用ITO(銦錫氧化物,一種透明的導(dǎo)電材料)導(dǎo)電膜,通過(guò)電場(chǎng)感應(yīng)方式感測(cè)屏幕表面的觸摸行為進(jìn)行。但是表面電容式觸摸屏有一些局限性,它只能識(shí)別一個(gè)手指或者一次觸摸。
2、投射式電容觸摸屏
投射電容式觸摸屏是傳感器利用觸摸屏電極發(fā)射出靜電場(chǎng)線。一般用于投射電容傳感技術(shù)的電容類型有兩種:自我電容和交互電容。
自我電容又稱絕對(duì)電容,是最廣為采用的一種方法,自我電容通常是指掃描電極與地構(gòu)成的電容。在玻璃表面有用ITO制成的橫向與縱向的掃描電極,這些電極和地之間就構(gòu)成一個(gè)電容的兩極。當(dāng)用手或觸摸筆觸摸的時(shí)候就會(huì)并聯(lián)一個(gè)電容到電路中去,從而使在該條掃描線上的總體的電容量有所改變。在掃描的時(shí)候,控制IC依次掃描縱向和橫向電極,并根據(jù)掃描前后的電容變化來(lái)確定觸摸點(diǎn)坐標(biāo)位置。筆記本電腦觸摸輸入板就是采用的這種方式,筆記本電腦的輸入板采用XY的傳感電極陣列形成一個(gè)傳感格子,當(dāng)手指靠近觸摸輸入板時(shí),在手指和傳感電極之間產(chǎn)生一個(gè)小量電荷。采用特定的運(yùn)算法則處理來(lái)自行、列傳感器的信號(hào),以此確定手指的位置。
交互電容又叫做跨越電容,它是在玻璃表面的橫向和縱向的ITO電極的交叉處形成電容。交互電容的掃描方式就是掃描每個(gè)交叉處的電容變化,來(lái)判定觸摸點(diǎn)的位置。當(dāng)觸摸的時(shí)候就會(huì)影響到相鄰電極的耦合,從而改變交叉處的電容量,交互電容的掃面方法可以偵測(cè)到每個(gè)交叉點(diǎn)的電容值和觸摸后電容變化,因而它需要的掃描時(shí)間與自我電容的掃描方式相比要長(zhǎng)一些,需要掃描檢測(cè)XY根電極。目前智能手機(jī)/平板電腦等的觸摸屏,都是采用交互電容技術(shù)。
正點(diǎn)原子所選擇的電容觸摸屏,采用的是投射式電容屏(交互電容類型),所以后面僅以投射式電容屏作為介紹。
透射式電容觸摸屏采用縱橫兩列電極組成感應(yīng)矩陣來(lái)感應(yīng)觸摸。以兩個(gè)交叉的電極矩陣(X軸電極和Y軸電極)來(lái)檢測(cè)每一格感應(yīng)單元的電容變化,如下圖所示:
圖 20.1.1 投射式電容屏電極矩陣示意圖
示意圖中的電極,實(shí)際是透明的,這里是為了方便大家理解故填充了顏色。圖中,X、Y軸的透明電極電容屏的精度、分辨率與X、Y軸的通道數(shù)有關(guān),通道數(shù)越多,精度越高。以上就是電容觸摸屏的基本原理,接下來(lái)看看電容觸摸屏的優(yōu)缺點(diǎn):
電容觸摸屏的優(yōu)點(diǎn):手感好、無(wú)需校準(zhǔn)、支持多點(diǎn)觸摸、透光性好。
電容觸摸屏的缺點(diǎn):成本高、精度不高、抗干擾能力差。
這里特別提醒大家電容觸摸屏對(duì)工作環(huán)境的要求是比較高的,在潮濕、多塵、高低溫環(huán)境下面,都是不適合使用電容屏的。
電容觸摸屏通常需要一個(gè)驅(qū)動(dòng)IC來(lái)檢測(cè)電容觸摸,且一般是通過(guò)IIC接口輸出觸摸數(shù)據(jù)的。正點(diǎn)原子不同尺寸和分辨率的觸摸屏較多,每款屏幕都配有觸摸芯片,不同的觸摸屏,配備了相同或者不同的觸摸芯片,即使是相同的觸摸屏,也有可能配備的是不同的觸摸芯片,至于觸摸芯片的具體型號(hào),可以查看觸摸屏背面觸摸芯片上的絲印。對(duì)于7寸RGB LCD屏1204600的分辨率來(lái)說(shuō),使用過(guò)的觸摸芯片有CST340、FT5206和GT911,CST340和FT5206的驅(qū)動(dòng)是兼容的,而GT911和這兩款芯片驅(qū)動(dòng)不兼容,因此在程序設(shè)計(jì)的時(shí)候,需要先獲取觸摸芯片的ID或者版本號(hào),采用不同的時(shí)序來(lái)驅(qū)動(dòng)觸摸屏。需要注意的是,后續(xù)不排除繼續(xù)更換觸摸芯片,因?yàn)楸娝苤脑?,部分芯片可能?huì)缺貨或者價(jià)格高到非常離譜,因此可能會(huì)采用其它替換方案。不過(guò)大家不用擔(dān)心,在尋找替換方案時(shí),一般會(huì)采用驅(qū)動(dòng)能夠兼容的芯片,即使不兼容,我們也會(huì)及時(shí)更新觸摸屏的驅(qū)動(dòng)程序。
正點(diǎn)原子RGB LCD液晶屏使用的觸摸芯片整體上分為GT系列(如GT911、GT1151等)和FT系列(如FT5206、FT5426等),GT系列和FT系列的寄存器不兼容,但是不同GT系列芯片之間的寄存器是兼容的,同樣的,不同F(xiàn)T系列芯片之間的寄存器也是兼容的,因此我們只需要學(xué)習(xí)GT系列中的一款芯片和FT系列中的一款芯片即可。
4.3寸800480的RGB LCD屏使用的觸摸芯片為GT911(最新的屏幕可能會(huì)替換成其它觸摸芯片),這里以GT911為例,講解GT系列觸摸芯片的驅(qū)動(dòng)方法,而其它觸摸芯片的使用方法非常類似,詳情可以查看相關(guān)芯片的數(shù)據(jù)手冊(cè)。
下面我們簡(jiǎn)單介紹下GT911,該芯片是深圳匯頂科技研發(fā)的一顆電容觸摸屏驅(qū)動(dòng)IC,支持100Hz觸點(diǎn)掃描頻率,支持5點(diǎn)觸摸,支持18*10個(gè)檢測(cè)通道,適合小于4.5寸的電容觸摸屏使用。
GT911與FPGA連接是通過(guò)4根線:SDA、SCL、RST和INT。其中:SDA和SCL是IIC通信用的,RST是復(fù)位腳(低電平有效),INT是中斷輸出信號(hào)。
GT911采用標(biāo)準(zhǔn)的IIC通信,最大通信速率為400KHz。GT911的IIC器件地址,可以是0X14或者0X5D,當(dāng)復(fù)位結(jié)束后的5ms內(nèi),如果INT是高電平,則使用0X14作為地址,否則使用0X5D作為地址。本章我們使用7’h14作為器件地址(不含最低位,換算成讀寫命令則是讀:0X29,寫:0X28)。GT911上電設(shè)置器件地址的時(shí)序圖如下圖所示:
圖 20.1.2上電設(shè)置器件地址時(shí)序圖
接下來(lái),介紹一下GT911的幾個(gè)重要的寄存器。
1,控制命令寄存器(0X8040)
該寄存器可以寫入不同值,實(shí)現(xiàn)不同的控制,我們一般使用0和2這兩個(gè)值,寫入2,即可軟復(fù)位GT911;寫入0,即可正常讀取坐標(biāo)數(shù)據(jù)(并且會(huì)結(jié)束軟復(fù)位)。
2,配置寄存器組(0X8047~0X8100)
這里共186個(gè)寄存器,用于配置GT911的各個(gè)參數(shù),這些配置一般由廠家提供給我們(一個(gè)數(shù)組),所以我們只需要將廠家給我們的配置,寫入到這些寄存器里面,即可完成GT911的配置。由于GT911可以保存配置信息(可寫入內(nèi)部FLASH,從而不需要每次上電都更新配置),這里有幾點(diǎn)注意的地方提醒大家:1,0X8047寄存器用于指示配置文件版本號(hào),程序?qū)懭氲陌姹咎?hào),必須大于等于GT911本地保存的版本號(hào),才可以更新配置。2,0X80FF寄存器用于存儲(chǔ)校驗(yàn)和,使得0X8047~0X80FF之間所有數(shù)據(jù)之和為0。3,0X8100用于控制是否將配置保存在本地,寫0,則不保存配置,寫1則保存配置。
3,產(chǎn)品ID寄存器(0X8140~0X8143)
這里總共由 4 個(gè)寄存器組成,用于保存產(chǎn)品 ID,對(duì)于GT911,這4個(gè)寄存器讀出來(lái)就是:9,1,4,7四個(gè)字符(ASCII碼格式)。因此,我們可以通過(guò)這4個(gè)寄存器的值,來(lái)判斷驅(qū)動(dòng)IC的型號(hào),從而判斷是GT911還是FT5206,以便執(zhí)行不同的初始化。
4,狀態(tài)寄存器(0X814E)
該寄存器各個(gè)位描述如下表所示:
表 20.1.1 寄存器定義
寄存器 bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
0X814E buffer狀態(tài) large detect 接近有效 按鍵 有效觸點(diǎn)個(gè)數(shù)
這里,我們僅關(guān)心最高位和最低4位,最高位用于表示buffer狀態(tài),如果有數(shù)據(jù)(坐標(biāo)/按鍵),buffer就會(huì)是1,最低4位用于表示有效觸點(diǎn)的個(gè)數(shù),范圍是:0~5,0表示沒(méi)有觸摸,5表示有5點(diǎn)觸摸。最后,該寄存器在每次讀取后,如果bit7有效,則必須寫0,清除這個(gè)位,否則不會(huì)輸出下一次數(shù)據(jù)!!這個(gè)要特別注意!??!
5,坐標(biāo)數(shù)據(jù)寄存器(共20個(gè))
這里共分成5組(5個(gè)點(diǎn)),每組4個(gè)寄存器存儲(chǔ)數(shù)據(jù),以觸點(diǎn)1的坐標(biāo)數(shù)據(jù)寄存器組為例,如下表所示:
表 20.1.2 觸點(diǎn)1坐標(biāo)寄存器組描述
寄存器 bit7~0 寄存器 bit7~0
0X8150 觸點(diǎn)1X坐標(biāo)低8位 0X8151 觸點(diǎn)1 X坐標(biāo)高8位
0X8152 觸點(diǎn)1Y坐標(biāo)低8位 0X8153 觸點(diǎn)1 Y坐標(biāo)高8位
我們一般只用到觸點(diǎn)的X,Y坐標(biāo),所以只需要讀取0X81500X8153的數(shù)據(jù)組合,即可得到觸點(diǎn)坐標(biāo)。其他4組分別是:0X8158、0X8160、0X8168和0X8170等開(kāi)頭的16個(gè)寄存器組成,分別針對(duì)觸點(diǎn)24的坐標(biāo)。GT911支持寄存器地址自增,我們只需要發(fā)送寄存器組的首地址,然后連續(xù)讀取即可,GT911會(huì)自動(dòng)地址自增,從而提高讀取速度。
GT911相關(guān)寄存器的介紹就介紹到這里,更詳細(xì)的資料,請(qǐng)參考:GT911編程指南.pdf這個(gè)文檔。
GT911只需要經(jīng)過(guò)簡(jiǎn)單的初始化就可以正常使用了,初始化流程:硬復(fù)位→延時(shí)10ms→結(jié)束硬復(fù)位→設(shè)置IIC地址→延時(shí)50ms→更新配置(需要時(shí))。此時(shí)GT911即可正常使用了。
然后,我們不停的查詢0X814E寄存器,判斷是否有有效觸點(diǎn),如果有,則讀取坐標(biāo)數(shù)據(jù)寄存器,得到觸點(diǎn)坐標(biāo),特別注意,如果0X814E讀到的值最高位為1,就必須對(duì)該位寫0,否則無(wú)法讀到下一次坐標(biāo)數(shù)據(jù)。
FT系列的觸摸芯片,我們以FT5206為例進(jìn)行講解,F(xiàn)T5206、FT5426和CST340的觸摸代碼一樣,它們只是在讀取版本號(hào)的時(shí)候稍有差異,在讀坐標(biāo)數(shù)據(jù)和配置等操作上沒(méi)有區(qū)別,所以FT系列的觸摸芯片可以共用一個(gè)驅(qū)動(dòng)程序。
FT5206采用標(biāo)準(zhǔn)的IIC通信,最大通信速率為400KHz,該芯片的器件地址為0X70(寫)和0X71(讀),不含最低位(讀寫位)為7’h38。
FT5206的寄存器比較多,這里我們著重介紹比較重要的寄存器。
1,工作模式寄存器(0X00)
該寄存器用于設(shè)置FT5206的工作模式,該寄存器的描述如下:
表 20.1.3寄存器定義
寄存器 bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
0X00 0 MODE[2:0] 0 0 0 0
MODE[2:0]用于控制FT5206的工作模式,一般設(shè)置為:000,表示正常工作模式。
2,中斷狀態(tài)控制寄存器(0XA4)
該寄存器用于設(shè)置FT5206的中斷狀態(tài),該寄存器的描述如下:
表 20.1.4 寄存器定義
寄存器 bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
0XA4 0 0 0 0 0 0 0 M
該寄存器只有最低位有效,M=0:表示查詢模式;M=1:觸發(fā)模式,一般設(shè)置為查詢模式。
3,有效觸摸門限控制寄存器(0X80)
該寄存器用于設(shè)置FT5206的中斷狀態(tài),該寄存器的描述如下:
表 20.1.5 寄存器定義
寄存器 bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
0X80 T7 T6 T5 T4 T3 T2 T1 T0
該寄存器8位數(shù)據(jù)都有效,用于設(shè)置FT5206有效觸摸的門限值,計(jì)算方式為:
有效觸摸門限值=T[7:0]*4,T[7:0]的值越小,觸摸越靈敏,默認(rèn)狀態(tài)下該值為70。
4,激活周期控制寄存器(0X88)
該寄存器用于設(shè)置FT5206的激活周期,該寄存器的描述如下:
表 20.1.6 寄存器定義
寄存器 bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
0X88 0 0 0 0 P3 P2 P1 P0
該寄存器只有低4位有效,用于設(shè)置FT5206的激活周期,P[3:0]的設(shè)置范圍為3~14,默認(rèn)值為12。
5,庫(kù)版本寄存器(0XA1和0XA2)
庫(kù)版本寄存器由兩個(gè)寄存器組成:0XA1和0XA2,用于讀取FT5206的驅(qū)動(dòng)庫(kù)版本,0XA1用于讀取版本號(hào)的高字節(jié),0XA2用于讀取版本號(hào)的低字節(jié)。7寸屏FT5206的版本號(hào)為0X3003。
6,觸摸狀態(tài)寄存器(0X02)
該寄存器用于讀取FT5206的觸摸狀態(tài),該寄存器的描述如下:
表 20.1.7 寄存器定義
寄存器 bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
0X02 0 0 0 0 TD3 TD2 TD1 TD0
該寄存器只有低4位有效,TD3[3:0]的取值范圍是1~5,表示有多少個(gè)有效觸摸點(diǎn)。我們可以根據(jù)這個(gè)寄存器的值來(lái)判斷有效觸摸點(diǎn)的個(gè)數(shù),然后通過(guò)0X03/0X09/0X0F/0X15和0X1B等寄存器來(lái)讀取觸摸坐標(biāo)數(shù)據(jù)。
7,觸摸數(shù)據(jù)寄存器(0X03~0X1E)
這里總共包括20個(gè)寄存器,它們是0X030X06、0X090X0C、0X0F0X12、0X150X18和0X1B0X1E。每4個(gè)寄存器為1組,表示一個(gè)觸摸點(diǎn)的坐標(biāo)數(shù)據(jù),比如0X030X06,則表示觸摸點(diǎn)1的坐標(biāo)數(shù)據(jù),其它的以此類推。這里,我們僅介紹0X03~0X06寄存器,該寄存器的描述如下:
表 20.1.8 寄存器定義
寄存器 bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
0X03 Event FLAG 0 0 X[11:8]
0X04 X[7:0]
0X05 Touch ID 0 0 Y[11:8]
0X06 Y[7:0]
這里的Event FLAG用于表示觸摸狀態(tài),00:按下;01:松開(kāi);10:持續(xù)觸摸;11:保留。一般我們只需要判斷該狀態(tài)是否為10即可,即持續(xù)觸摸狀態(tài),就可以穩(wěn)定的讀取觸摸坐標(biāo)數(shù)據(jù)了。而Touch ID,一般用不到,最后就是X和Y的坐標(biāo)數(shù)據(jù),這些數(shù)據(jù)以12位的形式輸出。
其它的0X090X0C、0X0F0X12、0X150X18和0X1B0X1E寄存器,則分別用于讀取第2~5個(gè)觸摸點(diǎn)坐標(biāo)的數(shù)據(jù)。
FT5206的初始化流程非常簡(jiǎn)單,首先通過(guò)CT_RST引腳對(duì)FT5206進(jìn)行一次復(fù)位,然FT5206進(jìn)入正常工作模式。然后設(shè)置工作模式、中斷狀態(tài)、觸摸閾值和激活周期等參數(shù),就完成了對(duì)FT5206的初始化。
初始化完成便可以讀取觸摸坐標(biāo)數(shù)據(jù)了,先讀取0X02寄存器,判斷有多少個(gè)有效觸摸點(diǎn),然后讀取0X03~0X1E等寄存器,便可以獲得觸摸坐標(biāo)數(shù)據(jù)。
需要注意的是,F(xiàn)T5206的寄存器地址為1個(gè)字節(jié),即8位;而GT911的寄存器地址為2個(gè)字節(jié),即16位,因此在程序設(shè)計(jì)時(shí)需要特別留意。
20.2實(shí)驗(yàn)任務(wù)
本節(jié)的實(shí)驗(yàn)任務(wù)是使用DFZU2EG/4EV MPSoC開(kāi)發(fā)板驅(qū)動(dòng)LCD顯示屏,用手觸摸顯示屏,在屏幕上顯示觸摸點(diǎn)的坐標(biāo)。
20.3硬件設(shè)計(jì)
MPSoC板載的LCD接口原理圖如圖 20.3.1所示。
圖 20.3.1 LCD接口原理圖
上圖中的關(guān)于LCD顯示部分的引腳就不再介紹了,這里我們主要看下CT_RST、IIC2_SDA、IIC2_SCL、CT_INT四個(gè)引腳,這四個(gè)引腳分別連接到了GT911的RST、SDA、SCL和INT四根引腳,我們?cè)诖a中通過(guò)控制這四個(gè)引腳來(lái)初始化GT911芯片或者和GT911進(jìn)行數(shù)據(jù)交互。
本實(shí)驗(yàn)中,各端口信號(hào)的管腳分配(由于引腳比較多,這里只給出了GT911的控制引腳,詳細(xì)引腳請(qǐng)參考例程提供的XDC文件)如下表所示:
表 20.3.1 觸摸顯示實(shí)驗(yàn)管腳分配
對(duì)應(yīng)的約束語(yǔ)句(GT911的引腳約束語(yǔ)句)如下所示:
set_property -dict {PACKAGE_PIN G11 IOSTANDARD LVCMOS33} [get_ports touch_scl]
set_property -dict {PACKAGE_PIN H12 IOSTANDARD LVCMOS33} [get_ports touch_sda]
set_property -dict {PACKAGE_PIN F12 IOSTANDARD LVCMOS33} [get_ports touch_int]
set_property -dict {PACKAGE_PIN H11 IOSTANDARD LVCMOS33} [get_ports touch_rst_n]
20.4程序設(shè)計(jì)
根據(jù)實(shí)驗(yàn)任務(wù)我們畫出了如下的程序框圖:
圖 20.4.1 LCD觸摸實(shí)驗(yàn)程序框圖
由上圖可知,時(shí)鐘IP核模塊為其余模塊提供驅(qū)動(dòng)時(shí)鐘;由于LCD屏的觸摸接口是IIC接口,因此通過(guò)IIC驅(qū)動(dòng)模塊實(shí)現(xiàn)整個(gè)IIC通信協(xié)議的功能,而LCD觸摸驅(qū)動(dòng)模塊負(fù)責(zé)整個(gè)LCD屏觸摸ID的確定、初始化、以及獲取觸摸點(diǎn)坐標(biāo)等操作。最后,我們還需要將獲取到的觸摸點(diǎn)坐標(biāo)顯示在RGB LCD液晶屏上,這部分功能由RGB LCD字符顯示模塊來(lái)實(shí)現(xiàn)。
本次實(shí)驗(yàn)的RTL視圖如下圖所示:
圖 20.4.2 RTL視圖
由上圖可知,F(xiàn)PGA頂層模塊例化了以下三個(gè)模塊,分別是時(shí)鐘IP核模塊(pll)、觸摸頂層模塊(touch_top)和LCD字符顯示模塊(lcd_rgb_char)。各模塊功能如下:
頂層模塊(top_lcd_touch):頂層模塊主要完成各個(gè)模塊的例化,實(shí)現(xiàn)各模塊之間的數(shù)據(jù)交互。
時(shí)鐘IP核模塊(pll):時(shí)鐘IP核模塊通過(guò)調(diào)用開(kāi)發(fā)工具官方IP核實(shí)現(xiàn),輸出一個(gè)50Mhz的時(shí)鐘,輸入的時(shí)鐘經(jīng)時(shí)鐘IP核后,時(shí)鐘的抖動(dòng)和偏斜更小。
觸摸頂層模塊(touch_top):觸摸頂層模塊實(shí)現(xiàn)了整個(gè)RGB LCD屏的觸摸驅(qū)動(dòng),輸出觸摸點(diǎn)的坐標(biāo),該模塊例化了IIC驅(qū)動(dòng)模塊和LCD觸摸驅(qū)動(dòng)模塊。
RGB LCD字符顯示模塊(lcd_rgb_char):RGB LCD字符顯示模塊實(shí)現(xiàn)了將輸入的觸摸點(diǎn)坐標(biāo),顯示在RGB LCD液晶屏的功能。該模塊的代碼和程序設(shè)計(jì)思路和“RTC實(shí)時(shí)時(shí)鐘LCD顯示實(shí)驗(yàn)”非常類似,因此可以參考該實(shí)驗(yàn)。
其中頂層例化模塊(top_lcd_touch)模塊代碼如下:
1 module top_lcd_touch(
2 //時(shí)鐘和復(fù)位接口
3 input sys_clk_p , //系統(tǒng)差分輸入時(shí)鐘
4 input sys_clk_n , //系統(tǒng)差分輸入時(shí)鐘
5 input sys_rst_n, //按鍵復(fù)位
6 //TOUCH 接口
7 inout touch_sda, //TOUCH IIC數(shù)據(jù)
8 output touch_scl, //TOUCH IIC時(shí)鐘
9 inout touch_int, //TOUCH INT信號(hào)
10 output touch_rst_n,//TOUCH 復(fù)位信號(hào)
11 //RGB LCD接口
12 output lcd_de, //LCD 數(shù)據(jù)使能信號(hào)
13 output lcd_hs, //LCD 行同步信號(hào)
14 output lcd_vs, //LCD 場(chǎng)同步信號(hào)
15 output lcd_bl, //LCD 背光控制信號(hào)
16 output lcd_rst_n, //LCD 復(fù)位
17 output lcd_clk, //LCD 像素時(shí)鐘
18 inout [23:0] lcd_rgb //LCD RGB顏色數(shù)據(jù)
19 );
20
21 //wire define
22 wire clk_50m ;
23 wire locked ;
24 wire rst_n ;
25
26 wire touch_int_in ;
27 wire touch_int_dir;
28 wire touch_int_out;
29 wire touch_sda_in ;
30 wire touch_sda_out;
31 wire touch_sda_dir;
32
33 wire [31:0] data ;
34 wire [15:0] lcd_id ;
35 wire touch_valid ;
36 wire [15:0] tp_x_coord ;
37 wire [15:0] tp_y_coord ;
38
39 //*****************************************************
40 //** main code
41 //*****************************************************
42
43 assign rst_n = sys_rst_n & locked;
44 assign data = {tp_x_coord,tp_y_coord};
45 assign lcd_rst_n = 1'b1;
46 assign touch_sda = touch_sda_dir ? touch_sda_out : 1'bz;
47 assign touch_sda_in = touch_sda;
48 assign touch_int = touch_int_dir ? touch_int_out : 1'bz;
49 assign touch_int_in = touch_int;
50
51 //例化鎖相環(huán)
52 clk_wiz_0 u_clk_wiz_0
53 (
54 // Clock out ports
55 .clk_50m(clk_50m), // output clk_50m
56 // Status and control signals
57 .reset(~sys_rst_n), // input reset
58 .locked(locked), // output locked
59 // Clock in ports
60 .clk_in1_p(sys_clk_p), // input clk_in1_p
61 .clk_in1_n(sys_clk_n)); // input clk_in1_n
62
63 //觸摸驅(qū)動(dòng)頂層模塊
64 touch_top u_touch_top(
65 .clk (clk_50m),
66 .rst_n (rst_n),
67
68 .touch_rst_n (touch_rst_n ),
69 .touch_int_in (touch_int_in ),
70 .touch_int_dir (touch_int_dir),
71 .touch_int_out (touch_int_out),
72 .touch_scl (touch_scl ),
73 .touch_sda_in (touch_sda_in ),
74 .touch_sda_out (touch_sda_out),
75 .touch_sda_dir (touch_sda_dir),
76
77 .lcd_id (lcd_id ),
78 .touch_valid (touch_valid),
79 .tp_x_coord (tp_x_coord ),
80 .tp_y_coord (tp_y_coord )
81 );
82
83 //例化LCD顯示模塊
84 lcd_rgb_char u_lcd_rgb_char
85 (
86 .sys_clk (clk_50m),
87 .sys_rst_n (rst_n ),
88 .data (data ), //觸摸點(diǎn)坐標(biāo)
89 //RGB LCD接口
90 .lcd_id (lcd_id),
91 .lcd_hs (lcd_hs), //LCD 行同步信號(hào)
92 .lcd_vs (lcd_vs), //LCD 場(chǎng)同步信號(hào)
93 .lcd_de (lcd_de), //LCD 數(shù)據(jù)輸入使能
94 .lcd_rgb (lcd_rgb), //LCD RGB顏色數(shù)據(jù)
95 .lcd_bl (lcd_bl), //LCD 背光控制信號(hào)
96 .lcd_clk (lcd_clk) //LCD 采樣時(shí)鐘
97 );
98
99 endmodule
在代碼的第44行,將兩個(gè)16位的X方向坐標(biāo)和Y方向坐標(biāo),賦值給32位的data,data是RGB LCD字符顯示模塊的輸入端口,該模塊會(huì)將data的值顯示在RGB LCD液晶屏上(分兩行顯示,第一行顯示X方向的坐標(biāo),第二行顯示Y方向的坐標(biāo))。
第46行至49行是對(duì)雙向信號(hào)的處理,LCD觸摸端口的中斷引腳(touch_int)和IIC的SDA引腳(touch_sda)是雙向引腳,這里根據(jù)_dir方向控制信號(hào),來(lái)切換雙向引腳的方向,即賦值_out或者高阻態(tài)。
觸摸頂層模塊實(shí)現(xiàn)了整個(gè)RGB LCD屏的觸摸驅(qū)動(dòng),并輸出觸 摸點(diǎn)的坐標(biāo),其模塊端口及信號(hào)連接如下圖所示:
圖 20.4.3 觸摸頂層模塊RTL視圖
IIC驅(qū)動(dòng)模塊(i2c_dri_m):該模塊實(shí)現(xiàn)了IIC通信協(xié)議的功能。需要說(shuō)明的是,該模塊是在“EEPROM讀寫測(cè)試實(shí)驗(yàn)”中的IIC驅(qū)動(dòng)模塊(i2c_dri)的基礎(chǔ)上做了修改,增加了對(duì)IIC寄存器連續(xù)讀寫的功能,以提高IIC的讀寫效率,關(guān)于該模塊的詳細(xì)介紹以及IIC的時(shí)序可以參考“EEPROM讀寫測(cè)試實(shí)驗(yàn)” 。
LCD觸摸驅(qū)動(dòng)模塊(touch_dri):LCD觸摸驅(qū)動(dòng)模塊實(shí)現(xiàn)了觸摸屏ID的獲取、初始化、配置、獲取觸摸點(diǎn)坐標(biāo)等功能。
觸摸頂層模塊(touch_top)的代碼如下:
1 module touch_top(
2 input clk ,
3 input rst_n ,
4 //LCD觸摸相關(guān)信號(hào)
5 output touch_rst_n , //觸摸屏復(fù)位
6 input touch_int_in , //INT輸入信號(hào)
7 output touch_int_dir, //INT方向控制信號(hào)
8 output touch_int_out, //INT輸出信號(hào)
9 output touch_scl , //I2C的SCL時(shí)鐘信號(hào)
10 input touch_sda_in , //I2C的SDA輸入信號(hào)
11 output touch_sda_out, //I2C的SDA輸出信號(hào)
12 output touch_sda_dir, //I2C的SDA方向控制
13 //用戶端口
14 input [15:0] lcd_id , //LCD ID
15 output touch_valid , //觸摸標(biāo)志
16 output [15:0] tp_x_coord , //X方向觸摸點(diǎn)的坐標(biāo)
17 output [15:0] tp_y_coord //Y方向觸摸點(diǎn)的坐標(biāo)
18 );
19
20 //parameter define
21 parameter CLK_FREQ = 50_000_000 ; //i2c_dri模塊的驅(qū)動(dòng)時(shí)鐘頻率(CLK_FREQ)
22 parameter I2C_FREQ = 250_000 ; //I2C的SCL時(shí)鐘頻率
23 parameter REG_NUM_WID = 8 ; //一次讀寫寄存器的個(gè)數(shù)的位寬
24
25 //wire define
26 wire [6:0] slave_addr; //器件地址
27 wire i2c_exec ; //I2C觸發(fā)執(zhí)行信號(hào)
28 wire i2c_rh_wl ; //I2C讀寫控制信號(hào)
29 wire [15:0] i2c_addr ; //I2C器件內(nèi)地址
30 wire [7:0] i2c_data_w; //I2C要寫的數(shù)據(jù)
31 wire bit_ctrl ; //字地址位控制(0:8b,1:16b)
32 wire [REG_NUM_WID-1:0] reg_num ; //一次讀寫寄存器的個(gè)數(shù)
33 wire [7:0] i2c_data_r; //I2C讀出的數(shù)據(jù)
34 wire i2c_done ; //I2C操作完成
35 wire once_done ; //一次讀寫操作完成
36 wire i2c_ack ; //應(yīng)答標(biāo)志
37 wire dri_clk ; //I2C驅(qū)動(dòng)時(shí)鐘
38
39 //*****************************************************
40 //** main code
41 //*****************************************************
42
43 //I2C驅(qū)動(dòng)模塊
44 i2c_dri_m #(
45 .CLK_FREQ (CLK_FREQ), //i2c_dri模塊的驅(qū)動(dòng)時(shí)鐘頻率(CLK_FREQ)
46 .I2C_FREQ (I2C_FREQ), //I2C的SCL時(shí)鐘頻率
47 .WIDTH (REG_NUM_WID) //一次讀寫寄存器的個(gè)數(shù)的位寬
48 )
49 u_i2c_dri_m(
50 .clk (clk ), //i2c_dri模塊的驅(qū)動(dòng)時(shí)鐘(CLK_FREQ)
51 .rst_n (rst_n ), //復(fù)位信號(hào)
52
53 .slave_addr (slave_addr ), //器件地址
54 .i2c_exec (i2c_exec ), //I2C觸發(fā)執(zhí)行信號(hào)
55 .i2c_rh_wl (i2c_rh_wl ), //I2C讀寫控制信號(hào)
56 .i2c_addr (i2c_addr ), //I2C器件內(nèi)地址
57 .i2c_data_w (i2c_data_w ), //I2C要寫的數(shù)據(jù)
58 .bit_ctrl (bit_ctrl ), //字地址位控制(16b/8b)
59 .reg_num (reg_num ), //一次讀寫寄存器的個(gè)數(shù)
60 .i2c_data_r (i2c_data_r ), //I2C讀出的數(shù)據(jù)
61 .i2c_done (i2c_done ), //I2C操作完成
62 .once_done (once_done ), //一次讀寫操作完成
63 .scl (touch_scl ), //I2C的SCL時(shí)鐘信號(hào)
64 .sda_in (touch_sda_in ), //I2C的SDA輸入信號(hào)
65 .sda_out (touch_sda_out), //I2C的SDA輸出信號(hào)
66 .sda_dir (touch_sda_dir), //I2C的SDA方向控制
67 .ack (i2c_ack ), //應(yīng)答標(biāo)志
68
69 .dri_clk (dri_clk ) //驅(qū)動(dòng)I2C操作的驅(qū)動(dòng)時(shí)鐘
70 );
71
72 //觸摸驅(qū)動(dòng)模塊
73 touch_dri #(
74 .WIDTH (REG_NUM_WID) //一次讀寫寄存器的個(gè)數(shù)的位寬
75 )
76 u_touch_dri(
77 .clk (dri_clk ), //時(shí)鐘信號(hào)
78 .rst_n (rst_n ), //復(fù)位信號(hào)(低有效)
79
80 .slave_addr (slave_addr ), //i2c器件地址
81 .i2c_exec (i2c_exec ), //i2c觸發(fā)控制
82 .i2c_rh_wl (i2c_rh_wl ), //i2c讀寫控制
83 .i2c_addr (i2c_addr ), //i2c操作地址
84 .i2c_data_w (i2c_data_w ), //i2c寫入的數(shù)據(jù)
85 .bit_ctrl (bit_ctrl ), //位控制信號(hào)
86 .reg_num (reg_num ), //一次讀寫寄存器的個(gè)數(shù)
87
88 .i2c_data_r (i2c_data_r ), //i2c讀出的數(shù)據(jù)
89 .i2c_ack (i2c_ack ), //i2c應(yīng)答信號(hào)
90 .i2c_done (i2c_done ), //i2c操作結(jié)束標(biāo)志
91 .once_done (once_done ), //一次讀寫操作完成
92
93 .lcd_id (lcd_id ), //LCD ID
94 .touch_valid (touch_valid ), //觸摸標(biāo)志
95 .tp_x_coord (tp_x_coord ), //X方向觸摸點(diǎn)的坐標(biāo)
96 .tp_y_coord (tp_y_coord ), //Y方向觸摸點(diǎn)的坐標(biāo)
97 .touch_rst_n (touch_rst_n ), //觸摸屏復(fù)位
98 .touch_int_in (touch_int_in ), //INT輸入信號(hào)
99 .touch_int_dir (touch_int_dir ), //INT方向控制信號(hào)
100 .touch_int_out (touch_int_out ) //INT輸出信號(hào)
101 );
102
103 endmodule
在代碼的第21行定義了該模塊輸入系統(tǒng)時(shí)鐘的參數(shù),為50_000_000,表示50Mhz;第22行定義了I2C時(shí)鐘的頻率為250Khz,一般該時(shí)鐘頻率要小于400Khz;第23行定義了一次讀寫寄存器個(gè)數(shù)的位寬,該值為8。
IIC驅(qū)動(dòng)模塊和LCD觸摸驅(qū)動(dòng)模塊之間通過(guò)I2C的用戶接口進(jìn)行交互,需要注意的是,IIC驅(qū)動(dòng)模塊輸出的dri_clk作為L(zhǎng)CD觸摸驅(qū)動(dòng)模塊的輸入操作時(shí)鐘,以方便數(shù)據(jù)的交互,該時(shí)鐘的頻率為1Mhz。
IIC驅(qū)動(dòng)模塊的部分代碼如下:
23 module i2c_dri_m
24 #(
25 parameter CLK_FREQ = 26'd50_000_000, //i2c_dri模塊的驅(qū)動(dòng)時(shí)鐘頻率(CLK_FREQ)
26 parameter I2C_FREQ = 18'd250_000 , //I2C的SCL時(shí)鐘頻率
27 parameter WIDTH = 4'd8 //一次讀寫寄存器的個(gè)數(shù)的位寬
28 )(
29 input clk , //i2c_dri模塊的驅(qū)動(dòng)時(shí)鐘(CLK_FREQ)
30 input rst_n , //復(fù)位信號(hào)
31 //i2c interface
32 input [6:0] slave_addr , //器件地址
33 input i2c_exec , //I2C觸發(fā)執(zhí)行信號(hào)
34 input i2c_rh_wl , //I2C讀寫控制信號(hào)
35 input [15:0] i2c_addr , //I2C器件內(nèi)地址
36 input [7:0] i2c_data_w , //I2C要寫的數(shù)據(jù)
37 input bit_ctrl , //字地址位控制(0:8b,1:16b)
38 input [WIDTH-1:0] reg_num , //一次讀寫寄存器的個(gè)數(shù)
39 output reg [7:0] i2c_data_r , //I2C讀出的數(shù)據(jù)
40 output reg i2c_done , //I2C操作完成
41 output reg once_done , //一次讀寫操作完成
42 output reg scl , //I2C的SCL時(shí)鐘信號(hào)
43 input sda_in , //I2C的SDA輸入信號(hào)
44 output reg sda_out , //I2C的SDA輸出信號(hào)
45 output reg sda_dir , //I2C的SDA方向控制
46 output reg ack , //應(yīng)答標(biāo)志
47 //user interface
48 output reg dri_clk //驅(qū)動(dòng)I2C操作的驅(qū)動(dòng)時(shí)鐘
49 );
以上是IIC驅(qū)動(dòng)模塊的端口信號(hào),從貼出的代碼可以發(fā)現(xiàn),和“EEPROM讀寫測(cè)試實(shí)驗(yàn)”中的IIC驅(qū)動(dòng)模塊相比,端口中多了slave_addr(器件地址)、bit_ctrl(字地址位控制)、reg_num(一次讀寫寄存器的個(gè)數(shù))和once_done(I2C單次讀寫完成),并且將SDA雙向引腳改成了三個(gè)端口,分別是sda_in、sda_out和sda_dir端口。
在“EEPROM讀寫測(cè)試實(shí)驗(yàn)” IIC驅(qū)動(dòng)模塊中,器件地址和字地址位控制都是以參數(shù)的形式定義的,而本次實(shí)驗(yàn)改成了端口的形式,這是由于不同的觸摸芯片具有不同的器件地址和字節(jié)地址位,因此這兩個(gè)信號(hào)必須定義成端口的形式,而如果定義成參數(shù)的形式,無(wú)法做到程序運(yùn)行時(shí)實(shí)時(shí)修改。
除此之外,本模塊還支持連續(xù)讀寫的功能,reg_num表示單次讀寫的寄存器個(gè)數(shù),如果這個(gè)值等于1,則等價(jià)于單次讀寫,而當(dāng)這個(gè)值大于1時(shí),表示此時(shí)對(duì)I2C進(jìn)行連續(xù)讀寫,這可以大大提升IIC的讀寫效率。每當(dāng)讀寫一個(gè)字節(jié)完成時(shí),once_done信號(hào)會(huì)拉高一次,而i2c_done信號(hào)拉高則表示對(duì)I2C的讀寫操作完成。
至于SDA端口由一個(gè)雙向端口改成了三個(gè)單向的端口,則僅僅是因?yàn)闉榱思嫒莶煌拈_(kāi)發(fā)平臺(tái),后續(xù)可能會(huì)對(duì)代碼進(jìn)行自定義IP核,方便對(duì)代碼進(jìn)行封裝,因此進(jìn)行了端口的修改,對(duì)于本次實(shí)驗(yàn)來(lái)說(shuō),也可以繼續(xù)使用一個(gè)雙向的SDA端口。
83 assign clk_divide = (CLK_FREQ/I2C_FREQ) >> 2'd2;//模塊驅(qū)動(dòng)時(shí)鐘的分頻系數(shù)
84 assign reg_done = reg_cnt == reg_num ? 1'b1 : 1'b0;
省略部分代碼……
100 //寄存器個(gè)數(shù)計(jì)數(shù)
101 always @(posedge dri_clk or negedge rst_n) begin
102 if(!rst_n)
103 reg_cnt <= 'd0;
104 else if(once_done)
105 reg_cnt <= reg_cnt + 1'd1;
106 else if(i2c_done)
107 reg_cnt <= 'd0;
108 end
由以上代碼可知,once_done每拉高一次,reg_cnt累加一次,當(dāng)reg_cnt的值等于輸入的reg_num時(shí),表示當(dāng)前連續(xù)讀寫的寄存器達(dá)到預(yù)設(shè)值,此時(shí)可以開(kāi)始結(jié)束讀寫操作。
166 st_data_wr: begin //寫數(shù)據(jù)(8 bit)
167 if(st_done) begin
168 if(reg_done)
169 next_state = st_stop;
170 else
171 next_state = st_data_wr;
172 end
173 else
174 next_state = st_data_wr;
175 end
176 st_addr_rd: begin //寫地址以進(jìn)行讀數(shù)據(jù)
177 if(st_done) begin
178 if(!ack)
179 next_state = st_data_rd;
180 else
181 next_state = st_stop;
182 end
183 else
184 next_state = st_addr_rd;
185 end
186 st_data_rd: begin //讀取數(shù)據(jù)(8 bit)
187 if(st_done) begin
188 if(reg_done)
189 next_state = st_stop;
190 else
191 next_state = st_data_rd;
192 end
193 else
194 next_state = st_data_rd;
195 end
由程序的第168行和第188行代碼可知,只有在reg_done信號(hào)拉高,即讀寫寄存器的個(gè)數(shù)達(dá)到預(yù)設(shè)值,狀態(tài)機(jī)才會(huì)跳轉(zhuǎn)到結(jié)束狀態(tài)。
接下來(lái)以讀取起始寄存器地址3,連續(xù)讀4個(gè)寄存器為例,在線調(diào)試抓取的波形圖如下:
圖 20.4.4在線調(diào)試波形圖
圖 20.4.5在線調(diào)試波形圖
由圖 20.4.4可知,i2c_exec信號(hào)拉高,此時(shí)i2c_rh_wl信號(hào)為高電平,表示發(fā)起的一次讀操作。由圖 20.4.5可知,起始地址為3,reg_num等于4,因此該模塊通過(guò)i2c_data_r信號(hào)共輸出寄存器地址3~6對(duì)應(yīng)的4個(gè)數(shù)據(jù),once_done也拉高了4次,最后i2c_done信號(hào)拉高,表示單次I2C讀操作完成。至此,I2C驅(qū)動(dòng)模塊介紹完成。
在簡(jiǎn)介部分中向大家介紹過(guò),觸摸屏所使用的觸摸芯片主要分為兩類,GT系列和FT系列,這兩個(gè)系列的寄存器、寄存器地址位數(shù)和初始化過(guò)程等都不一樣,因此在操作之前,需要先確定當(dāng)前連接的觸摸屏所使用的觸摸芯片屬于哪一類,然后再對(duì)相關(guān)寄存器進(jìn)行配置(只有FT系列的觸摸芯片才需要配置)、檢查是否有手指按下以及獲取觸摸點(diǎn)坐標(biāo)。在程序設(shè)計(jì)時(shí),以上的每個(gè)步驟可以當(dāng)成一個(gè)狀態(tài),通過(guò)狀態(tài)機(jī)實(shí)現(xiàn)整個(gè)觸摸驅(qū)動(dòng)會(huì)非常的方便,因此我們通過(guò)一個(gè)三段式的狀態(tài)機(jī)實(shí)現(xiàn)LCD觸摸屏的驅(qū)動(dòng),狀態(tài)機(jī)的跳轉(zhuǎn)圖如下:
圖 20.4.6 LCD驅(qū)動(dòng)模塊狀態(tài)機(jī)跳轉(zhuǎn)圖
從上圖可以比較直觀的看到每個(gè)狀態(tài)實(shí)現(xiàn)的功能以及跳轉(zhuǎn)到下一個(gè)狀態(tài)的條件,下面一一對(duì)各個(gè)狀態(tài)進(jìn)行講解。
st_idle:初始狀態(tài)。在此狀態(tài)中,只是做了簡(jiǎn)單的延時(shí),就會(huì)跳轉(zhuǎn)到上電初始化狀態(tài);
st_init:上電初始化狀態(tài)。在此狀態(tài)中,會(huì)控制CT_RST(硬件復(fù)位)信號(hào)的高低變化,完成對(duì)觸摸芯片的硬件復(fù)位,對(duì)于GT系列來(lái)說(shuō),在這個(gè)過(guò)程中會(huì)配置觸摸芯片的器件地址。在初始化完成之后,會(huì)跳轉(zhuǎn)到獲取觸摸ID狀態(tài);
st_get_id:獲取觸摸ID狀態(tài)。在此狀態(tài)中,會(huì)根據(jù)LCD ID,以及獲取到的觸摸芯片的ID,來(lái)確定當(dāng)前觸摸屏連接的是GT系列還是FT系列。如果確定當(dāng)前的觸摸芯片是GT系列,那么接下來(lái)會(huì)跳轉(zhuǎn)到檢測(cè)觸摸狀態(tài);而如果觸摸芯片是FT系列,接下來(lái)會(huì)跳轉(zhuǎn)到配置寄存器狀態(tài);
st_cfg_reg:配置寄存器狀態(tài)。FT系列相比于GT系列,需要額外配置一些寄存器,如工作模式寄存器、中斷狀態(tài)控制寄存器、有效觸摸門限控制寄存器和激活周期控制寄存器。在此狀態(tài)中,會(huì)對(duì)這些寄存器進(jìn)行配置,配置完成后會(huì)跳轉(zhuǎn)到檢測(cè)觸摸狀態(tài);
st_check_touch:檢測(cè)觸摸狀態(tài)。在此狀態(tài)中,會(huì)讀取觸摸狀態(tài)寄存器,以檢測(cè)觸摸屏當(dāng)前有沒(méi)有手指按下,并清除該寄存器的值。如果檢測(cè)到有效觸摸,則跳轉(zhuǎn)到獲取觸摸點(diǎn)坐標(biāo)狀態(tài);
st_get_coord:獲取觸摸點(diǎn)坐標(biāo)狀態(tài)。在此狀態(tài)中,會(huì)讀取LCD屏的觸摸點(diǎn)坐標(biāo)。需要注意的是,本次實(shí)驗(yàn)的功能是將第一個(gè)觸摸點(diǎn)的坐標(biāo)顯示在RGB LCD液晶屏上,所以無(wú)論觸摸屏是否有多個(gè)觸摸點(diǎn),這里只讀取第一個(gè)觸摸點(diǎn)的坐標(biāo)。獲取到觸摸點(diǎn)坐標(biāo)之后,跳轉(zhuǎn)到坐標(biāo)處理狀態(tài);
st_coord_handle:坐標(biāo)處理狀態(tài)。在上一個(gè)狀態(tài)獲取到的觸摸點(diǎn)坐標(biāo),并不是真正的觸摸屏X和Y方向的坐標(biāo),還需要做額外的處理,這個(gè)處理在此狀態(tài)中完成。在對(duì)坐標(biāo)點(diǎn)處理完成后,跳轉(zhuǎn)到獲取觸摸點(diǎn)坐標(biāo)狀態(tài),重新來(lái)檢測(cè)觸摸屏是否有手指按下,在最后三個(gè)狀態(tài)中不停的循環(huán)。
LCD觸摸模塊的代碼如下:
23 module touch_dri #(parameter WIDTH = 4'd8) //一次讀寫寄存器的個(gè)數(shù)的位寬
24 (
25 input clk , //時(shí)鐘信號(hào)
26 input rst_n , //復(fù)位信號(hào)(低有效)
27 //I2C用戶端口
28 output reg [6:0] slave_addr , //i2c器件地址
29 output reg i2c_exec , //i2c觸發(fā)控制
30 output reg i2c_rh_wl , //i2c讀寫控制
31 output reg [15:0] i2c_addr , //i2c操作地址
32 output reg [7:0] i2c_data_w , //i2c寫入的數(shù)據(jù)
33 output reg bit_ctrl , //字地址位控制(0:8b,1:16b)
34 output reg [WIDTH-1:0] reg_num , //一次讀寫寄存器的個(gè)數(shù)
35
36 input [7:0] i2c_data_r , //i2c讀出的數(shù)據(jù)
37 input i2c_ack , //i2c應(yīng)答信號(hào)
38 input i2c_done , //i2c操作結(jié)束標(biāo)志
39 input once_done , //一次讀寫操作完成
40
41 //LCD相關(guān)端口
42 input [15:0] lcd_id , //LCD ID
43 output reg touch_valid , //觸摸標(biāo)志
44 output reg [15:0] tp_x_coord , //X方向觸摸點(diǎn)的坐標(biāo)
45 output reg [15:0] tp_y_coord , //Y方向觸摸點(diǎn)的坐標(biāo)
46 output reg touch_rst_n , //觸摸屏復(fù)位
47 input touch_int_in , //INT輸入信號(hào)
48 output reg touch_int_dir, //INT方向控制信號(hào)
49 output reg touch_int_out //INT輸出信號(hào)
50 );
在I2C用戶端口中,這些端口都是連接到I2C驅(qū)動(dòng)模塊,實(shí)現(xiàn)和I2C驅(qū)動(dòng)模塊的數(shù)據(jù)交互。在程序的第43至45行代碼,是本模塊比較關(guān)鍵的三個(gè)端口,分別表示觸摸有效標(biāo)志、X方向觸摸點(diǎn)坐標(biāo)和Y方向觸摸點(diǎn)坐標(biāo)。其中觸摸有效標(biāo)志為高時(shí),表示當(dāng)前觸摸屏有手指按下,否則表示松開(kāi)手指。
52 //parameter define
53 //FT系列
54 localparam FT_SLAVE_ADDR = 7'h38; //FT系列器件地址
55 localparam FT_BIT_CTRL = 1'b0; //FT系列位控制
56
57 localparam FT_ID_LIB_VERSION= 8'hA1; //版本
58 localparam FT_DEVIDE_MODE = 8'h00; //模式控制寄存器
59 localparam FT_ID_MODE = 8'hA4; //FT中斷模式控制寄存器
60 localparam FT_ID_THGROUP = 8'h80; //觸摸有效值設(shè)置寄存器
61 localparam FT_ID_PERIOD_ACT = 8'h88; //激活狀態(tài)周期設(shè)置寄存器
62 localparam FT_STATE_REG = 8'h02; //觸摸狀態(tài)寄存器
63 localparam FT_TP1_REG = 8'h03; //第一個(gè)觸摸點(diǎn)數(shù)據(jù)地址
64
65 //GT系列
66 localparam GT_SLAVE_ADDR = 7'h14; //GT系列器件地址
67 localparam GT_BIT_CTRL = 1'b1; //GT系列位控制
68
69 localparam GT_STATE_REG = 16'h814E; //觸摸狀態(tài)寄存器
70 localparam GT_TP1_REG = 16'h8150; //第一個(gè)觸摸點(diǎn)數(shù)據(jù)地址
程序中第54至63行代碼,定義了觸摸芯片為FT系列的參數(shù),包括器件地址、字地址位數(shù)和寄存器;第66至70行代碼定義了觸摸芯片為GT系列的參數(shù),包括器件地址、字地址位數(shù)和寄存器。這些寄存器在簡(jiǎn)介部分中已經(jīng)作了介紹,需要注意的是,F(xiàn)T系列的字地址位數(shù)是8位,所以FT_BIT_CTRL參數(shù)等于0;而GT系列的字地址位數(shù)是16位,所以GT_BIT_CTRL參數(shù)等于1。
72 localparam st_idle = 7'b000_0001;//空閑狀態(tài)
73 localparam st_init = 7'b000_0010;//上電初始化
74 localparam st_get_id = 7'b000_0100;//獲取觸摸芯片ID
75 localparam st_cfg_reg = 7'b000_1000;//配置寄存器
76 localparam st_check_touch = 7'b001_0000;//檢測(cè)觸摸狀態(tài)
77 localparam st_get_coord = 7'b010_0000;//獲取觸摸點(diǎn)坐標(biāo)
78 localparam st_coord_handle = 7'b100_0000;//針對(duì)不對(duì)尺寸的觸摸的坐標(biāo)數(shù)據(jù)進(jìn)行處理
程序中第72至78行代碼定義了狀態(tài)機(jī)相關(guān)參數(shù),共分為7個(gè)狀態(tài)。
80 //reg define
81 reg [6:0] cur_state ;
82 reg [6:0] next_state ;
83
84 reg cnt_1us_en ; //使能計(jì)時(shí)
85 reg [19:0] cnt_1us_cnt ; //計(jì)時(shí)計(jì)數(shù)器
86 reg [15:0] chip_version; //芯片版本號(hào)
87 reg ft_flag ; //FT系列芯片的標(biāo)志
88 reg [15:0] touch_s_reg ; //觸摸狀態(tài)寄存器
89 reg [15:0] coord_reg ; //觸摸點(diǎn)坐標(biāo)寄存器
90 reg [15:0] tp_x_coord_t; //X方向觸摸點(diǎn)臨時(shí)坐標(biāo)
91 reg [15:0] tp_y_coord_t; //Y方向觸摸點(diǎn)臨時(shí)坐標(biāo)
92 reg [3:0] flow_cnt ; //流程計(jì)數(shù)器
93 reg st_done ; //操作完成信號(hào)
94
95 //*****************************************************
96 //** main code
97 //*****************************************************
98
99 //計(jì)時(shí)控制
100 always @(posedge clk or negedge rst_n) begin
101 if(!rst_n) begin
102 cnt_1us_cnt <= 20'd0;
103 end
104 else if(cnt_1us_en)
105 cnt_1us_cnt <= cnt_1us_cnt + 1'b1;
106 else
107 cnt_1us_cnt <= 20'd0;
108 end
程序中第100行至108行代碼的always語(yǔ)句,實(shí)現(xiàn)了計(jì)時(shí)的功能,由于本模塊輸入的時(shí)鐘clk為1Mhz,周期為1us,因此cnt_1us_cnt的值實(shí)際上表示了計(jì)時(shí)多少us。當(dāng)cnt_1us_en拉高時(shí),表示此時(shí)使能計(jì)時(shí)的功能;否則結(jié)束計(jì)時(shí)。
110 //狀態(tài)跳轉(zhuǎn)
111 always @ (posedge clk or negedge rst_n) begin
112 if(!rst_n)
113 cur_state <= st_idle;
114 else
115 cur_state <= next_state;
116 end
117
118 //組合邏輯狀態(tài)判斷轉(zhuǎn)換條件
119 always @(*) begin
120 case(cur_state)
121 st_idle : begin
122 if(st_done)
123 next_state = st_init;
124 else
125 next_state = st_idle;
126 end
127 st_init : begin
128 if(st_done)
129 next_state = st_get_id;
130 else
131 next_state = st_init;
132 end
133 st_get_id : begin
134 if(st_done) begin
135 if(ft_flag) //僅FT系列需要配置寄存器
136 next_state = st_cfg_reg;
137 else
138 next_state = st_check_touch;
139 end
140 else
141 next_state = st_get_id;
142 end
143 st_cfg_reg : begin
144 if(st_done)
145 next_state = st_check_touch;
146 else
147 next_state = st_cfg_reg;
148 end
149 st_check_touch: begin
150 if(st_done)
151 next_state = st_get_coord;
152 else
153 next_state = st_check_touch;
154 end
155 st_get_coord : begin
156 if(st_done)
157 next_state = st_coord_handle;
158 else
159 next_state = st_get_coord;
160 end
161 st_coord_handle : begin
162 if(st_done)
163 next_state = st_check_touch;
164 else
165 next_state = st_coord_handle;
166 end
167 default: next_state = st_idle;
168 endcase
169 end
以上代碼的兩個(gè)always語(yǔ)句分別是三段式狀態(tài)機(jī)的第一段和第二段,尤其是關(guān)于第二段式狀態(tài)機(jī)的狀態(tài)跳轉(zhuǎn),可以結(jié)合著前面狀態(tài)機(jī)跳轉(zhuǎn)圖來(lái)理解代碼,會(huì)更加直觀和易懂。
171 always @ (posedge clk or negedge rst_n) begin
172 if(!rst_n) begin
173 cnt_1us_en <= 1'b0;
174 chip_version <= 1'b0;
175 ft_flag <= 1'b0;
176 touch_s_reg <= 1'b0;
177 coord_reg <= 1'b0;
178 tp_x_coord_t <= 1'b0;
179 tp_y_coord_t <= 1'b0;
180 flow_cnt <= 1'b0;
181 st_done <= 1'b0;
182 touch_int_dir<= 1'b0;
183 touch_int_out<= 1'b0;
184
185 slave_addr <= 1'b0;
186 i2c_exec <= 1'b0;
187 i2c_rh_wl <= 1'b0;
188 i2c_addr <= 1'b0;
189 i2c_data_w <= 1'b0;
190 bit_ctrl <= 1'b0;
191 reg_num <= 1'b0;
192
193 touch_valid <= 1'b0;
194 tp_x_coord <= 1'b0;
195 tp_y_coord <= 1'b0;
196 touch_rst_n <= 1'b0;
197 end
198 else begin
199 i2c_exec <= 1'b0;
200 st_done <= 1'b0;
201 case(next_state)
202 st_idle : begin
203 cnt_1us_en <= 1'b1;
204 touch_int_dir <= 1'b1; //TOUCH INT端口方向設(shè)置為輸出
205 touch_int_out <= 1'b1; //TOUCH INT端口輸出高電平
206 if(cnt_1us_cnt >= 10) begin
207 st_done <= 1'b1;
208 cnt_1us_en <= 1'b0;
209 end
210 end
空閑狀態(tài)比較簡(jiǎn)單,首先將雙向INT引腳設(shè)置為輸出,并輸出高電平。對(duì)于GT系列來(lái)說(shuō),INT引腳會(huì)影響到器件地址的選擇,在后續(xù)正常工作的時(shí)候,INT才會(huì)作為輸入的引腳,不過(guò)INT引腳作為輸入時(shí),一般作為MCU處理器的中斷引腳,本次實(shí)驗(yàn)沒(méi)有使用到。在空閑狀態(tài)延時(shí)了10us之后,進(jìn)入到下一個(gè)狀態(tài)。
211 st_init : begin
212 cnt_1us_en <= 1'b1;
213 if(cnt_1us_cnt < 10_000) //延時(shí)10ms
214 touch_rst_n <= 1'b0; //開(kāi)始復(fù)位
215 else if(cnt_1us_cnt == 10_000)
216 touch_rst_n <= 1'b1; //結(jié)束復(fù)位
217 else if(cnt_1us_cnt == 60_000) begin //再次延時(shí)50ms(60_000-10_000)
218 touch_int_dir <= 1'b0; //將INT引腳設(shè)置為輸入
219 cnt_1us_en <= 1'b0;
220 st_done <= 1'b1;
221 flow_cnt <= 'd0;
222 end
223 end
在上電初始化狀態(tài)實(shí)現(xiàn)對(duì)觸摸芯片的硬件復(fù)位,和設(shè)置GT系列觸摸芯片的器件地址。首先延時(shí)10ms之后,拉低touch_rst_n信號(hào)進(jìn)行復(fù)位,再次延時(shí)50ms之后結(jié)束復(fù)位,此時(shí)將INT引腳設(shè)置為輸入。在硬件復(fù)位期間,INT為高電平,表示GT系列觸摸芯片的器件地址為7’h14。
224 st_get_id : begin
225 case(flow_cnt)
226 'd0 : begin
227 //這幾款屏幕是GT系列
228 if(lcd_id == 16'h4384 || lcd_id == 16'h4342 ||
229 lcd_id == 16'h1018) begin
230 flow_cnt <= 'd5;
231 ft_flag <= 1'b0; //ft_flag=0,說(shuō)明觸摸芯片為GT系列
232 end
233 else
234 flow_cnt <= flow_cnt + 1'b1;
235 end
236 'd1 : begin //讀FT系列版本號(hào)
237 i2c_exec <= 1'b1;
238 i2c_rh_wl <= 1'b1;
239 i2c_addr <= FT_ID_LIB_VERSION;
240 reg_num <= 'd2;
241 slave_addr <= FT_SLAVE_ADDR;
242 bit_ctrl <= FT_BIT_CTRL;
243 flow_cnt <= flow_cnt + 1'b1;
244 end
245 'd2 : begin
246 if(once_done) begin
247 chip_version[15:8] <= i2c_data_r;
248 flow_cnt <= flow_cnt + 1'b1;
249 end
250 else if(i2c_done && i2c_ack) begin //未應(yīng)答,說(shuō)明是GT系列
251 chip_version = "GT";
252 flow_cnt <= 'd4;
253 end
254 end
255 'd3 : begin
256 if(i2c_done) begin
257 chip_version[7:0] <= i2c_data_r;
258 flow_cnt <= flow_cnt + 1'b1;
259 end
260 end
261 'd4 : begin
262 flow_cnt <= flow_cnt + 1'b1;
263 //FT系列版本:0X3003/0X0001/0X0002/CST340
264 if(chip_version == 16'h3003 || chip_version == 16'h0001
265 || chip_version == 16'h0002 || chip_version == 16'h0000)
266 ft_flag <= 1'b1; //ft_flag=1,說(shuō)明觸摸芯片為FT系列
267 else
268 ft_flag <= 1'b0; //ft_flag=0,說(shuō)明觸摸芯片為GT系列
269 end
270 'd5 : begin
271 st_done <= 1'b1;
272 flow_cnt <= 'd0;
273 if(ft_flag) begin //將參數(shù)配置為FT系列
274 touch_s_reg <= FT_STATE_REG;
275 coord_reg <= FT_TP1_REG;
276 bit_ctrl <= FT_BIT_CTRL;
277 slave_addr <= FT_SLAVE_ADDR;
278 end
279 else begin //將參數(shù)配置為GT系列
280 touch_s_reg <= GT_STATE_REG;
281 coord_reg <= GT_TP1_REG;
282 bit_ctrl <= GT_BIT_CTRL;
283 slave_addr <= GT_SLAVE_ADDR;
284 end
285 end
286 default :;
287 endcase
288 end
以上代碼中的flow_cnt是一個(gè)流程控制計(jì)數(shù)器,方便在不同時(shí)刻下進(jìn)行順序操作。
在獲取觸摸ID狀態(tài)中,正點(diǎn)原子4.3寸480*272、4.3寸800*480、10.1寸1280*800分辨率的屏幕固定使用的是GT系列芯片,所以這里首先判斷LCD的ID是否為16’h4342、16’h4384和16’h1018,如果是的話,則確定使用的是GT系列觸摸芯片,當(dāng)然也可以通過(guò)讀取觸摸ID來(lái)判斷是否為GT系列觸摸芯片。
如果不是以上三種屏幕,則先假設(shè)當(dāng)前連接的是FT系列觸摸芯片,按照FT系列相關(guān)的參數(shù)來(lái)獲取ID,如果能夠獲取到正確的觸摸版本號(hào)或者ID,則確認(rèn)為FT系列觸摸芯片;否則則認(rèn)為是GT系列觸摸芯片,包括I2C未應(yīng)答、獲取到的版本號(hào)不正確等都認(rèn)為是GT系列芯片。
在flow_cnt等于5時(shí),通過(guò)ft_flag的值可以知道當(dāng)前連接的觸摸芯片是GT系列還是FT系列,然后給相關(guān)的變量進(jìn)行賦值,如器件地址(slave_addr)、字節(jié)地址位控制(bit_ctrl)等。
289 st_cfg_reg : begin
290 case(flow_cnt)
291 //配置FT系列
292 'd0 : begin
293 i2c_exec <= 1'b1;
294 i2c_rh_wl <= 1'b0;
295 i2c_addr <= FT_DEVIDE_MODE;
296 i2c_data_w <= 8'd0; //進(jìn)入正常模式
297 reg_num <= 'd1;
298 flow_cnt <= flow_cnt + 1'b1;
299 end
300 'd1 : begin
301 if(i2c_done) begin
302 if(i2c_ack == 1'b0) //I2C應(yīng)答
303 flow_cnt <= flow_cnt + 1'b1;
304 else //I2C未應(yīng)答
305 flow_cnt <= flow_cnt - 1'b1;
306 end
307 end
308 'd2 : begin
309 i2c_exec <= 1'b1;
310 i2c_rh_wl <= 1'b0;
311 i2c_addr <= FT_ID_MODE;
312 i2c_data_w <= 8'd0; //查詢模式
313 reg_num <= 'd1;
314 flow_cnt <= flow_cnt + 1'b1;
315 end
316 'd3 : begin
317 if(i2c_done) begin
318 if(i2c_ack == 1'b0) //I2C應(yīng)答
319 flow_cnt <= flow_cnt + 1'b1;
320 else //I2C未應(yīng)答
321 flow_cnt <= flow_cnt - 1'b1;
322 end
323 end
324 'd4 : begin
325 i2c_exec <= 1'b1;
326 i2c_rh_wl <= 1'b0;
327 i2c_addr <= FT_ID_THGROUP;
328 i2c_data_w <= 8'd22; //設(shè)置觸摸有效值,值越小,越靈敏
329 reg_num <= 'd1;
330 flow_cnt <= flow_cnt + 1'b1;
331 end
332 'd5 : begin
333 if(i2c_done) begin
334 if(i2c_ack == 1'b0) //I2C應(yīng)答
335 flow_cnt <= flow_cnt + 1'b1;
336 else //I2C未應(yīng)答
337 flow_cnt <= flow_cnt - 1'b1;
338 end
339 end
340 'd6 : begin
341 i2c_exec <= 1'b1;
342 i2c_rh_wl <= 1'b0;
343 i2c_addr <= FT_ID_PERIOD_ACT;
344 i2c_data_w <= 8'd12; //激活周期,12~14
345 reg_num <= 'd1;
346 flow_cnt <= flow_cnt + 1'b1;
347 end
348 'd7 : begin
349 if(i2c_done) begin
350 if(i2c_ack == 1'b0) begin//I2C應(yīng)答
351 flow_cnt <= 'd0;
352 st_done <= 1'b1;
353 end
354 else //I2C未應(yīng)答
355 flow_cnt <= flow_cnt - 1'b1;
356 end
357 end
358 default : ;
359 endcase
360 end
配置寄存器狀態(tài)主要配置FT系列觸摸芯片的寄存器,只需要按照簡(jiǎn)介部分介紹的,配置工作模式寄存器、中斷狀態(tài)控制寄存器、有效觸摸門限控制寄存器和激活周期控制寄存器即可。如果當(dāng)前寄存器沒(méi)有配置成功,即i2c_ack信號(hào)未應(yīng)答則重新配置該寄存器,直到配置完所需的寄存器。
361 st_check_touch : begin
362 case(flow_cnt)
363 'd0: begin //延時(shí)
364 cnt_1us_en <= 1'b1;
365 if(cnt_1us_cnt == 20_000) begin
366 flow_cnt <= flow_cnt + 1'b1;
367 cnt_1us_en <= 1'b0;
368 end
369 end
370 'd1 : begin
371 i2c_exec <= 1'b1;
372 i2c_rh_wl <= 1'b1;
373 i2c_addr <= touch_s_reg; //讀取觸摸點(diǎn)狀態(tài)
374 reg_num <= 'd1;
375 flow_cnt <= flow_cnt + 1'b1;
376 end
377 'd2 : begin
378 if(i2c_done) begin
379 if(i2c_ack == 1'b0)
380 flow_cnt <= flow_cnt + 1'b1;
381 else
382 flow_cnt <= flow_cnt - 1'b1;
383 end
384 end
385 'd3 : begin
386 flow_cnt <= flow_cnt + 1'b1;
387 if(ft_flag) begin
388 if(i2c_data_r[3:0] > 4'd0 && i2c_data_r[3:0] <= 4'd5)
389 touch_valid <= 1'b1; //檢測(cè)到觸摸
390 else
391 touch_valid <= 1'b0; //未檢測(cè)到觸摸
392 end
393 else begin
394 if(i2c_data_r[7]== 1'b1 && i2c_data_r[3:0] > 4'd0
395 && i2c_data_r[3:0] <= 4'd5) begin
396 touch_valid <= 1'b1; //檢測(cè)到觸摸
397 end
398 else
399 touch_valid <= 1'b0; //未檢測(cè)到觸摸
400 end
401 end
402 'd4 : begin
403 i2c_exec <= 1'b1;
404 i2c_rh_wl <= 1'b0;
405 i2c_addr <= touch_s_reg;
406 i2c_data_w <= 8'd0; //清除觸摸標(biāo)志
407 reg_num <= 'd1;
408 flow_cnt <= flow_cnt + 1'b1;
409 end
410 'd5 : begin
411 if(i2c_done) begin
412 if(i2c_ack == 1'b0) begin
413 st_done <= touch_valid;
414 flow_cnt <= 1'b0;
415 end
416 else
417 flow_cnt <= flow_cnt - 1'b1;
418 end
419 end
420 default : ;
421 endcase
422 end
以上代碼通過(guò)讀取查詢觸摸狀態(tài)寄存器,來(lái)判斷當(dāng)前有沒(méi)有手指按下。需要注意的是,一般觸摸點(diǎn)轉(zhuǎn)換時(shí)間需要7~20ms左右,這里固定延時(shí)20ms再去獲取觸摸點(diǎn)狀態(tài)。當(dāng)檢查到有效觸摸之后,需要向該寄存器寫0以清除觸摸。由于筆者在實(shí)際測(cè)試時(shí)發(fā)現(xiàn),在第一次讀取觸摸狀態(tài)時(shí),手指未接觸觸摸屏,偶爾也會(huì)讀到有效觸摸狀態(tài),因此這里無(wú)論有沒(méi)有檢測(cè)到觸摸狀態(tài),都會(huì)進(jìn)行寫0。
423 st_get_coord : begin
424 case(flow_cnt)
425 'd0 : begin
426 i2c_exec <= 1'b1;
427 i2c_rh_wl <= 1'b1;
428 i2c_addr <= coord_reg; //獲取X和Y方向坐標(biāo)點(diǎn)
429 reg_num <= 'd4; //連續(xù)讀四個(gè)寄存器
430 flow_cnt <= flow_cnt + 1'b1;
431 end
432 'd1 : begin
433 if(once_done) begin
434 if(i2c_ack == 1'b0) begin
435 tp_x_coord_t[7:0] <= i2c_data_r;
436 flow_cnt <= flow_cnt + 1'b1;
437 end
438 else
439 flow_cnt <= 1'b0;
440 end
441 end
442 'd2 : begin
443 if(once_done) begin
444 flow_cnt <= flow_cnt + 1'b1;
445 tp_x_coord_t[15:8] <= i2c_data_r;
446 end
447 end
448 'd3 : begin
449 if(once_done) begin
450 flow_cnt <= flow_cnt + 1'b1;
451 tp_y_coord_t[7:0] <= i2c_data_r;
452 end
453 end
454 'd4 : begin
455 if(once_done) begin
456 st_done <= 1'b1;
457 flow_cnt <= 'd0;
458 tp_y_coord_t[15:8] <= i2c_data_r;
459 end
460 end
461 default:;
462 endcase
463 end
讀取觸摸點(diǎn)狀態(tài)用于讀取第一個(gè)有效觸摸點(diǎn)的X和Y方向坐標(biāo),讀取完成后進(jìn)入下一個(gè)狀態(tài)。
464 st_coord_handle : begin
465 st_done <= 1'b1;
466 if(ft_flag) begin //FT系列需對(duì)數(shù)據(jù)做處理
467 tp_x_coord <= {4'd0,tp_y_coord_t[3:0],tp_y_coord_t[15:8]};
468 tp_y_coord <= {4'd0,tp_x_coord_t[3:0],tp_x_coord_t[15:8]};
469 end
470 else begin
471 tp_x_coord <= tp_x_coord_t;
472 tp_y_coord <= tp_y_coord_t;
473 end
474 end
475 default : ;
476 endcase
477 end
478 end
479
480 endmodule
這里值得一提的是,由于FT系列和GT系列輸出的坐標(biāo)順序不一致,這里我們?cè)賮?lái)回顧一下。
GT系列:
表 20.4.1 GT系列觸點(diǎn) 1 坐標(biāo)寄存器組描述
寄存器 bit7~0 寄存器 bit7~0
0X8150 觸點(diǎn)1 X坐標(biāo)低8位 0X8151 觸點(diǎn)1 X坐標(biāo)高8位
0X8152 觸點(diǎn)1 Y坐標(biāo)低8位 0X8153 觸點(diǎn)1 Y坐標(biāo)高8位
FT系列:
表 20.4.2 FT系列觸摸點(diǎn)1寄存器組描述
寄存器 bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
0X03 Event FLAG 0 0 X[11:8]
0X04 X[7:0]
0X05 Touch ID 0 0 Y[11:8]
0X06 Y[7:0]
由上面兩張表格對(duì)比可以發(fā)現(xiàn),GT系列先輸出的是X方向坐標(biāo)的低8位,而FT系列輸出的是X方向的高4位,因此在坐標(biāo)處理狀態(tài)中,需要對(duì)最終輸出的X和Y方向的坐標(biāo)點(diǎn)進(jìn)行處理。由于程序是按照先接收低8位,再接收高8位的順序,和GT系列寄存器定義的順序一致,因此只需要對(duì)FT系列的坐標(biāo)點(diǎn)做處理。
最后還需要注意的一點(diǎn)是,在對(duì)FT系列進(jìn)行坐標(biāo)處理時(shí),除了調(diào)換高低位之外,還講X和Y方向的坐標(biāo)進(jìn)行了調(diào)換,這是由于FT系列和GT系列對(duì)于X和Y方向的定義不同。GT系列是以橫屏方式定義X和Y方向,而FT系列是以豎屏方式定義X和Y方向,這兩者的差異通過(guò)兩幅圖片進(jìn)行展示(以800*480分辨率為例):
GT系列對(duì)X和Y方向的定義如下:
圖 20.4.7GT系列對(duì)X和Y方向的定義
圖 20.4.8FT系列對(duì)X和Y方向的定義
我們常規(guī)對(duì)LCD屏X和Y方向的定義是按照GT系列的方式,所以對(duì)于GT系列的坐標(biāo)不用做任何處理,而對(duì)FT系列的坐標(biāo)處理除高低位互換外,X和Y方向的坐標(biāo)也需要調(diào)換。
至此LCD觸摸驅(qū)動(dòng)介紹結(jié)束。
關(guān)于RGB LCD字符顯示模塊,實(shí)現(xiàn)的功能是將LCD觸摸驅(qū)動(dòng)模塊輸出的X和Y方向坐標(biāo)點(diǎn)顯示在RGB LCD液晶屏上,該模塊的代碼和程序設(shè)計(jì)思路和“RTC實(shí)時(shí)時(shí)鐘LCD顯示實(shí)驗(yàn)” 非常類似,因此可以參考該實(shí)驗(yàn)。只不過(guò)原來(lái)生成的字模寬度和高度是16x16,這里改成了32x32,并且字模數(shù)據(jù)除“0123456789”之外,還加了“XY”字模。
字模是使用“PCtoLCD2002”(軟件存放路徑:開(kāi)發(fā)板資料盤(A盤)\6_軟件資料\1_軟件)軟件生成的,生成步驟如下圖所示:
圖 20.4.9字模生成步驟
首先在資料盤A盤找到“PCtoLCD2002完美版”軟件并打開(kāi),然后按照上圖步驟操作。第一步點(diǎn)擊“選項(xiàng)”按鈕打開(kāi)字模屬性設(shè)置,然后按照上圖序號(hào)2、3、4、5、6、7、8步驟設(shè)置字模參數(shù)并點(diǎn)擊確定,之后在上圖序號(hào)9的位置輸入我們想要生成的字符(本節(jié)實(shí)驗(yàn)輸入0123456789XY),再到序號(hào)10的位置設(shè)置字符的寬度和高度(本節(jié)實(shí)驗(yàn)選擇3232,但是在實(shí)際顯示英文字符的時(shí)候?qū)挾葧?huì)減半也就是1632),最后點(diǎn)擊“生成字?!卑粹o,在上圖序號(hào)11的位置就生成了我們需要的字模數(shù)據(jù)組,拷貝到代碼中即可使用。
生成后的字模在程序中的展示如下(代碼位于lcd_display模塊):
圖 20.4.10字模代碼
lcd_display模塊部分代碼如下:
29 module lcd_display(
30 input lcd_pclk, //lcd驅(qū)動(dòng)時(shí)鐘
31 input sys_rst_n, //復(fù)位信號(hào)
32
33 input [31:0] data ,
34
35 input [10:0] pixel_xpos, //像素點(diǎn)橫坐標(biāo)
36 input [10:0] pixel_ypos, //像素點(diǎn)縱坐標(biāo)
37 output reg [15:0] pixel_data //像素點(diǎn)數(shù)據(jù),
38 );
39
40 //parameter define
41 localparam CHAR_POS_X = 11'd1; //字符區(qū)域起始點(diǎn)橫坐標(biāo)
42 localparam CHAR_POS_Y = 11'd1; //字符區(qū)域起始點(diǎn)縱坐標(biāo)
43 localparam CHAR_WIDTH = 11'd144; //字符區(qū)域?qū)挾?/span>
44 localparam CHAR_HEIGHT = 11'd32; //字符區(qū)域高度
45
46 localparam WHITE = 24'b11111_111111_11111; //背景色,白色
47 localparam BLACK = 24'b00000_000000_00000; //字符顏色,黑色
48
49 //reg define
50 reg [511:0] char [11:0] ; //字符數(shù)組
51
52 //wire define
53 wire [3:0] data0 ; // 十萬(wàn)位數(shù)
54 wire [3:0] data1 ; // 萬(wàn)位數(shù)
55 wire [3:0] data2 ; // 千位數(shù)
56 wire [3:0] data3 ; // 百位數(shù)
57 wire [3:0] data4 ; // 十位數(shù)
58 wire [3:0] data5 ; // 個(gè)位數(shù)
59 wire [3:0] data6 ;
60
61 //*****************************************************
62 //** main code
63 //*****************************************************
64 assign data6 = data[31:16] / 10'd1000 % 4'd10 ; // X軸坐標(biāo)千位數(shù)
65 assign data5 = data[31:16] / 7'd100 % 4'd10 ; // X軸坐標(biāo)百位數(shù)
66 assign data4 = data[31:16] / 4'd10 % 4'd10 ; // X軸坐標(biāo)十位數(shù)
67 assign data3 = data[31:16] % 4'd10 ; // X軸坐標(biāo)個(gè)位數(shù)
68 assign data2 = data[15:0] / 7'd100 % 4'd10 ; // Y軸坐標(biāo)百位數(shù)
69 assign data1 = data[15:0] / 4'd10 % 4'd10 ; // Y軸坐標(biāo)十位數(shù)
70 assign data0 = data[15:0] % 4'd10 ; // Y軸坐標(biāo)個(gè)位數(shù)
第33行代碼輸入的32位data數(shù)據(jù),就是由兩個(gè)16位X和Y方向坐標(biāo)拼接成的32位;而程序中第41行至44行代碼定義了X和Y坐標(biāo)在RGB LCD液晶屏上顯示的位置。第46行和第47行代碼定義了背景色和字符顏色,分別是白色和黑色。
我們將X方向和Y方向坐標(biāo)顯示在相應(yīng)的位置上,那么需要分別求出X方向坐標(biāo)的千位、百位、十位和個(gè)位,以及Y方向坐標(biāo)的百位、十位和個(gè)位。計(jì)算方式見(jiàn)程序第64行至70行代碼。
124 //給不同的區(qū)域賦值不同的像素?cái)?shù)據(jù)
125 always @(posedge lcd_pclk or negedge sys_rst_n) begin
126 if (!sys_rst_n) begin
127 pixel_data <= BLACK;
128 end
129 else if((pixel_xpos >= CHAR_POS_X) && (pixel_xpos < CHAR_POS_X + CHAR_WIDTH/9*1)
130 && (pixel_ypos >= CHAR_POS_Y) && (pixel_ypos < CHAR_POS_Y + CHAR_HEIGHT)) begin
131 if(char[data6][(CHAR_HEIGHT+CHAR_POS_Y-pixel_ypos)*16-((pixel_xpos-CHAR_POS_X)%16)-1])
132 pixel_data <= BLACK;
133 else
134 pixel_data <= WHITE;
135 end
省略部分代碼……
192 else begin
193 pixel_data <= WHITE; //繪制屏幕背景為白色
194 end
195 end
196 endmodule
以上代碼是根據(jù)輸入的pixel_xpos(像素點(diǎn)橫坐標(biāo))和pixel_ypos(像素點(diǎn)縱坐標(biāo)),來(lái)將當(dāng)前像素點(diǎn)賦值為背景色或者字符的顏色。
我們顯示的內(nèi)容首先分成兩行,第一行從左往右依次顯示X軸坐標(biāo)千位數(shù)、X軸坐標(biāo)百位數(shù)、X軸坐標(biāo)十位數(shù)、X軸坐標(biāo)個(gè)位數(shù)和字符“X”;第二行從左往右依次顯示Y軸坐標(biāo)百位數(shù)、Y軸坐標(biāo)十位數(shù)、Y軸坐標(biāo)個(gè)位數(shù)和字符“Y”。
代碼第50行定義了一個(gè)元素個(gè)數(shù)為12,每個(gè)元素的位寬為512位的數(shù)組(char),這12個(gè)元素分別對(duì)應(yīng)阿拉伯?dāng)?shù)字“0~9”、“X”和“Y”字模數(shù)據(jù),每一個(gè)字模(數(shù)字)所占的像素大小是長(zhǎng)32個(gè)像素,寬16個(gè)像素,共32*16=512位像素?cái)?shù)據(jù)。這里將一個(gè)數(shù)字的字模數(shù)據(jù)存放在了數(shù)組的一個(gè)元素中,因此數(shù)組元素的位寬是512位。
代碼第129到135行是一個(gè)具體的字符顯示的邏輯。首先判斷當(dāng)前像素坐標(biāo)的位置,如代碼第129到130行,如果處在字符顯示的區(qū)域則開(kāi)始根據(jù)字符數(shù)組值來(lái)顯示像素。顯示時(shí),數(shù)組參數(shù)pixel_xpos,pixel_ypos分別從小到大取不同的值時(shí),代入數(shù)組,此時(shí)我們實(shí)際上就是在從左到右,從上到下掃描一個(gè)字符像素平面,pixel_xpos變化對(duì)于行掃描,pixel_ypos則對(duì)于列掃描。
對(duì)于131行的代碼 “ (CHAR_HEIGHT+CHAR_POS_Y_1 - pixel_ypos)*16”,我們不難理解“*16”的由來(lái),因?yàn)樵诓檎覕?shù)組元素的時(shí)候,pixel_ypos的每次變化代表?yè)Q到下一行掃描,一行跨過(guò)16個(gè)數(shù)據(jù),所有乘以16。這里總結(jié)一下:字符數(shù)組一行的512個(gè)數(shù)據(jù)從高位到低位,每16位代表另一行,分別對(duì)應(yīng)點(diǎn)陣中該行從左向右的每一個(gè)像素點(diǎn)。
程序中第132行到134行是對(duì)數(shù)組的每個(gè)元素分別賦值,具體是數(shù)組元素為1的點(diǎn)賦值為黑色,否則為白色。
往下,每一個(gè)字符顯示邏輯的分析和上面類似,請(qǐng)大家自行分析。
20.5下載驗(yàn)證
首先將下載器與DFZU2EG/4EV MPSoC開(kāi)發(fā)板上的JTAG接口連接,下載器另外一端與電腦連接,然后將LCD屏連接到開(kāi)發(fā)板上,最后連接電源線后撥動(dòng)開(kāi)關(guān)按鍵給開(kāi)發(fā)板上電。
然后將本次實(shí)驗(yàn)生成的bit流文件下載到開(kāi)發(fā)板中,此時(shí)可以看到LCD屏幕點(diǎn)亮并顯示“0000X000Y”,我們用手觸摸LCD屏,觸摸點(diǎn)的數(shù)據(jù)就會(huì)顯示出來(lái)了。
實(shí)驗(yàn)結(jié)果如下圖所示:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-422314.html
圖 20.5.1 觸摸顯示文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-422314.html
到了這里,關(guān)于【正點(diǎn)原子FPGA連載】 第二十章 LCD觸摸屏實(shí)驗(yàn)摘自【正點(diǎn)原子】DFZU2EG/4EV MPSoC 之FPGA開(kāi)發(fā)指南V1.0的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!