FPGA之PS鍵盤驅(qū)動_第1頁
FPGA之PS鍵盤驅(qū)動_第2頁
FPGA之PS鍵盤驅(qū)動_第3頁
FPGA之PS鍵盤驅(qū)動_第4頁
FPGA之PS鍵盤驅(qū)動_第5頁
已閱讀5頁,還剩12頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、小梅哥和你一起深入學(xué)習(xí)FPGA之PS2鍵盤驅(qū)動在我們的電子系統(tǒng)中,當(dāng)需要用到大量的按鍵輸入時,普通的獨(dú)立按鍵和矩陣鍵盤已經(jīng)無法滿足我們的輸入需求,這個時候,我們需要使用一種功能更加強(qiáng)大的鍵盤,來幫助我們輸入更多的信息。在pc機(jī)上,我們經(jīng)常使用104鍵的鍵盤,這種鍵盤與pc機(jī)的接口,可分為USB接口和PS2接口,我們FPGA要實現(xiàn)USB接口比較困難,因為USB的接口線路,不是標(biāo)準(zhǔn)的TTL電平,而PS2接口,則使用標(biāo)準(zhǔn)的TTL電平,那么我們今天就使用FPGA來解碼驅(qū)動一個采用PS2接口的pc機(jī)鍵盤,用這個鍵盤來擴(kuò)展我們FPGA的輸入系統(tǒng),以使我們能夠方便的輸入更多的信息。一、 實驗?zāi)康膶崿F(xiàn)采用PS

2、2協(xié)議的PC機(jī)鍵盤的解碼,最終將PS2鍵盤作為FPGA系統(tǒng)的一個標(biāo)準(zhǔn)輸入設(shè)備。二、 實驗原理PS2鍵盤的內(nèi)部結(jié)構(gòu)我們不需要過多的去關(guān)注,我們只需要關(guān)心其接口協(xié)議,正確的解碼其發(fā)送過來的按鍵信息即可,至于解碼到的按鍵信息該怎么處理,不同的應(yīng)用有不同的處理方式,這里就不做過多的介紹。PS2協(xié)議的簡單描述如下:PS2協(xié)議總共由兩根線組成,一根時鐘線和一根數(shù)據(jù)線。這里我們將采用PS2協(xié)議的鍵盤稱為從機(jī),將控制和解碼PS2協(xié)議的一方成為主機(jī),生活中最常見的主機(jī)便是我們的PC機(jī)。PS2總線協(xié)議的兩根線中,時鐘線傳輸時鐘信號,該時鐘信號始終由從機(jī),即鍵盤產(chǎn)生。PS2協(xié)議發(fā)送一個字節(jié)的數(shù)據(jù)總共有11位,分別為

3、1位起始位8位數(shù)據(jù)位1位校驗位1位停止位PS2從機(jī)發(fā)送一個完整數(shù)據(jù)包的時序圖如下所示:圖2-1 PS2從機(jī)發(fā)送數(shù)據(jù)時序圖相信熟悉UART協(xié)議的同學(xué)一眼就能看出來,PS2協(xié)議和我們最熟悉的UART通信協(xié)議非常相似,那么我們的工作就簡單了,既然鍵盤按照這個協(xié)議發(fā)送數(shù)據(jù),我們FPGA作為主機(jī),只需要正確的實現(xiàn)該協(xié)議的解碼,將其中的8位數(shù)據(jù)位讀取出來即可。由圖可知,數(shù)據(jù)在時鐘的下降沿處是穩(wěn)定的,因此我們只需要去捕獲時鐘信號的下降沿,并在檢測到這個下降沿時去讀取數(shù)據(jù)線上的電平,就能夠正確的讀到數(shù)據(jù)。以上是PS2協(xié)議中從機(jī)到主機(jī)的一個通訊過程,實際在PS2協(xié)議中,包含了從機(jī)到主機(jī)和主機(jī)到從機(jī)的通信時序,只

4、是在我們進(jìn)行PS2鍵盤的解碼時,可以不需要進(jìn)行主機(jī)到從機(jī)的通信,因此這部分內(nèi)容小梅哥就不在這里講解了,如果大家以后要解碼PS2鼠標(biāo)的話,就會用到主機(jī)到從機(jī)的通信了。上面只是簡單的介紹了PS2從機(jī)到主機(jī)的通信協(xié)議,我們知道了鍵盤是一個字節(jié)一個字節(jié)的往主機(jī)發(fā)送數(shù)據(jù)的,但是,每個字節(jié)代表了什么內(nèi)容呢,我們還需要對照鍵盤編碼對照表來查看。鍵盤掃描碼分為第一套掃描碼、第二套掃描碼和第三套掃描碼,我們?nèi)粘I钪谐R姷膾呙璐a絕大多數(shù)采用第二套掃描碼,因此這里小梅哥就只附上第二套掃描碼的內(nèi)容。實際一個按鍵由按下到釋放時鍵盤將按照如下的規(guī)定往主機(jī)發(fā)送數(shù)據(jù):只要一個鍵被按下,這個鍵的通碼(MAKE)就被發(fā)送到計算

