當今智能手機霸占天下的時代,不管是用于工作的軟件,還是生活類的軟件,大家都希望能在擺脫電腦的情況下,把它玩于掌上,在手機上來操作它。畢竟,不管是工作中還是生活中,不方便攜帶電腦的時候還是存在的,就比如當下比較火的一款教學軟件幾何畫板,它是專門為學生和老師創作教學課程而出臺的,專門繪制動態幾何圖形的教學工具。這么好用的一款工具,大家肯定更期待它的手機版吧,下面小編就來給大家聊聊關于幾何畫板手機版的那些事。
幾何畫板(Sketchpad)是一款非常好用的作圖工具,是由美國Key Curriculum Press公司制作并出版的優秀教育軟件,能幫助老師們解決黑板上的教學缺陷,也能幫助學生們學習數學知識,通過動態地演示可以達到舉一反三的效果。該軟件雖然看起來界面簡潔,其實不然,其中的功能非常強大,有著很多你想不到的功能。幾何畫板分為MAC版和Windows版,分別在Windows系統的電腦和蘋果電腦上使用,這么強大的軟件,目前好像還沒出幾何畫板手機版,但是最新版有著便于我們使用的簡體中文版,下載地址:http://www.jihehuaban.com.cn/xiazai.html。
幾何畫板功能:
幾何畫板最新版擁有動態的圖形功能,可以在圖形變動是保持設定不變的幾何關系;簡便的動畫功能,可以針對教學要求制作動畫對象,以表現幾何體的運動;有趣的變換功能,可以按指定的值或動態的值對圖形進行變換;方便的計算功能,能對對象進行度量和計算;獨特的自定義工具,可以把繪圖過程自動記錄下來;豐富的圖像功能,只要給出函數表達式,就能畫出任何函數圖像,是極方便的。
幾何畫板手機版注冊碼:
License Name: MH UJNM
Active Authorization Code:VQ74UDF3234F46J2FGAWQ4G9A
License Name: MH DFGH
Active Authorization Code:SV34454F8W6843F3FDDV3F4G2A
License Name: MH JMFD
Active Authorization Code:VQ28G34VGFDE343E2FGAOF4E1A
License Name: MH EGHJ
Active Authorization Code:WN74P56Q8M2357E34FGDS9E1A
License Name: MH NMFS
Active Authorization Code:KF74P973FVDFV1E24FVDDOF4I1A
提示:以上注冊碼都是羅列的網上的,如果不能使用,恐怕就需要大家去購買有用的激活碼了。
無論是作圖還是演示、亦或者是元素的變換還是構造等等,都可以在幾何畫板上為你完成,對圖形圖像不滿意還能進行實時的修改,提供了充分的手段為用戶實現實時的圖像教學示范,絕對是一款在教學上極其出色的軟件。
鴉栗 乾明 郭一璞 發自 凹非寺
量子位 報道 | 公眾號 QbitAI
這兩天,一個“魔法畫板”在國外傳瘋了。
AI圈內外的靈魂畫手們玩到根本停不下來,創造的驚喜畫作能裝滿好幾個美術館。
這個畫板背后,可不是一個普通的畫畫AI。它,會腦補。
隨便畫一筆,就能得到一只貓:
畫個圓圈,變成貓;
畫個三角,變成貓;
畫個方塊,變成貓;
真是萬物皆可喵喵。
當然,你也可以不讓它畫貓,改成畫狗。只要你設定了一個繪畫的目標,之后隨便畫一筆,AI就能腦補出余下的畫面。
這個“魔法”,是來自谷歌的吸貓少女Monica Dinculescu用Sketch RNN開發的。
因為她愛貓成癡,不僅自己頭像是和自家喵子的合影,連個人主頁域名都叫Meowni.ca,我們就叫她喵妮卡好了。
所以,受到創作者的影響,這個AI默認屬性為吸貓愛好者,但除了貓之外,AI也會腦補許多其他內容,腦洞很大。
發布之后,眾人競相玩耍,好評如潮,2000多人點贊。
有人讓AI畫了滿屏的骷髏,說,好美啊!
谷歌大佬David Ha也表示,他已經試過用各種基本形狀來教導AI畫羊了。
喵妮卡給應用起名為魔法畫板 (Magic Sketchpad) ,也名副其實。
畢竟,只要畫一筆,媽咪媽咪哄!一整張圖就出現在眼前。
△ 你想要什么樣的美人魚?
而且,只要按一下選擇欄左邊的刷新按鈕,AI就會根據剛才那一筆,不斷為你展現新的畫法。
一共有100多種東西可以畫,青蛙,秋千,直升飛機,連龍貓里的貓巴士都有。
我是一只豆豆眼的貓頭鷹:
我是一只很鬼魅的仙人掌:
為了這100多種選項,都能找到合適的色彩來詮釋,畫板還提供了18種顏色的畫筆。
這樣一來,就有數不清的排列組合。有大膽想法的小伙伴們,可以在魔法畫板上盡情加戲了。
在你開始表演之前,量子位先拋拋磚:
鯨魚噴出的不一定是水,也有可能是花。
牙刷上方溫柔的曲線不一定是牙膏,也有可能是蝸牛。
另外,如果你還沒想到,除了排列組合之外,還可以鬼畜啊。
一頭鯨魚噴水沒什么,十幾頭鯨一起噴,就很有節奏感了 (誤) 。
一個人做瑜伽太孤單了,十幾個人一起做,姿態各不相同,清明瑜伽圖豈不美哉?
不過雖然好玩,量子位似乎還是發現了一個bug,像貓巴士 (Catbus) 這種組合選項:畫方成車,畫圓成貓,無法兼顧。那么,怎樣才能一步生成下面這樣的效果呢?
想要體驗一下的盆友,傳送門照例在文末~
可能你已經發覺了,它的畫風很像的谷歌推出的Quick, Draw!,中文名為“猜畫小歌”。
是的,他們是一家人。
喵妮卡在推特上說了,她的魔法畫板使用的就是Quick, Draw!數據集。
這個數據集里面,有5000萬張畫,分為345個類別。每一張畫,都記錄了畫畫的整個過程:畫筆運動的方向,何時提筆,何時停止繪畫。
如果你玩過猜畫小歌,那這個數據集里,也有你的一份貢獻。
既然使用的是Quick, Draw!數據集,模型基本上沒有什么懸念。
正是Sketch-RNN。這是一個用Quick, Draw!數據集訓練出來循環神經網絡(RNN)。目標是讓AI以類似人類的方式來畫畫,并概括出抽象的概念。
模型有這樣的能力,做出來魔法畫板也就沒有那么難了。
你隨手畫個圈,就是為Sketch-RNN輸入了一個序列,它可以根據這個序列和你選擇要畫的東西,預測接下來的序列:也就是補完這幅畫。
雖然畫風奇特,但畫啥就有點像啥。
具體的實現代碼,喵妮卡也全部放出來了。(傳送門在文末。)
除了這個萬物皆可喵的網頁之外,喵妮卡所在的Google Magenta團隊還用Sketch-RNN創作了幾個不同的涂鴉應用。
9×N種預測,總能猜中你的心
你涂鴉的每一筆,都被我預料到了。
無論你畫了個啥,我都能猜出你接下來準備如何下筆。
并且,我有無數種方案,只要點擊predict,就可以出現新的9種圖案。
而且我還能選擇不同的美術風格,通過調整temperature,數值越接近1,我的畫風越抽象、越狂放不羈;
數值越接近0,我的畫風越寫實,下筆婉轉,基本符合小學美術的要求。
不同圖像,一鍵生成漸變效果
和GAN的許多應用Demo一樣,Sketch-RNN也可以實現“漸變”功能。
比如,我們隨機選了兩個公交車的圖案,圖案的美術風格依然由“狂放度”temperature決定。
之后,點擊Interpolate!就可以實現插值效果,也就是兩個圖案漸變過程的每一幀變化圖案。
我畫得跟你一樣
這個玩法用上了變分自動編碼器(Variational Auto-Encoder,VAE)
VAE在這里的應用,是“模仿你畫畫”。
比如,畫一只貓貓,畫完之后點擊auto-encode,就可以模仿你的筆觸,畫出各種不同的貓。
不過,在不同品類上,似乎學得不太像。
可能是貢獻數據集的那些外國人,不認識“王”字,對小腦斧的理解跟我們不太一樣吧。
另外,這個AI很有個性,非常堅持自己的看法。
比如選中菠蘿pineapple,你非要畫一個蘋果,它也不相信你畫的就是菠蘿。
△ “圖樣,本AI見過的菠蘿多了去了,不要拿蘋果糊弄我”
真是“投之以蘋果,報之以菠蘿”。
魔法畫板
親測手機可玩
https://magic-sketchpad.glitch.me/
實現代碼:
https://glitch.com/edit/#!/magic-sketchpad?path=README.md:1:0
其他可玩Demo
多預測:
https://magenta.tensorflow.org/assets/sketch_rnn_demo/multi_predict.html
插值:
https://magenta.tensorflow.org/assets/sketch_rnn_demo/interp.html
變分自動編碼器(VAE):
https://magenta.tensorflow.org/assets/sketch_rnn_demo/multi_vae.html
背后的Sketch-RNN
Sketch-RNN論文:
https://arxiv.org/abs/1704.03477
Google博客:
https://ai.googleblog.com/2017/04/teaching-machines-to-draw.html
Magenta博客:
https://magenta.tensorflow.org/sketch-rnn-demo
— 完 —
誠摯招聘
量子位正在招募編輯/記者,工作地點在北京中關村。期待有才氣、有熱情的同學加入我們!相關細節,請在量子位公眾號(QbitAI)對話界面,回復“招聘”兩個字。
量子位 QbitAI · 頭條號簽約作者
?'?' ? 追蹤AI技術和產品新動態
)實驗平臺:正點原子開拓者FPGA 開發板
2)摘自《開拓者 Nios II開發指南》關注官方微信號公眾號,獲取更多資料:正點原子
3)全套實驗源碼+手冊+視頻下載地址:http://www.openedv.com/docs/index.html
第十二章MCU TFT-LCD畫板實驗(觸摸驅動)
現在幾乎所有智能手機,包括平板電腦都是采用電容屏作為觸摸屏,電容屏是利用人體感
應進行觸點檢測控制,不需要直接接觸或只需要輕微接觸,通過檢測感應電流來定位觸摸坐標。
在本章中,我們將向大家介紹 Nios II 控制 ALIENTKE LCD 電容觸摸模塊,實現觸摸屏驅動,最
終實現一個手寫板的功能。
本章包括以下幾個部分:
12.1 簡介
12.2 實驗任務
12.3 硬件設計
12.4 軟件設計
12.5 下載驗證
簡介
目前最常用的觸摸屏有兩種:電阻式觸摸屏與電容式觸摸屏。下面,我們來分別介紹。
1) 電阻式觸摸屏
在 Iphone 面世之前,幾乎清一色的都是使用電阻式觸摸屏,電阻式觸摸屏利用壓力感應
進行觸點檢測控制,需要直接應力接觸,通過檢測電阻來定位觸摸位置。
ALIENTEK 2.4/2.8/3.5 寸 LCD 模塊自帶的觸摸屏都屬于電阻式觸摸屏,下面簡單介紹下電阻
式觸摸屏的原理。
電阻觸摸屏的主要部分是一塊與顯示器表面非常配合的電阻薄膜屏,這是一種多層的復合
薄膜,它以一層玻璃或硬塑料平板作為基層,表面涂有一層透明氧化金屬(透明的導電電阻)
導電層,上面再蓋有一層外表面硬化處理、光滑防擦的塑料層、它的內表面也涂有一層涂層、
在它們之間有許多細小的(小于 1/1000 英寸)的透明隔離點把兩層導電層隔開絕緣。當手指
觸摸屏幕時,兩層導電層在觸摸點位置就有了接觸,電阻發生變化,在 X 和 Y 兩個方向上產生
信號,然后送觸摸屏控制器。控制器偵測到這一接觸并計算出(X,Y)的位置,再根據獲得的
位置模擬鼠標的方式運作。這就是電阻技術觸摸屏的最基本的原理。
電阻觸摸屏的優點:精度高、價格便宜、抗干擾能力強、穩定性好。
電阻觸摸屏的缺點:容易被劃傷、透光性不太好、不支持多點觸摸。
從以上介紹可知,觸摸屏都需要一個 AD 轉換器,一般來說是需要一個控制器的。ALIENTEK
LCD 模塊選擇的是四線電阻式觸摸屏,這種觸摸屏的控制芯片有很多,包括:ADS7843、ADS7846、
TSC2046、XPT2046 和 AK4182 等。這幾款芯片的驅動基本上是一樣的,也就是你只要寫出了
ADS7843 的驅動,這個驅動對其他幾個芯片也是有效的。而且封裝也有一樣的,完全 PIN TO PIN
兼容。所以在替換起來,很方便。
ALIENTEK LCD 模塊自帶的觸摸屏控制芯片為 XPT2046。XPT2046 是一款 4 導線制觸摸屏控
制器,內含 12 位分辨率 125KHz 轉換速率逐步逼近型 A/D 轉換器。XPT2046 支持從 1.5V 到
5.25V 的低電壓 I/O 接口。XPT2046 能通過執行兩次 A/D 轉換查出被按的屏幕位置,除此之外,
還可以測量加在觸摸屏上的壓力。內部自帶 2.5V 參考電壓可以作為輔助輸入、溫度測量和電
池監測模式之用,電池監測的電壓范圍可以從 0V 到 6V。XPT2046 片內集成有一個溫度傳感器。
在 2.7V 的典型工作狀態下,關閉參考電壓,功耗可小于 0.75mW。XPT2046 采用微小的封裝形
式:TSSOP-16,QFN-16(0.75mm 厚度)和 VFBGA-48。工作溫度范圍為-40℃~+85℃。
該芯片完全是兼容 ADS7843 和 ADS7846 的,關于這個芯片的詳細使用,可以參考這兩個芯片的 datasheet。
電阻式觸摸屏就介紹到這里。
2) 電容式觸摸屏
現在幾乎所有智能手機,包括平板電腦都是采用電容屏作為觸摸屏,電容屏是利用人體感
應進行觸點檢測控制,不需要直接接觸或只需要輕微接觸,通過檢測感應電流來定位觸摸坐標。
ALIENTEK 4.3/7 寸 LCD 模塊自帶的觸摸屏采用的是電容式觸摸屏,下面簡單介紹下電容式
觸摸屏的原理。
電容式觸摸屏主要分為兩種:
1、表面電容式電容觸摸屏。
表面電容式觸摸屏技術是利用 ITO(銦錫氧化物,一種透明的導電材料)導電膜,通過電場
感應方式感測屏幕表面的觸摸行為進行。但是表面電容式觸摸屏有一些局限性,它只能識別一
個手指或者一次觸摸。
投射式電容觸摸屏
投射電容式觸摸屏是傳感器利用觸摸屏電極發射出靜電場線。一般用于投射電容傳感技術
的電容類型有兩種:自我電容和交互電容。
自我電容又稱絕對電容,是最廣為采用的一種方法,自我電容通常是指掃描電極與地構成
的電容。在玻璃表面有用 ITO 制成的橫向與縱向的掃描電極,這些電極和地之間就構成一個電
容的兩極。當用手或觸摸筆觸摸的時候就會并聯一個電容到電路中去,從而使在該條掃描線上
的總體的電容量有所改變。在掃描的時候,控制 IC 依次掃描縱向和橫向電極,并根據掃描前
后的電容變化來確定觸摸點坐標位置。筆記本電腦觸摸輸入板就是采用的這種方式,筆記本電
腦的輸入板采用 X*Y 的傳感電極陣列形成一個傳感格子,當手指靠近觸摸輸入板時,在手指和
傳感電極之間產生一個小量電荷。采用特定的運算法則處理來自行、列傳感器的信號來確定手
指的位置。
交互電容又叫做跨越電容,它是在玻璃表面的橫向和縱向的 ITO 電極的交叉處形成電容。
交互電容的掃描方式就是掃描每個交叉處的電容變化,來判定觸摸點的位置。當觸摸的時候就
會影響到相鄰電極的耦合,從而改變交叉處的電容量,交互電容的掃面方法可以偵測到每個交
叉點的電容值和觸摸后電容變化,因而它需要的掃描時間與自我電容的掃描方式相比要長一些,
需要掃描檢測 X*Y 根電極。目前智能手機/平板電腦等的觸摸屏,都是采用交互電容技術。
ALIENTEK 所選擇的電容觸摸屏,也是采用的是投射式電容屏(交互電容類型),所以后面
僅以投射式電容屏作為介紹。
透射式電容觸摸屏采用縱橫兩列電極組成感應矩陣,來感應觸摸。以兩個交叉的電極矩陣,
即:X 軸電極和 Y 軸電極,來檢測每一格感應單元的電容變化,如下圖所示:
圖 12.1.1 投射式電容屏電極矩陣示意圖
示意圖中的電極,實際是透明的,這里是為了方便大家理解。圖中,X、Y 軸的透明電極電
容屏的精度、分辨率與 X、Y 軸的通道數有關,通道數越多,精度越高。以上就是電容觸摸屏
的基本原理,接下來看看電容觸摸屏的優缺點:
電容觸摸屏的優點:手感好、無需校準、支持多點觸摸、透光性好。
電容觸摸屏的缺點:成本高、精度不高、抗干擾能力差。
這里特別提醒大家電容觸摸屏對工作環境的要求是比較高的,在潮濕、多塵、高低溫環境
下面,都是不適合使用電容屏的。
電容觸摸屏一般都需要一個驅動 IC 來檢測電容觸摸,且一般是通過 IIC 接口輸出觸摸數據
的。ALIENTEK 7’LCD 模塊的電容觸摸屏,使用 FT5206/FT5426 做為驅動 IC,采用的是 15*28 的
驅動結構(15 個感應通道,28 個驅動通道)。ALIENTEK 4.3’LCD 模塊則使用 GT9147 作為驅
動 IC,采用 17*10 的驅動結構(10 個感應通道,17 個驅動通道)。
這兩個模塊都只支持最多 5 點觸摸,本例程除 CPLD 方案的 V1 版本 7 寸屏模塊不支持外,
其他所有 ALIENTEK 的 LCD 模塊都支持,電容觸摸驅動 IC,這里只介紹 GT9147 的驅動,FT5206
和 FT5426 的驅動同 GT9147 類似,大家可以參考著學習即可。
下面我們簡單介紹下 GT9147,該芯片是深圳匯頂科技研發的一顆電容觸摸屏驅動 IC,支
持 100Hz 觸點掃描頻率,支持 5 點觸摸,支持 18*10 個檢測通道,適合小于 4.5 寸的電容觸摸
屏使用。
GT9147 與 FPGA 連接是通過 4 根線:SDA、SCL、RST 和 INT。其中:SDA 和 SCL 是 IIC 通信
用的,RST 是復位腳(低電平有效),INT 是中斷輸出信號。
GT9147 的 IIC 地址,可以是 0X14 或者 0X5D,當復位結束后的 5ms 內,如果 INT 是高電
平,則使用 0X14 作為地址,否則使用 0X5D 作為地址,具體的設置過程,請看:GT9147 數據
手冊.pdf 這個文檔。本章我們使用 0X14 作為器件地址(不含最低位,換算成讀寫命令則是讀:
0X29,寫:0X28),接下來,介紹一下 GT9147 的幾個重要的寄存器。
1,控制命令寄存器(0X8040)
該寄存器可以寫入不同值,實現不同的控制,我們一般使用 0 和 2 這兩個值,寫入 2,
即可軟復位 GT9147,在硬復位之后,一般要往該寄存器寫 2,實行軟復位。然后,寫入 0,
即可正常讀取坐標數據(并且會結束軟復位)。
2,配置寄存器組(0X8047~0X8100)
這里共 186 個寄存器,用于配置 GT9147 的各個參數,這些配置一般由廠家提供給我們(一
個數組),所以我們只需要將廠家給我們的配置,寫入到這些寄存器里面,即可完成 GT9147
的配置。由于 GT9147 可以保存配置信息(可寫入內部 FLASH,從而不需要每次上電都更新配
置),我們有幾點注意的地方提醒大家:1,0X8047 寄存器用于指示配置文件版本號,程序寫
入的版本號,必須大于等于 GT9147 本地保存的版本號,才可以更新配置。2,0X80FF 寄存器
用于存儲校驗和,使得 0X8047~0X80FF 之間所有數據之和為 0。3,0X8100 用于控制是否將配
置保存在本地,寫 0,則不保存配置,寫 1 則保存配置。
3,產品 ID 寄存器(0X8140~0X8143)
這里總共由 4 個寄存器組成,用于保存產品 ID,對于 GT9147,這 4 個寄存器讀出來就
是:9,1,4,7 四個字符(ASCII 碼格式)。因此,我們可以通過這 4 個寄存器的值,來判斷
驅動 IC 的型號,從而判斷是 GT9147 還是 FT5206,以便執行不同的初始化。
4,狀態寄存器(0X814E)
該寄存器各位描述如下表所示:
圖 12.1.2 寄存器定義
這里,我們僅關心最高位和最低 4 位,最高位用于表示 buffer 狀態,如果有數據(坐標/
按鍵),buffer 就會是 1,最低 4 位用于表示有效觸點的個數,范圍是:0~5,0 表示沒有觸摸,
5 表示有 5 點觸摸。最后,該寄存器在每次讀取后,如果 bit7 有效,則必須寫 0,清除這個位,
否則不會輸出下一次數據!!這個要特別注意!!!
5,坐標數據寄存器(共 30 個)
這里共分成 5 組(5 個點),每組 6 個寄存器存儲數據,以觸點 1 的坐標數據寄存器組為
例,如下表所示:
圖 12.1.3 觸點 1 坐標寄存器組描述
我們一般只用到觸點的 x,y 坐標,所以只需要讀取 0X8150~0X8153 的數據,組合即可得
到觸點坐標。其他 4 組分別是:0X8158、0X8160、0X8168 和 0X8170 等開頭的 16 個寄存器組
成,分別針對觸點 2~4 的坐標。GT9147 支持寄存器地址自增,我們只需要發送寄存器組的首
地址,然后連續讀取即可,GT9147 會自動地址自增,從而提高讀取速度。
GT9147 相關寄存器的介紹就介紹到這里,更詳細的資料,請參考:GT9147 編程指南.pdf
這個文檔。
GT9147 只需要經過簡單的初始化就可以正常使用了,初始化流程:硬復位→延時 10ms→
結束硬復位→設置 IIC 地址→延時 100ms→軟復位→更新配置(需要時)→結束軟復位。此時
GT9147 即可正常使用了。
然后,我們不停的查詢 0X814E 寄存器,判斷是否有有效觸點,如果有,則讀取坐標數據
寄存器,得到觸點坐標,特別注意,如果 0X814E 讀到的值最高位為 1,就必須對該位寫 0,否
則無法讀到下一次坐標數據。
特別說明:FT5206 和 FT5426 的驅動代碼完全一模一樣,他們只是版本號讀取的時候稍有
差異,讀坐標數據和配置等操作動完全是一模一樣的。所以,這兩個電容屏驅動 IC,可以共用
一個.c 文件(ft5206.c)。電容式觸摸屏部分,就介紹到這里。
實驗任務
本章我們使用 Nios II 結合 MCU TFT-LCD 驅動,實現 LCD 畫板功能。
硬件設計
硬件框架
本章實驗的硬件框架是在 MCU TFT-LCD 顯示實驗框架的基礎上添加觸摸屏驅動所需的 4
個 PIO 信號,如下圖所示:
圖12.3.1 TFTLCD顯示實驗的硬件框架圖
頂層代碼如下:
1 module qsys_touch(
2 //module clock
3 input sys_clk , //系統時鐘,50Mhz
4 input sys_rst_n , //系統復位,低電平有效
5
6 //SDRAM interface
7 output sdram_clk , //SDRAM 芯片時鐘
8 output sdram_cke , //SDRAM 時鐘有效
9 output sdram_cs_n , //SDRAM 片選
10 output sdram_ras_n, //SDRAM 行有效
11 output sdram_cas_n, //SDRAM 列有效
12 output sdram_we_n , //SDRAM 寫有效
13 output [ 1:0] sdram_ba , //SDRAM Bank 地址
14 output [12:0] sdram_addr , //SDRAM 行/列地址
15 inout [15:0] sdram_data , //SDRAM 數據
16 output [ 1:0] sdram_dqm , //SDRAM 數據掩碼
17
18 //EPCS FLASH interface
19 output epcs_dclk , // EPCS 時鐘信號
20 output epcs_sce , // EPCS 片選信號
21 output epcs_sdo , // EPCS 數據輸出信號
22 input epcs_data0 , // EPCS 數據輸入信號
23
24 //MCU LCD interface
25 inout [15:0] mlcd_data , // LCD 數據信號
26 output mlcd_bl , // LCD 背光信號
27 output mlcd_cs_n , // LCD 片選信號
28 output mlcd_wr_n , // LCD 寫信號
29 output mlcd_rd_n , // LCD 讀信號
30 output mlcd_rs , // LCD 命令/數據信號
31 output mlcd_rst_n , // LCD 復位信號
32
33 //TOUCH interface
34 output touch_tcs , // 觸摸屏復位信號
35 inout touch_int , // 觸摸屏中斷信號
36 output touch_scl , // 觸摸屏 IIC_SCL 信號
37 inout touch_sda // 觸摸屏 IIC_SDA 信號
38 );
39
40 //wire define
41 wire clk_100m; //SDRAM 控制器時鐘
42 wire rst_n ; //系統復位信號
43 wire locked ; //PLL 輸出穩定標志
44
45 //*****************************************************
46 //** main code
47 //*****************************************************
48
49 //待 PLL 輸出穩定之后,停止系統復位
50 assign rst_n =sys_rst_n & locked;
51
52 //例化 PLL
53 pll_clk u_pll_clk(
54 .areset (~sys_rst_n),
55 .inclk0 (sys_clk ),
56 .c0 (clk_100m ),
57 .c1 (sdram_clk ),
58 .locked (locked )
59 );
60
61 //例化 Nios2 系統模塊
62 nios2os u_nios2os (
63 .clk_clk (clk_100m ), // 時鐘 100M
64 .reset_reset_n (rst_n ), // 復位信號
65 .sdram_addr (sdram_addr ), // SDRAM 行/列地址
66 .sdram_ba (sdram_ba ), // SDRAM Bank 地址
67 .sdram_cas_n (sdram_cas_n), // SDRAM 列有效
68 .sdram_cke (sdram_cke ), // SDRAM 時鐘有效
69 .sdram_cs_n (sdram_cs_n ), // SDRAM 片選
70 .sdram_dq (sdram_data ), // SDRAM 數據
71 .sdram_dqm (sdram_dqm ), // SDRAM 數據掩碼
72 .sdram_ras_n (sdram_ras_n), // SDRAM 行有效
73 .sdram_we_n (sdram_we_n ), // SDRAM 寫有效
74 .epcs_dclk (epcs_dclk ), // EPCS 時鐘信號
75 .epcs_sce (epcs_sce ), // EPCS 片選信號
76 .epcs_sdo (epcs_sdo ), // EPCS 數據輸出信號
77 .epcs_data0 (epcs_data0 ), // EPCS 數據輸入信號
78 .mlcd_data_export (mlcd_data ), // LCD 數據信號
79 .mlcd_cs_n_export (mlcd_cs_n ), // LCD 片選信號
80 .mlcd_wr_n_export (mlcd_wr_n ), // LCD 寫信號
81 .mlcd_rd_n_export (mlcd_rd_n ), // LCD 讀信號
82 .mlcd_rst_n_export(mlcd_rst_n ), // LCD 復位信號
83 .mlcd_rs_export (mlcd_rs ), // LCD 命令/數據信號
84 .mlcd_bl_export (mlcd_bl ), // LCD 背光信號
85 .touch_tcs_export (touch_tcs ), // 觸摸屏復位信號
86 .touch_int_export (touch_int ), // 觸摸屏中斷信號
87 .touch_scl_export (touch_scl ), // 觸摸屏 IIC_SCL 信號
88 .touch_sda_export (touch_sda ) // 觸摸屏 IIC_SDA 信號
89 );
90
91 endmodule
頂層代碼主要實現 PLL 和 Nios II 系統模塊的例化。
接下來進行引腳分配,需要在 TFT LCD 顯示實驗的基礎上分配觸摸的引腳,如下:
圖 12.3.2 引腳分配
軟件設計
創建好軟件工程后,我們將 hello_world.c 更改為 qsys_touch.c,并在 qsys_touch 的應用工
程下新建兩個文件夾,分別命名為 drives 和 APP,然后在 drives 文件夾里面新建兩個文件夾,
分別命名為 LCD 和 TOUCH,LCD 文件夾存放 TFTLCD 的驅動代碼文件和相應的字體文件,TOUCH
文件夾存放觸摸驅動相關的文件,APP 文件夾下存放宏定義文件和延時函數文件。工程目錄結
構如下圖所示:
圖 12.4.1 工程目錄結構
LCD 文件夾的內容在 MCU TFT-LCD 章節已具體介紹,主要用于驅動 TFT LCD 的顯示,TOUCH
文件夾下的文件用于驅動正點原子不同型號的采用 IIC 協議的電容觸摸屏,myiic 文件是用 C
模擬的 IIC 協議。我們先來看一下 APP 文件夾下的文件內容。
defines.h 文件是將我們常用的宏定義做一個歸類,方便使用,內容如下:
1 #ifndef DEFINES_H_
2 #define DEFINES_H_
3
4 //重新定義類型
5 #define u8 unsigned char
6 #define u16 unsigned short
7 #define u32 unsigned long
8 #define u64 unsigned long long
9
10 #endif /* DEFINES_H_ */
delay.c 文件內容如下:
1 #include "delay.h"
2 #include <unistd.h>
3
4 //延時函數,單位毫秒
5 void delay_ms(u32 n)
6 {
7 usleep(n*1000);
8 }
9
10 //延時函數,單位微秒
11 void delay_us(u32 n)
12 {
13 usleep(n);
14 }
現在我們來看一下使用 C 來模擬 IIC 協議的 myiic.h 和 myiic.c 文件,myiic.h 內容如下:
1 #ifndef __MYIIC_H
2 #define __MYIIC_H
3 #include "delay.h"
4 #include "system.h"
5 #include "altera_avalon_pio_regs.h"
6
7 //IO 方向設置
8 #define SDA_IN() {IOWR_ALTERA_AVALON_PIO_DIRECTION(TOUCH_SDA_BASE,0x0);} //輸入模式
9 #define SDA_OUT() {IOWR_ALTERA_AVALON_PIO_DIRECTION(TOUCH_SDA_BASE,0x1);} //輸出模式
10
11 //IO 操作函數
12 #define IIC_SCL(x) IOWR_ALTERA_AVALON_PIO_DATA(TOUCH_SCL_BASE,x) //SCL
13 #define IIC_SDA(x) IOWR_ALTERA_AVALON_PIO_DATA(TOUCH_SDA_BASE,x) //寫入 SDA
14 #define READ_SDA IORD_ALTERA_AVALON_PIO_DATA(TOUCH_SDA_BASE) //讀取 SDA
15
16 //IIC 所有操作函數
17 void IIC_Init(void); //初始化 IIC 的 IO 口
18 void IIC_Start(void); //發送 IIC 開始信號
19 void IIC_Stop(void); //發送 IIC 停止信號
20 void IIC_Send_Byte(u8 txd); //IIC 發送一個字節
21 u8 IIC_Read_Byte(unsigned char ack); //IIC 讀取一個字節
22 u8 IIC_Wait_Ack(void); //IIC 等待 ACK 信號
23 void IIC_Ack(void); //IIC 發送 ACK 信號
24 void IIC_NAck(void); //IIC 不發送 ACK 信號
25 #endif
代碼的第 8~9 行,設置了雙向信號 SDA 的輸入、輸出模式。代碼的第 12~14 行宏定義了 IO
操作函數。
myiic.c 文件的內容如下:
1 #include "myiic.h"
2 #include "delay.h"
3 #include <unistd.h>
4
5 //初始化 IIC
6 void IIC_Init(void)
7 {
8 IIC_SCL(1);
9 IIC_SDA(1);
10 }
11
12 //產生 IIC 起始信號
13 void IIC_Start(void)
14 {
15 SDA_OUT(); //sda 線輸出
16 IIC_SDA(1);
17 IIC_SCL(1);
18 usleep(2);
19 IIC_SDA(0); //START 信號:SCL 為高時,SDA 由高變低
20 usleep(2);
21 IIC_SCL(0); //鉗住 I2C 總線,準備發送或接收數據
22 }
23
24 //產生 IIC 停止信號
25 void IIC_Stop(void)
26 {
27 SDA_OUT(); //sda 線輸出
28 IIC_SCL(0);
29 IIC_SDA(0); //STOP 信號:SCL 為高時,SDA 由低變高
30 usleep(2);
31 IIC_SCL(1);
32 usleep(2);
33 IIC_SDA(1); //發送 I2C 總線結束信號
34 usleep(2);
35 }
36
37 //等待應答信號到來
38 //返回值:1,接收應答失敗
39 // 0,接收應答成功
40 u8 IIC_Wait_Ack(void)
41 {
42 u8 ucErrTime=0;
43 SDA_IN(); //SDA 設置為輸入
44 IIC_SDA(1);
45 usleep(2);
46 IIC_SCL(1);
47 usleep(2);
48 while(READ_SDA) {
49 ucErrTime++;
50 if(ucErrTime>250) {
51 IIC_Stop();
52 return 1;
53 }
54 }
55 IIC_SCL(0);//時鐘輸出 0
56 return 0;
57 }
58
59 //產生 ACK 應答
60 void IIC_Ack(void)
61 {
62 IIC_SCL(0);
63 SDA_OUT();
64 IIC_SDA(0);
65 usleep(2);
66 IIC_SCL(1);
67 usleep(2);
68 IIC_SCL(0);
69 }
70
71 //不產生 ACK 應答
72 void IIC_NAck(void)
73 {
74 IIC_SCL(0);
75 SDA_OUT();
76 IIC_SDA(1);
77 usleep(1);
78 IIC_SCL(1);
79 usleep(1);
80 IIC_SCL(0);
81 }
82
83 //IIC 發送一個字節
84 //返回從機有無應答
85 //1,有應答
86 //0,無應答
87 void IIC_Send_Byte(u8 txd)
88 {
89 u8 t;
90 SDA_OUT();
91 IIC_SCL(0);//拉低時鐘開始數據傳輸
92 for(t=0; t<8; t++) {
93 IIC_SDA((txd&0x80)>>7);
94 txd<<=1;
95 usleep(1);
96 IIC_SCL(1);
97 usleep(1);
98 IIC_SCL(0);
99 usleep(1);
100 }
101 }
102
103 //讀 1 個字節,ack=1 時,發送 ACK,ack=0,發送 nACK
104 u8 IIC_Read_Byte(unsigned char ack)
105 {
106 unsigned char i,receive=0;
107 SDA_IN();//SDA 設置為輸入
108 for(i=0; i<8; i++ ) {
109 IIC_SCL(0);
110 usleep(1);
111 IIC_SCL(1);
112 receive<<=1;
113 if(READ_SDA)
114 receive++;
115 usleep(1);
116 }
117 if (!ack)
118 IIC_NAck();//發送 nACK
119 else
120 IIC_Ack(); //發送 ACK
121 return receive;
122 }
該部分為 IIC 驅動代碼,實現包括 IIC 的初始化(IO 口)、IIC 開始、IIC 結束、ACK、IIC 讀
寫等功能,在其他函數里面,只需要調用相關的 IIC 函數就可以和外部 IIC 器件通信了,這里并
不局限于 TOUCH 的驅動,該段代碼可以用在任何 IIC 設備上。對于 IIC 協議的具體介紹可以參
見《開拓者 FPGA 開發指南》的第二十八章 EEPROM 讀寫測試實驗。
保存該部分代碼,把 myiic.c 加入到 drives\TOUCH 文件夾下面,然后在 myiic.h 里面輸入如
下代碼:
1 #ifndef __MYIIC_H
2 #define __MYIIC_H
3 #include "delay.h"
4 #include "system.h"
5 #include "altera_avalon_pio_regs.h"
6
7 //IO 方向設置
8 #define SDA_IN() {IOWR_ALTERA_AVALON_PIO_DIRECTION(TOUCH_SDA_BASE,0x0);} //輸入模式
9 #define SDA_OUT() {IOWR_ALTERA_AVALON_PIO_DIRECTION(TOUCH_SDA_BASE,0x1);} //輸出模式
10
11 //IO 操作函數
12 #define IIC_SCL(x) IOWR_ALTERA_AVALON_PIO_DATA(TOUCH_SCL_BASE,x) //SCL
13 #define IIC_SDA(x) IOWR_ALTERA_AVALON_PIO_DATA(TOUCH_SDA_BASE,x) //寫入 SDA
14 #define READ_SDA IORD_ALTERA_AVALON_PIO_DATA(TOUCH_SDA_BASE) //讀取 SDA
15
16 //IIC 所有操作函數
17 void IIC_Init(void); //初始化 IIC 的 IO 口
18 void IIC_Start(void); //發送 IIC 開始信號
19 void IIC_Stop(void); //發送 IIC 停止信號
20 void IIC_Send_Byte(u8 txd); //IIC 發送一個字節
21 u8 IIC_Read_Byte(unsigned char ack); //IIC 讀取一個字節
22 u8 IIC_Wait_Ack(void); //IIC 等待 ACK 信號
23 void IIC_Ack(void); //IIC 發送 ACK 信號
24 void IIC_NAck(void); //IIC 不發送 ACK 信號
25 #endif
接下來我們看一下電容觸摸屏的驅動代碼。
首先,我們看看 touch.h 里面的代碼,
1 #ifndef __TOUCH_H__
2 #define __TOUCH_H__
3
4 #include "system.h"
5 #include "gt9147.h"
6 #include "gt9271.h"
7 #include "ft5206.h"
8 #include "mculcd.h"
9
10 #define TP_PRES_DOWN 0x8000 //觸屏被按下
11 #define TP_CATH_PRES 0x4000 //有按鍵按下了
12 #define CT_MAX_TOUCH 10 //電容屏支持的點數,固定為10點
13
14 #define PEN IORD_ALTERA_AVALON_PIO_DATA(TOUCH_INT_BASE) //T_PEN
15
16 //觸摸屏控制器
17 typedef struct
18 {
19 u8 (*init)(void); //初始化觸摸屏控制器
20 u8 (*scan)(u8); //掃描觸摸屏.0,屏幕掃描;1,物理坐標;
21 u16 x[CT_MAX_TOUCH]; //當前坐標
22 u16 y[CT_MAX_TOUCH];
23 //電容屏最多有10組坐標,電阻屏則用x[0],y[0]代表:此次掃描時,觸屏的坐標,用
24 //x[9],y[9]存儲第一次按下時的坐標.
25 u16 sta; //筆的狀態
26 //b15:按下1/松開0;
27 //b14:0,沒有按鍵按下;1,有按鍵按下.
28 //b13~b10:保留
29 //b9~b0:電容觸摸屏按下的點數(0,表示未按下,1表示按下)
30 //新增的參數,當觸摸屏的左右上下完全顛倒時需要用到.
31 //b0:0,豎屏(適合左右為X坐標,上下為Y坐標的TP)
32 // 1,橫屏(適合左右為Y坐標,上下為X坐標的TP)
33 //b1~6:保留.
34 //b7:0,電阻屏
35 // 1,電容屏
36 u8 touchtype;
37 }_m_tp_dev;
38
39 extern _m_tp_dev tp_dev; //觸屏控制器在touch.c里面定義
40
41 //電容屏 共用函數
42 u8 TP_Scan(); //掃描
43 void TP_Init(void); //初始化
44
45 #endif
上述代碼,我們重點看看_m_tp_dev 結構體,改結構體用于管理和記錄觸摸屏相關信息。
通過結構體,在使用的時候,我們一般直接調用 tp_dev 的相關成員函數/變量,即可達到需要
的效果,這種設計簡化了接口,且方便管理和維護,大家可以效仿一下。
現在,我們看一下 touch.c 里面的代碼,由于代碼比較多,我們就不一一介紹了,這里我
們僅介紹 TP_Init 函數,該函數根據 LCD 的 ID(即 lcddev.id)判別不同的電容屏,然后執行不
同的初始化,該函數代碼如下:
46 //觸摸屏初始化
47 void TP_Init(void)
48 {
49 if(lcddev.id==0X5510||lcddev.id==0X4342) { //電容觸摸屏,4.3 寸屏
50 GT9147_Init();
51 tp_dev.scan=GT9147_Scan; //掃描函數指向 GT9147 觸摸屏掃描
52 tp_dev.touchtype|=0X80; //電容屏
53 tp_dev.touchtype|=lcddev.dir&0X01; //橫屏還是豎屏
54 }
55 //SSD1963 7 寸屏或者 7 寸 800*480/1024*600 RGB 屏
56 else if(lcddev.id==0X1963||lcddev.id==0X7084||lcddev.id==0X7016) {
57 FT5206_Init();
58 tp_dev.scan=FT5206_Scan; //掃描函數指向 GT9147 觸摸屏掃描
59 tp_dev.touchtype|=0X80; //電容屏
60 tp_dev.touchtype|=lcddev.dir&0X01; //橫屏還是豎屏
61 } else if(lcddev.id==0X1018) {
62 GT9271_Init();
63 tp_dev.scan=GT9271_Scan; //掃描函數指向 GT271 觸摸屏掃描
64 tp_dev.touchtype|=0X80; //電容屏
65 tp_dev.touchtype|=lcddev.dir&0X01; //橫屏還是豎屏
66 }
67 }
該函數比較簡單,重點說一下:tp_dev.scan,這個結構體函數指針,默認是指向 TP_Scan
的,如果是電阻屏則用默認的即可,如果是電容屏,則指向新的掃描函數 GT9147_Scan 或
FT5206_Scan(根據芯片 ID 判斷到底指向那個),執行電容觸摸屏的掃描函數。
因為 GT9147 和 GT9271 為同一系列的觸摸屏,除配置參數有差別外,其它的差別不大,
而 FT5206 的代碼與 GT9147 的差別在于無需通過 int 引腳來選擇不同的 i2c 器件地址,也無需
配置繁雜的寄存器,其余的和 GT9147 差別不大。所以下面我們主要針對 GT9147 的驅動進行
介紹。
首先我們看下 gt9147.h 代碼,如下:
1 #ifndef __GT9147_H
2 #define __GT9147_H
3 #include "system.h"
4 #include "defines.h"
5 #include "mculcd.h"
6
7 //IO 操作函數
8 #define GT9147_RST(x) IOWR_ALTERA_AVALON_PIO_DATA(TOUCH_TCS_BASE,x) //GT9147 復位引腳
9 #define GT9147_INT(x) IOWR_ALTERA_AVALON_PIO_DATA(TOUCH_INT_BASE,x) //GT9147 中斷引腳
10 //設置 PIO 的方向
11 #define GT9147_INT_DIR(x) IOWR_ALTERA_AVALON_PIO_DIRECTION(TOUCH_INT_BASE,x)
12
13 //I2C 讀寫命令
14 #define GT_CMD_WR 0X28 //寫命令
15 #define GT_CMD_RD 0X29 //讀命令
16
17 //GT9147 部分寄存器定義
18 #define GT_CTRL_REG 0X8040 //GT9147 控制寄存器
19 #define GT_CFGS_REG 0X8047 //GT9147 配置起始地址寄存器
20 #define GT_CHECK_REG 0X80FF //GT9147 校驗和寄存器
21 #define GT_PID_REG 0X8140 //GT9147 產品 ID 寄存器
22
23 #define GT_GSTID_REG 0X814E //GT9147 當前檢測到的觸摸情況
24 #define GT_TP1_REG 0X8150 //第一個觸摸點數據地址
25 #define GT_TP2_REG 0X8158 //第二個觸摸點數據地址
26 #define GT_TP3_REG 0X8160 //第三個觸摸點數據地址
27 #define GT_TP4_REG 0X8168 //第四個觸摸點數據地址
28 #define GT_TP5_REG 0X8170 //第五個觸摸點數據地址
29
30
31 u8 GT9147_Send_Cfg(u8 mode); //發送 GT9147 配置參數
32 u8 GT9147_WR_Reg(u16 reg,u8 *buf,u8 len); //向 GT9147 寫入一次數據
33 void GT9147_RD_Reg(u16 reg,u8 *buf,u8 len); //從 GT9147 讀出一次數據
34 u8 GT9147_Init(void); //初始化 GT9147 觸摸屏
35 u8 GT9147_Scan(u8 mode); //掃描觸摸屏(采用查詢方式)
36 #endif
37
在該頭文件中我們宏定義了 IO 操作函數和 GT9147 的寄存器地址。主要用于方便修改和
管理。
接下來看下 gt9147.c 里面的代碼,這里我們僅介紹 GT9147_Init 和 GT9147_Scan 兩個函數,
代碼如下:
94 //初始化 GT9147 觸摸屏
95 //返回值:0,初始化成功;1,初始化失敗
96 u8 GT9147_Init(void)
97 {
98 u8 temp[5];
99 GT9147_INT_DIR(1);
100 GT9147_INT(1);
101 IIC_Init(); //初始化電容屏的 I2C 總線
102 GT9147_RST(0); //復位
103 delay_ms(10);
104 GT9147_RST(1); //釋放復位
105 delay_ms(10);
106 GT9147_INT_DIR(0);
107 delay_ms(100);
108 GT9147_RD_Reg(GT_PID_REG,temp,4);//讀取產品 ID
109 temp[4]=0;
110 printf("CTP ID:%s\r\n",temp); //打印 ID
111 if(strcmp((char*)temp,"9147")==0) { //ID==9147
112 temp[0]=0X02;
113 GT9147_WR_Reg(GT_CTRL_REG,temp,1);//軟復位 GT9147
114 GT9147_RD_Reg(GT_CFGS_REG,temp,1);//讀取 GT_CFGS_REG 寄存器
115 if(temp[0]<0X60) { //默認版本比較低,需要更新 flash 配置
116 // printf("Default Ver:%d\r\n",temp[0]);
117 if(lcddev.id==0X5510)
118 GT9147_Send_Cfg(1);//僅 4.3 寸 MCU 屏,更新并保存配置
119 }
120 delay_ms(10);
121 temp[0]=0X00;
122 GT9147_WR_Reg(GT_CTRL_REG,temp,1);//結束復位
123 return 0;
124 }
125 return 1;
126 }
以上代碼,GT9147_Init 用于初始化 GT9147,該函數通過讀取 0X8140~0X8143 這 4 個寄存
器,并判斷是否是:“9147”
,來確定是不是 GT9147 芯片,在讀取到正確的 ID 后,軟復位 GT9147,
然后根據當前芯片版本號,確定是否需要更新配置,通過 GT9147_Send_Cfg 函數,發送配置信
息(一個數組),配置完后,結束軟復位,即完成 GT9147 初始化。
130 //掃描觸摸屏(采用查詢方式)
131 //mode:0,正常掃描.
132 //返回值:當前觸屏狀態.
133 //0,觸屏無觸摸;1,觸屏有觸摸
134 u8 GT9147_Scan(u8 mode)
135 {
136 u8 buf[4];
137 u8 i=0;
138 u8 res=0;
139 u8 temp;
140 u8 tempsta;
141 static u8 t=0;//控制查詢間隔,從而降低 CPU 占用率
142 t++;
143 if((t%10)==0||t<10) { //空閑時,每進入 10 次 CTP_Scan 函數才檢測 1 次,從而節省 CPU 使用率
144 GT9147_RD_Reg(GT_GSTID_REG,&mode,1); //讀取觸摸點的狀態
145 if((mode & 0X80) &&((mode&0XF)<6)) {
146 temp=0;
147 GT9147_WR_Reg(GT_GSTID_REG,&temp,1);//清標志
148 }
149 if((mode&0XF)&&((mode&0XF)<6)) {
150 temp=0XFF<<(mode&0XF); //將點的個數轉換為 1 的位數,匹配 tp_dev.sta 定義
151 tempsta=tp_dev.sta; //保存當前的 tp_dev.sta 值
152 tp_dev.sta=(~temp)|TP_PRES_DOWN|TP_CATH_PRES;
153 tp_dev.x[4]=tp_dev.x[0]; //保存觸點 0 的數據
154 tp_dev.y[4]=tp_dev.y[0];
155 for(i=0; i<5; i++) {
156 if(tp_dev.sta&(1<<i)) { //觸摸有效?
157 GT9147_RD_Reg(GT9147_TPX_TBL[i],buf,4); //讀取 XY 坐標值
158 if(lcddev.id==0X5510) { //4.3 寸 800*480 MCU 屏
159 if(tp_dev.touchtype & 0X01) { //橫屏
160 tp_dev.y[i]=((u16)buf[1]<<8)+buf[0];
161 tp_dev.x[i]=800-(((u16)buf[3]<<8)+buf[2]);
162 } else {
163 tp_dev.x[i]=((u16)buf[1]<<8)+buf[0];
164 tp_dev.y[i]=((u16)buf[3]<<8)+buf[2];
165 }
166 } else if(lcddev.id==0X4342) { //4.3 寸 480*272 RGB 屏
167 if(tp_dev.touchtype & 0X01) { //橫屏
168 tp_dev.x[i]=(((u16)buf[1]<<8)+buf[0]);
169 tp_dev.y[i]=(((u16)buf[3]<<8)+buf[2]);
170 } else {
171 tp_dev.y[i]=((u16)buf[1]<<8)+buf[0];
172 tp_dev.x[i]=272-(((u16)buf[3]<<8)+buf[2]);
173 }
174 }
175 // printf("x[%d]:%d,y[%d]:%d\r\n",i,tp_dev.x[i],i,tp_dev.y[i]);
176 }
177 }
178 res=1;
179 if(tp_dev.x[0]>lcddev.width||tp_dev.y[0]>lcddev.height) { // 坐標超出了
180 if((mode&0XF)>1) { //有其他點有數據,則復第二個觸點的數據到第一個觸點.
181 tp_dev.x[0]=tp_dev.x[1];
182 tp_dev.y[0]=tp_dev.y[1];
183 t=0; //觸發一次,則會最少連續監測 10 次,從而提高命中率
184 } else { //非法數據,則忽略此次數據(還原原來的)
185 tp_dev.x[0]=tp_dev.x[4];
186 tp_dev.y[0]=tp_dev.y[4];
187 mode=0X80;
188 tp_dev.sta=tempsta; //恢復 tp_dev.sta
189 }
190 } else t=0; //觸發一次,則會最少連續監測 10 次,從而提高命中率
191 }
192 }
193 if((mode&0X8F)==0X80) { //無觸摸點按下
194 if(tp_dev.sta&TP_PRES_DOWN) { //之前是被按下的
195 tp_dev.sta &=~(1<<7); //標記按鍵松開
196 } else { //之前就沒有被按下
197 tp_dev.x[0]=0xffff;
198 tp_dev.y[0]=0xffff;
199 tp_dev.sta&=0XE0; //清除點有效標記
200 }
201 }
202 if(t>240)
203 t=10;//重新從 10 開始計數
204 return res;
205 }
GT9147_Scan 函數用于掃描電容觸摸屏是否有按鍵按下,由于我們不是用的中斷方式來讀
取 GT9147 的數據的,而是采用查詢的方式,所以這里使用了一個靜態變量來提高效率,當無
觸摸的時候,盡量減少對 CPU 的占用,當有觸摸的時候,又保證能迅速檢測到。對 GT9147 數
據的讀取,先讀取手勢 ID 寄存器(GT_GSTID_REG),判斷是不是有有效數據,如果有,則讀
取,否則直接忽略,繼續后面的處理。
最后我們打開 qsys_touch.c,這里就不全部貼出來了,僅介紹 main 函數和電容觸摸屏測試
函數。main 函數代碼如下:
17 int main(void) {
18 printf("Hello from Nios II!\n");
19 MCULCD_Init(); //初始化 MCU LCD
20 tp_dev.init(); //觸摸屏初始化
21 POINT_COLOR =MLCD_RED;
22
23 LCD_ShowString(30, 50, 300, 30, 24, 0, "Welcome to PIONEER FPGA");
24 LCD_ShowString(30, 80, 400, 30, 24, 0, "This is a TOUCH test application");
25 LCD_ShowString(30, 110, 200, 30, 24, 0, "ATOM@ALIENTEK");
26 LCD_ShowString(30, 140, 200, 30, 24, 0, "2018/10/10");
27
28 delay_ms(1500);
29 Load_Drow_Dialog();
30
31 if (tp_dev.touchtype & 0X80)
32 ctp_test(); //電容屏測試
33 }
main 函數比較簡單,初始化相關外設,輸出提示信息,然后根據觸摸屏類型,去選擇執
行 ctp_test 函數。ctp_test 函數代碼如下:
83 //電容觸摸屏測試函數
84 void ctp_test(void) {
85 u8 t =0;
86 u8 i =0;
87 u16 lastpos[10][2]; //最后一次的數據
88 u8 maxp =5; //最大觸摸點數
89 if (lcddev.id ==0X1018)
90 maxp =10;
91 while(1) {
92 tp_dev.scan(0);
93 for (t =0; t < maxp; t++) {
94 if ((tp_dev.sta) & (1 << t)) {
95 if (tp_dev.x[t] < lcddev.width && tp_dev.y[t] < lcddev.height) {
96 if (lastpos[t][0]==0XFFFF) {
97 lastpos[t][0]=tp_dev.x[t];
98 lastpos[t][1]=tp_dev.y[t];
99 }
100 lcd_draw_bline(lastpos[t][0], lastpos[t][1], tp_dev.x[t],
101 tp_dev.y[t], 2, POINT_COLOR_TBL[t]); //畫線
102 lastpos[t][0]=tp_dev.x[t];
103 lastpos[t][1]=tp_dev.y[t];
104 if (tp_dev.x[t] > (lcddev.width - 43) && tp_dev.y[t] < 24) {
105 Load_Drow_Dialog(); //清除
106 }
107 }
108 } else
109 lastpos[t][0]=0XFFFF;
110 }
111 delay_ms(5);
112 i++;
113 }
114 }
ctp_test,該函數用于電容觸摸屏的測試,由于我們采用 tp_dev.sta 來標記當前按下的觸摸
屏點數,所以判斷是否有電容觸摸屏按下,也就是判斷 tp_dev.sta 的最低 5 位,如果有數據,
則劃線,如果沒數據則忽略,且 5 個點劃線的顏色各不一樣,方便區分。另外,電容觸摸屏不
需要校準,所以沒有校準程序。
軟件部分就介紹到這里,接下來看看下載驗證。
下載驗證
講完了軟件工程,接下來我們就將該實驗下載至我們的開拓者開發板進行驗證。
首先我們將 4.3 寸的 ATK-4.3’TFTLCD 與開發板上的 MCU TFT LCD 接口連接。再將下載器
一端連電腦,另一端與開發板上對應端口連接,最后連接電源線并打開電源開關。
我們在 Quartus II 軟件中將 qsys_touch.sof 文件下載至我們的開拓者開發板,qsys_ touch.sof
下載完成后,我們還需要在 Nios II SBT for Eclipse 軟件中將 qsys_ touch.elf 文件下載至我們的開
拓者開發板,qsys_ touch.elf 下載完成以后,我們的 C 程序將會執行在我們的開拓者開發板上。
手指在觸摸屏上劃動時顯示劃動的軌跡(寫一個“正”字),結果如下圖所示。
圖 12.5.1 實驗結果圖
至此,我們的 TFT LCD 觸摸屏實驗就完成了。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。