国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【正點(diǎn)原子FPGA連載】 第二十章 LCD觸摸屏實(shí)驗(yàn)摘自【正點(diǎn)原子】DFZU2EG/4EV MPSoC 之FPGA開(kāi)發(fā)指南V1.0

這篇具有很好參考價(jià)值的文章主要介紹了【正點(diǎn)原子FPGA連載】 第二十章 LCD觸摸屏實(shí)驗(yàn)摘自【正點(diǎn)原子】DFZU2EG/4EV MPSoC 之FPGA開(kāi)發(fā)指南V1.0。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

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è)X
Y根電極。目前智能手機(jī)/平板電腦等的觸摸屏,都是采用交互電容技術(shù)。
正點(diǎn)原子所選擇的電容觸摸屏,采用的是投射式電容屏(交互電容類型),所以后面僅以投射式電容屏作為介紹。
透射式電容觸摸屏采用縱橫兩列電極組成感應(yīng)矩陣來(lái)感應(yīng)觸摸。以兩個(gè)交叉的電極矩陣(X軸電極和Y軸電極)來(lái)檢測(cè)每一格感應(yīng)單元的電容變化,如下圖所示:
【正點(diǎn)原子FPGA連載】 第二十章 LCD觸摸屏實(shí)驗(yàn)摘自【正點(diǎn)原子】DFZU2EG/4EV MPSoC 之FPGA開(kāi)發(fā)指南V1.0

圖 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寸800
480的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í)序圖如下圖所示:
【正點(diǎn)原子FPGA連載】 第二十章 LCD觸摸屏實(shí)驗(yàn)摘自【正點(diǎn)原子】DFZU2EG/4EV MPSoC 之FPGA開(kāi)發(fā)指南V1.0

圖 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所示。
【正點(diǎn)原子FPGA連載】 第二十章 LCD觸摸屏實(shí)驗(yàn)摘自【正點(diǎn)原子】DFZU2EG/4EV MPSoC 之FPGA開(kāi)發(fā)指南V1.0

圖 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)管腳分配
【正點(diǎn)原子FPGA連載】 第二十章 LCD觸摸屏實(shí)驗(yàn)摘自【正點(diǎn)原子】DFZU2EG/4EV MPSoC 之FPGA開(kāi)發(fā)指南V1.0

對(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ù)我們畫出了如下的程序框圖:
【正點(diǎn)原子FPGA連載】 第二十章 LCD觸摸屏實(shí)驗(yàn)摘自【正點(diǎn)原子】DFZU2EG/4EV MPSoC 之FPGA開(kāi)發(fā)指南V1.0

圖 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視圖如下圖所示:
【正點(diǎn)原子FPGA連載】 第二十章 LCD觸摸屏實(shí)驗(yàn)摘自【正點(diǎn)原子】DFZU2EG/4EV MPSoC 之FPGA開(kāi)發(fā)指南V1.0

圖 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)連接如下圖所示:
【正點(diǎn)原子FPGA連載】 第二十章 LCD觸摸屏實(shí)驗(yàn)摘自【正點(diǎn)原子】DFZU2EG/4EV MPSoC 之FPGA開(kāi)發(fā)指南V1.0

圖 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)試抓取的波形圖如下:
【正點(diǎn)原子FPGA連載】 第二十章 LCD觸摸屏實(shí)驗(yàn)摘自【正點(diǎn)原子】DFZU2EG/4EV MPSoC 之FPGA開(kāi)發(fā)指南V1.0

圖 20.4.4在線調(diào)試波形圖
【正點(diǎn)原子FPGA連載】 第二十章 LCD觸摸屏實(shí)驗(yàn)摘自【正點(diǎn)原子】DFZU2EG/4EV MPSoC 之FPGA開(kāi)發(fā)指南V1.0

圖 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)圖如下:
【正點(diǎn)原子FPGA連載】 第二十章 LCD觸摸屏實(shí)驗(yàn)摘自【正點(diǎn)原子】DFZU2EG/4EV MPSoC 之FPGA開(kāi)發(fā)指南V1.0

圖 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ù)地址
程序中第5463行代碼,定義了觸摸芯片為FT系列的參數(shù),包括器件地址、字地址位數(shù)和寄存器;第6670行代碼定義了觸摸芯片為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ù)等于172  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)行處理
程序中第7278行代碼定義了狀態(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.3480*272、4.3800*480、10.11280*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方向的定義如下:
【正點(diǎn)原子FPGA連載】 第二十章 LCD觸摸屏實(shí)驗(yàn)摘自【正點(diǎn)原子】DFZU2EG/4EV MPSoC 之FPGA開(kāi)發(fā)指南V1.0

圖 20.4.7GT系列對(duì)X和Y方向的定義

【正點(diǎn)原子FPGA連載】 第二十章 LCD觸摸屏實(shí)驗(yàn)摘自【正點(diǎn)原子】DFZU2EG/4EV MPSoC 之FPGA開(kāi)發(fā)指南V1.0

圖 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_軟件)軟件生成的,生成步驟如下圖所示:
【正點(diǎn)原子FPGA連載】 第二十章 LCD觸摸屏實(shí)驗(yàn)摘自【正點(diǎn)原子】DFZU2EG/4EV MPSoC 之FPGA開(kāi)發(fā)指南V1.0

圖 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模塊):
【正點(diǎn)原子FPGA連載】 第二十章 LCD觸摸屏實(shí)驗(yàn)摘自【正點(diǎn)原子】DFZU2EG/4EV MPSoC 之FPGA開(kāi)發(fā)指南V1.0

圖 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é)果如下圖所示:
【正點(diǎn)原子FPGA連載】 第二十章 LCD觸摸屏實(shí)驗(yàn)摘自【正點(diǎn)原子】DFZU2EG/4EV MPSoC 之FPGA開(kāi)發(fā)指南V1.0

圖 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)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包