5、機(jī)。通碼只表示鍵盤上的一個按鍵,它不表示印刷在按鍵上的那個字符。 這就意味著在通碼和ASCII碼之間沒有已定義好的關(guān)聯(lián), 直到主機(jī)把掃描碼翻譯成一個字符或命令。 雖然多數(shù)第二套通碼都只有一個字節(jié)寬,但也有少數(shù)“ 擴(kuò)展按鍵”的通碼是兩字節(jié)或四字節(jié)寬,這類的通碼第一個字節(jié)總是為E0H(如“END”、“HOME”)。正如鍵按下通碼就被發(fā)往計算機(jī)一樣, 只要鍵一釋放, 斷碼就會被發(fā)送。每個鍵都有它自己唯一的通碼,它們也都有唯一的斷碼。 幸運(yùn)的是,你不用總是通過查表來找出按鍵的斷碼 在通碼和斷碼之間存在著必然的聯(lián)系。 多數(shù)第二套斷碼有兩字節(jié)長,它們的第一個字節(jié)是F0H, 第二個字節(jié)是這個鍵的通碼。例如,

6、當(dāng)我們按下鍵盤上的“A”鍵時,鍵盤就會往主機(jī)發(fā)送”A”鍵對應(yīng)的通碼(MAKE)”1C”,如果你一直按下這個按鍵不釋放,那么在一個短暫的延時之后,鍵盤會再次開始,以一定的速率持續(xù)向主機(jī)發(fā)送”1C“,直到該按鍵被釋放。在該按鍵被釋放后,鍵盤將會向主機(jī)發(fā)送“A ”的斷碼(Break),即首先發(fā)送“F0”,然后下一個字節(jié)再馬上發(fā)送“1C”。如果我們按下的是“END”、“PAGE UP”等擴(kuò)展按鍵時,會怎么樣呢?這里,以”END”鍵舉例。當(dāng)”END“鍵被按下后,鍵盤會首先向主機(jī)發(fā)送“E0”,發(fā)送完成后,又會接著發(fā)送下一個字節(jié)“69”,釋放時也與前面的普通按鍵類似,先發(fā)送“E0”,然后發(fā)送“F0”,最后再

7、發(fā)送“69”。由上述分析可知,我們FPGA在解碼到一次數(shù)據(jù)后,還需要對這個數(shù)據(jù)進(jìn)行分析判斷,判斷該數(shù)據(jù)是否為斷碼標(biāo)志“F0”以及擴(kuò)展碼標(biāo)志”E0“。 三、 硬件設(shè)計PS2電路結(jié)構(gòu)簡單,因此這里就略去。四、 架構(gòu)設(shè)計本實驗我們進(jìn)行PS2鍵盤的解碼實驗,并將解碼到的結(jié)果顯示在數(shù)碼管上,同時,為了使我們更加直觀的感受到按鍵被按下和釋放,小梅哥在這里增加了一個蜂鳴器,當(dāng)有按鍵按下或釋放(包括長按時每接收到一個通碼)時,蜂鳴器發(fā)出一個短暫的響聲,來反饋給操作者,讓我們知道我們的解碼模塊解碼到了按鍵信息。設(shè)計結(jié)構(gòu)如下圖所示:Key_DispDig_Led_seg7:0Dig_Led_sel2:0Rst_n

8、Data23:0DIG_LED_DriverClkBeepBeep14d0Beep_EnPS2_Key_Board_DriverKey_FlagKey_Value9:0PS2_DinPS2_Clk圖4-1 led實驗?zāi)K組織結(jié)構(gòu)圖詳細(xì)端口名及其意義如下端口說明端口名端口功能或意義Rst_n全局復(fù)位Clk系統(tǒng)時鐘輸入端口Dig_Led_sel數(shù)碼管位選輸出,接三八譯碼器Dig_Led_seg數(shù)碼管段選輸出,接數(shù)碼管8個段PS2_DinPS2數(shù)據(jù)線PS2_ClkPS2時鐘線表4-1 獨(dú)立按鍵檢測實驗端口說明因為存在模塊間的連接,因此有部分內(nèi)部信號,下表為內(nèi)部信號的名稱和功能說明內(nèi)部信號說明內(nèi)部信號

9、名內(nèi)部信號功能或意義Data數(shù)碼管待顯示數(shù)據(jù),共24位,含每4位組成一個BCD碼,對應(yīng)一個數(shù)碼管需要顯示的數(shù)據(jù)內(nèi)容,這里高14位接0,低10位接到了Key_Value上,以顯示Key_Value的值。Key_Value按鍵檢測結(jié)果輸出,總共10位,其中最高位為通/斷碼標(biāo)志位,為0表示通碼,為1表示斷碼;次高位為短碼和長碼(擴(kuò)展碼)標(biāo)志位,為0表示短碼,為1表示長碼;低8位為數(shù)據(jù)位。Beep_En蜂鳴器鳴叫使能信號,為高則使能一次鳴叫,這里接到了Key_Flag上,因此,只要一成功解碼到一次按鍵事件(按下、釋放或長按時的每一次數(shù)據(jù)發(fā)送)Key_Flag按鍵檢測成功標(biāo)志信號表4-2 獨(dú)立按鍵檢測實

10、驗內(nèi)部信號說明五、 代碼分析這里,解碼的關(guān)鍵是PS2接口的時鐘信號,該時鐘為異步時鐘,我們需要通過邊沿檢測的方式來檢測其下降沿,以便根據(jù)下降沿的個數(shù)來確定每個時鐘我們因該做什么,邊沿檢測的電路,前面幾個實驗已經(jīng)講過很多次了,這里便不再做過多的解釋,貼上代碼即可:reg PS2_Clk_Tmp0,PS2_Clk_Tmp1,PS2_Clk_Tmp2,PS2_Clk_Tmp3;wire nedge_PS2_Clk;/*PS2從機(jī)時鐘下降沿檢測標(biāo)志信號*/always (posedge Clk or negedge Rst_n)if(!Rst_n) beginPS2_Clk_Tmp0 <= 1&

11、#39;b0;PS2_Clk_Tmp1 <= 1'b0;PS2_Clk_Tmp2 <= 1'b0;PS2_Clk_Tmp3 <= 1'b0;endelse beginPS2_Clk_Tmp0 <= PS2_Clk;PS2_Clk_Tmp1 <= PS2_Clk_Tmp0;PS2_Clk_Tmp2 <= PS2_Clk_Tmp1;PS2_Clk_Tmp3 <= PS2_Clk_Tmp2;end/*-獲取PS時鐘信號的下降沿-*/assign nedge_PS2_Clk = !PS2_Clk_Tmp0 & !PS2_Clk_

12、Tmp1 & PS2_Clk_Tmp2 & PS2_Clk_Tmp3;一個PS2的數(shù)據(jù)包總共由11位組成,因此會有11個時鐘下降沿,因此我們必須對下降沿的個數(shù)準(zhǔn)確計數(shù),才能保證我們能夠解碼得到正確的數(shù)據(jù),這里,使用我們的PS2時鐘下降沿標(biāo)志信號來使能我們的計數(shù)器自加,當(dāng)計數(shù)器加到11后,表示一個數(shù)據(jù)包接收完成,將計數(shù)器清零,等待下一個下降沿的到來,相關(guān)代碼如下:/*-PS2時鐘下降沿個數(shù)計數(shù)器-*/always (posedge Clk or negedge Rst_n)if(!Rst_n)Cnt1 <= 4'd0;else if(Cnt1 = 4'd11

13、)Cnt1 <= 4'd0;else if(nedge_PS2_Clk)Cnt1 <= Cnt1 + 1'b1;接下來,就是根據(jù)時鐘下降沿的計數(shù)個數(shù),來讀取對應(yīng)位的數(shù)據(jù)了,因為采用了非阻塞賦值的方式,因此,PS2時鐘下降沿到來時,此時Cnt1執(zhí)行自加1操作,但同時如果也來用Cnt1的值來確定數(shù)據(jù)位數(shù),就一定會造成錯誤,因為此時,Cnt1的加1操作并沒有執(zhí)行,而是會在下一個時鐘上升沿到來之時才變,因此,為了保證我們使用的Cnt1的數(shù)據(jù)是已經(jīng)更新了的,我們需要在Cnt1已經(jīng)變化之后再來使用其值做判斷,即在PS2時鐘下降沿檢測成功后,滯后一個系統(tǒng)時鐘周期后再來讀取PS2_

14、Din上的值,比較簡單的操作方式就是將PS2時鐘下降沿檢測標(biāo)志信號再用寄存器打一拍,對應(yīng)代碼如下:always (posedge Clk)nedge_PS2_Clk_Shift <= nedge_PS2_Clk;可能這里相對比較難以理解,希望大家結(jié)合仿真結(jié)果自學(xué)揣摩體會。接下來就是根據(jù)Cnt1的計數(shù)值來讀取每一位的數(shù)據(jù)了,這部分代碼很簡單,如下所示:/*-讀取8位數(shù)據(jù)位-*/always (posedge Clk or negedge Rst_n)if(!Rst_n)Data_tmp <= 8'd0;else if(nedge_PS2_Clk_Shift) begincas

15、e(Cnt1)4'd2:Data_tmp0 <= PS2_Din;4'd3:Data_tmp1 <= PS2_Din;4'd4:Data_tmp2 <= PS2_Din;4'd5:Data_tmp3 <= PS2_Din;4'd6:Data_tmp4 <= PS2_Din;4'd7:Data_tmp5 <= PS2_Din;4'd8:Data_tmp6 <= PS2_Din;4'd9:Data_tmp7 <= PS2_Din;default:Data_tmp <= Data_t

16、mp;endcaseendelseData_tmp <= Data_tmp;通過以上操作,我們就能正確的解碼PS2鍵盤發(fā)送過來的每一個字節(jié)的數(shù)據(jù)了,但是,這些數(shù)據(jù)代表了什么呢,如果是斷碼標(biāo)志,或者是長碼標(biāo)志,我們又該如何進(jìn)行操作呢,這里,小梅哥先貼上我的處理代碼:always (posedge Clk or negedge Rst_n)if(!Rst_n) beginBreak_r <= 1'b0;Key_Valve <= 10'd0;Key_Flag <= 1'b0;Long_Code_r <= 1'b0;endelse if(C

17、nt1 = 4'd11) beginif(Data_tmp = 8'hE0)/*判斷是否為長碼*/Long_Code_r <= 1'b1;/*將長碼標(biāo)志置1*/else if(Data_tmp = 8'hF0)/*判斷是否為斷碼*/Break_r <= 1'b1;/*將斷碼標(biāo)志置1*/else begin/*檢測到的數(shù)據(jù)為通碼*/Key_Valve <= Break_r,Long_Code_r,Data_tmp;/*將長碼標(biāo)志、斷碼標(biāo)志和解碼到的按鍵碼輸出*/Key_Flag <= 1'b1;/*產(chǎn)生解碼成功標(biāo)志信號*/L

18、ong_Code_r <= 1'b0;/*清零長碼標(biāo)志*/Break_r <= 1'b0;/*清零斷碼標(biāo)志*/endendelse beginKey_Valve <= Key_Valve;Key_Flag <= 1'b0;Break_r <= Break_r;Long_Code_r <= Long_Code_r;end這里,小梅哥使用了兩個標(biāo)志寄存器,當(dāng)檢測數(shù)據(jù)完成后,即Cnt1=11時,就對解碼到到數(shù)據(jù)進(jìn)行判斷,如果Data_tmp = 8'hE0,則解碼到到數(shù)據(jù)為長碼(擴(kuò)展碼)標(biāo)志,此時便將長碼標(biāo)志寄存器置1,如果Data

19、_tmp = 8'hF0,則解碼到到數(shù)據(jù)為斷碼標(biāo)志,此時便將斷碼標(biāo)志寄存器置1。然后,當(dāng)解碼到其他數(shù)據(jù)(如單字節(jié)通碼或雙子節(jié)通碼的第二個字節(jié))后,便將解碼到的數(shù)據(jù)連同斷碼和長碼標(biāo)志寄存器的狀態(tài)輸出,并給出按鍵檢測成功標(biāo)志(Key_Flag置1)。六、 仿真分析為了對小梅哥設(shè)計的PS2鍵盤解碼驅(qū)動進(jìn)行驗證,小梅哥編寫了一個Testbench來模擬鍵盤發(fā)送數(shù)據(jù),通過觀察鍵盤解碼驅(qū)動的輸出來驗證該解碼模塊的正確性,關(guān)于模擬鍵盤發(fā)送數(shù)據(jù),在一份介紹PS2協(xié)議的手冊中有如下描述:我推薦仿真鍵盤/鼠標(biāo)采用下面的過程發(fā)送一字節(jié)的數(shù)據(jù)到主機(jī):1) 等待Clock線為高電平, 即等待主機(jī)釋放Clock線

20、;2) 延時50us;3) 判斷Clock線是否為高電平?No 跳到第1步;4) Data線是否為高電平?No 放棄(跳到從主機(jī)讀取字節(jié)的程序中) 。5) 延遲20us,輸出起始位(0) , 然后延遲20us, 再拉低Clock線保持40us后釋放Clock線, 形成一個脈沖;6) 延時20us, 測試Clock線是否為高電平?No 跳到第1步;7) 輸出第1個數(shù)據(jù)位, 然后延時20us, 再拉低Clock線保持40us后釋放Clock線, 形成一個脈沖;8) 重復(fù)6-7步發(fā)送剩下的7個數(shù)據(jù)位和校驗位;9) 延時20us, 測試Clock線是否為高電平?No 跳到第1步;因此,我們的模擬鍵盤發(fā)

21、送數(shù)據(jù)的過程只需要依照上面的流程來即可,這里貼上小梅哥編寫的testbench:timescale 1ns/1nsmodule PS2_Key_Board_Driver_tb;reg Clk;/*system clock*/reg Rst_n;/*復(fù)位信號*/reg PS2_Din;/*PS2鍵盤數(shù)據(jù)線*/reg PS2_Clk;/*PS2鍵盤時鐘線*/wire Key_Flag;/*解碼得到鍵值標(biāo)志信號*/wire 9:0 Key_Valve;/*解碼結(jié)果,其中最高位為通/斷碼識別位,0為通碼,1為斷碼,低八位為碼值*/PS2_Key_Board_Driver u1(.Clk(Clk),.R

22、st_n(Rst_n),.PS2_Din(PS2_Din),.PS2_Clk(PS2_Clk),.Key_Flag(Key_Flag),.Key_Valve(Key_Valve);initial beginClk = 1;Rst_n = 0;PS2_Din = 1;PS2_Clk = 1;#200;Rst_n = 1;Key_Event(8'h1A);/* Z */#400;Key_Event(8'h35);/* X */#800;Key_Event(8'h44);/* O */#1320;Key_Event(8'h4D);/* P */#2560;Key_Ev

23、ent(8'h24);/* E */#1230;Key_Event(8'h31);/* N */#20000;Long_Key_Event(8'h70);/* "INSERT" */#400;Long_Key_Event(8'h6c);/* "HOME" */#800;Long_Key_Event(8'h7d);/* "PAGE UP" */#1320;Long_Key_Event(8'h71);/* "DELETE" */#2560;Long_Key_Event(8

24、'h69);/* "END" */#1230;Long_Key_Event(8'h7a);/* "PAGE DOWN" */#2000000;$stop;end/*-生成工作時鐘-*/always #10 Clk = Clk;/*-任務(wù):以PS2協(xié)議發(fā)送一個字節(jié)的數(shù)據(jù)-*/task Send_data;input 7:0Data;beginPS2_Din = 0;/*發(fā)送起始位*/#20000;PS2_Clk = 0;#40000;PS2_Clk = 1;#20000;PS2_Din = Data0;/*發(fā)送第0位*/#20000;PS2

25、_Clk = 0;#40000;PS2_Clk = 1;#20000;PS2_Din = Data1;/*發(fā)送第1位*/#20000;PS2_Clk = 0;#40000;PS2_Clk = 1;#20000;PS2_Din = Data2;/*發(fā)送第2位*/#20000;PS2_Clk = 0;#40000;PS2_Clk = 1;#20000;PS2_Din = Data3;/*發(fā)送第3位*/#20000;PS2_Clk = 0;#40000;PS2_Clk = 1;#20000;PS2_Din = Data4;/*發(fā)送第4位*/#20000;PS2_Clk = 0;#40000;PS2_

26、Clk = 1;#20000;PS2_Din = Data5;/*發(fā)送第5位*/#20000;PS2_Clk = 0;#40000;PS2_Clk = 1;#20000;PS2_Din = Data6;/*發(fā)送第6位*/#20000;PS2_Clk = 0;#40000;PS2_Clk = 1;#20000;PS2_Din = Data7;/*發(fā)送第7位*/#20000;PS2_Clk = 0;#40000;PS2_Clk = 1;#20000;PS2_Din = 0;/*暫時忽略校驗位*/#20000;PS2_Clk = 0;#40000;PS2_Clk = 1;#20000;PS2_Din = 1;/*停止位*/#20000;PS2_Clk = 0;#40000;

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論