設(shè)計(jì)背景:
PS2接口是一種PC兼容型電腦系統(tǒng)上的接口,可以用來鏈接鍵盤及鼠標(biāo)。PS2的命名來自于1987年時(shí)IBM所推出的個(gè)人電腦:PS/2系列。PS2的鍵盤和鼠標(biāo)在電氣特性上十分類似,主要差別在于鍵盤接口需要雙向的溝通。PS2接口不支持熱插拔,使用時(shí)需要關(guān)機(jī)插上,目前已逐漸被USB所替代,只有少部分臺(tái)式機(jī)仍然提供PS2接口。
設(shè)計(jì)原理:
PS2的接口如下圖所示:
上圖中,1是數(shù)據(jù)線DATA;2是預(yù)留N/C;3是GND;4是VCC(+5V);5是時(shí)鐘信號(hào)線CLK;6是預(yù)留N/C。
PS2原理電路圖如下:
PS2協(xié)議總共由兩根線組成,從電路原理圖中也可以看出,需要控制的只有PS2_CLK和PS2_SDA,即一根時(shí)鐘線和一根數(shù)據(jù)線。PS2設(shè)備中的時(shí)鐘和數(shù)據(jù)都是集電極開路的,平時(shí)都是高電平。本設(shè)計(jì)將采用PS2接口的鍵盤稱為從機(jī),將控制和解碼PS2協(xié)議的一方稱為主機(jī)(FPGA)。PS2協(xié)議的時(shí)鐘線始終由從機(jī)(即鍵盤)產(chǎn)生的,PS2協(xié)議發(fā)送一個(gè)字節(jié)數(shù)據(jù)共有11位。時(shí)序如下圖所示:
1Bit起始位,總是0;8Bit數(shù)據(jù)位,低位在前;1Bit校驗(yàn)位,奇校驗(yàn);1Bit停止位,總是1。
從機(jī)(鍵盤)按照這個(gè)時(shí)序發(fā)送數(shù)據(jù),主機(jī)(FPGA)只需要實(shí)現(xiàn)該協(xié)議的解碼,即可將其中的8Bit數(shù)據(jù)位提取出來。根據(jù)時(shí)序圖可以看出,數(shù)據(jù)在PS2時(shí)鐘的下降沿是保持穩(wěn)定的,主機(jī)只需在檢測(cè)到PS2時(shí)鐘出現(xiàn)下降沿時(shí),去讀取數(shù)據(jù)線上的電平,就可得到正確的數(shù)據(jù)。
通過上述的內(nèi)容,已經(jīng)知道了PS2從機(jī)到主機(jī)的通信協(xié)議,接下來就需要知道從機(jī)發(fā)送過來的每個(gè)字節(jié)代表什么?這時(shí)就要對(duì)照鍵盤編碼表進(jìn)行查看。鍵盤上一個(gè)按鍵由按下到釋放時(shí),鍵盤是按照如下的規(guī)定向主機(jī)發(fā)送數(shù)據(jù)的:
只要一個(gè)按鍵被按下,這個(gè)鍵的通碼(MAKE)就會(huì)被發(fā)送到主機(jī),按鍵一被釋放,斷碼(BREAK)也會(huì)被發(fā)送,如果按鍵被按下不釋放的話,鍵盤會(huì)以一定的頻率發(fā)送那個(gè)按鍵的通碼。每個(gè)按鍵都有自己唯一的通碼和斷碼,從而組成鍵盤編碼表,表上的碼值為16進(jìn)制:
例如,如果鍵盤上‘A’鍵被按下時(shí),鍵盤就會(huì)向主機(jī)發(fā)送‘A’鍵對(duì)應(yīng)的通碼‘1C’,直到按鍵被釋放。在按鍵被釋放后,鍵盤將會(huì)向主機(jī)發(fā)送‘A’鍵的斷碼,即首先發(fā)送‘F0’,然后下一個(gè)字節(jié)發(fā)送‘1C’。通過觀察鍵盤編碼表,可以發(fā)現(xiàn)按鍵的通碼與斷碼存在一定的聯(lián)系,多數(shù)斷碼的第一個(gè)字節(jié)是‘F0’,第二個(gè)字節(jié)則是這個(gè)鍵的通碼。
如果按下鍵盤上的擴(kuò)展按鍵時(shí),如‘END’,當(dāng)‘END’鍵被按下后,鍵盤會(huì)首先向主機(jī)發(fā)送‘E0’,然后發(fā)送‘F0’,最后再發(fā)送‘69’。 根據(jù)上述的分析可知,在主機(jī)(FPGA)解碼一次數(shù)據(jù)后,還需要對(duì)這個(gè)數(shù)據(jù)進(jìn)行分析判斷,判斷該數(shù)據(jù)是否為斷碼標(biāo)志‘F0’以及擴(kuò)展碼標(biāo)志‘E0’。
設(shè)計(jì)架構(gòu)圖:
本設(shè)計(jì)將實(shí)現(xiàn)在PS2鍵盤上按下26個(gè)字母任一個(gè),在數(shù)碼管上顯示其對(duì)應(yīng)的ASCII碼。架構(gòu)圖如下:
ps2scan模塊是根據(jù)PS2的時(shí)序協(xié)議,將鍵盤的按鍵值譯成一個(gè)8位的數(shù)據(jù)(out_data)輸出;ASCII模塊,根據(jù)ASCII表,將數(shù)據(jù)與字母一一對(duì)應(yīng);seg_num模塊將相應(yīng)的數(shù)據(jù)在數(shù)碼管上顯示。
設(shè)計(jì)代碼:
ps2scan模塊代碼:
0moduleps2scan (clk,rst_n,ps2_sclk,ps2_sda,out_data);
1
2//端口信號(hào):模塊的輸入輸出接口
3inputclk;//系統(tǒng)時(shí)鐘
4inputrst_n;//低電平復(fù)位
5inputps2_sclk;//ps2時(shí)鐘信號(hào)(ps2設(shè)備自動(dòng)產(chǎn)生,大約10KHz左右)
6inputps2_sda;//ps2數(shù)據(jù)信號(hào)
7outputreg[7:0]out_data;//鍵值數(shù)據(jù)(采集ps2的一幀信號(hào)中間的8位有效位)
8
9//在發(fā)送時(shí)序中,數(shù)據(jù)在ps2_sclk的下降沿采集信號(hào),以下為檢測(cè)下降沿
10regin1,in2;
11wireen;
12
13always@(posedgeclk ornegedgerst_n)
14begin
15if(!rst_n)
16begin
17in1 <=1'b0;
18in2 <=1'b0;
19end
20else
21begin
22in1 <=ps2_sclk;
23in2 <=in1;
24end
25end
26
27assignen =(~in1)&in2;//當(dāng)出現(xiàn)ps2_sclk下降沿后拉高一個(gè)時(shí)鐘,以進(jìn)行數(shù)據(jù)的采集
28
29
30//采集ps2的一幀信號(hào)中間的8位有效位:每檢測(cè)一個(gè)下降沿算一位數(shù)據(jù)位,在中間8位采集有效數(shù)據(jù)
31reg[7:0]temp_data;
32reg[3:0]num;
33
34always@(posedgeclk ornegedgerst_n)
35begin
36if(!rst_n)
37begin
38num <=4'd0;
39temp_data <=8'd0;
40end
41elseif(en)
42case(num)
434'd0:num <=num+1'b1;//開始位
444'd1:begin
45num <=num+1'b1;
46temp_data[0]<=ps2_sda;//bit0
47end
484'd2:begin
49num <=num+1'b1;
50temp_data[1]<=ps2_sda;//bit1
51end
524'd3:begin
53num <=num+1'b1;
54temp_data[2]<=ps2_sda;//bit2
55end
564'd4:begin
57num <=num+1'b1;
58temp_data[3]<=ps2_sda;//bit3
59end
604'd5:begin
61num <=num+1'b1;
62temp_data[4]<=ps2_sda;//bit4
63end
644'd6:begin
65num <=num+1'b1;
66temp_data[5]<=ps2_sda;//bit5
67end
684'd7:begin
69num <=num+1'b1;
70temp_data[6]<=ps2_sda;//bit6
71end
724'd8:begin
73num <=num+1'b1;
74temp_data[7]<=ps2_sda;//bit7
75end
764'd9:num <=num+1'b1;//結(jié)束位
774'd10:num <=4'd0;
78default:;
79endcase
80end
81
82//判斷是否有鍵按下:根據(jù)通碼、斷碼的特性判斷
83regkey;
84
85always@(posedgeclk ornegedgerst_n)
86begin
87if(!rst_n)
88key <=1'b0;
89elseif(num==4'd10)
90begin
91if(temp_data ==8'hf0)
92key <=1'b1;
93else
94begin
95if(!key)
96out_data <=temp_data;
97else
98key <=1'b0;
99end
100end
101end
102
103endmodule
ASCII模塊代碼:
0moduleASCII(out_data,tx_out);
1
2//端口信號(hào):模塊的輸入輸出接口
3input[7:0]out_data;//鍵盤的掃描鍵值
4outputreg[7:0]tx_out;//通過ASCII碼轉(zhuǎn)換之后的值
5
6//通過查找表的方式,對(duì)照ASCII碼將鍵值轉(zhuǎn)換為二進(jìn)制數(shù)值
7always@(*)
8case(out_data)
98'h1c:tx_out <=8'h41;//A
108'h32:tx_out <=8'h42;//B
118'h21:tx_out <=8'h43;//C
128'h23:tx_out <=8'h44;//D
138'h24:tx_out <=8'h45;//E
148'h2b:tx_out <=8'h46;//F
158'h34:tx_out <=8'h47;//G
168'h33:tx_out <=8'h48;//H
178'h43:tx_out <=8'h49;//I
188'h3b:tx_out <=8'h4a;//J
198'h42:tx_out <=8'h4b;//K
208'h4b:tx_out <=8'h4c;//L
218'h3a:tx_out <=8'h4d;//M
228'h31:tx_out <=8'h4e;//N
238'h44:tx_out <=8'h4f;//O
248'h4d:tx_out <=8'h50;//P
258'h15:tx_out <=8'h51;//Q
268'h2d:tx_out <=8'h52;//R
278'h1b:tx_out <=8'h53;//S
288'h2c:tx_out <=8'h54;//T
298'h3c:tx_out <=8'h55;//U
308'h2a:tx_out <=8'h56;//V
318'h1d:tx_out <=8'h57;//W
328'h22:tx_out <=8'h58;//X
338'h35:tx_out <=8'h59;//Y
348'h1a:tx_out <=8'h5a;//Z
35default:tx_out <=8'h00;
36endcase
37
38endmodule
seg_num模塊代碼:
0moduleseg_num (clk,rst_n,num,sel,seg);
1
2//端口信號(hào):模塊的輸入輸出接口
3inputclk;//系統(tǒng)時(shí)鐘50MHz
4inputrst_n;//低電平復(fù)位
5input[7:0]num;//輸入的數(shù)據(jù)
6outputreg[2:0]sel;//數(shù)碼管位選
7outputreg[7:0]seg;//數(shù)碼管段選
8
9
10//計(jì)數(shù)分頻,通過選擇cnt的相應(yīng)位的變化來大致分頻
11reg[23:0]cnt;
12wireclk_r;
13
14always@(posedgeclk ornegedgerst_n)
15begin
16if(!rst_n)
17cnt <=24'd0;
18else
19cnt <=cnt +1'b1;
20end
21
22assignclk_r =cnt[15];//通過計(jì)數(shù)cnt的第10位來分頻計(jì)數(shù),2^10/50M
23//通過查找表的方式將數(shù)據(jù)與相應(yīng)的數(shù)碼管顯示一一對(duì)應(yīng)
24reg[3:0]data;
25
26always@(*)
27case(data)
284'h0:seg <=8'hC0;//8'b1100_0000
294'h1:seg <=8'hF9;//8'b1111_1001
304'h2:seg <=8'hA4;//8'b1010_0100
314'h3:seg <=8'hB0;//8'b1011_0000
324'h4:seg <=8'h99;//8'b1001_1001
334'h5:seg <=8'h92;//8'b1001_0010
344'h6:seg <=8'h82;//8'b1000_0010
354'h7:seg <=8'hF8;//8'b1111_1000
364'h8:seg <=8'h80;//8'b1000_0000
374'h9:seg <=8'h90;//8'b1001_0000
384'hA:seg <=8'h88;
394'hB:seg <=8'h83;
404'hC:seg <=8'hC6;
414'hD:seg <=8'hA1;
424'hE:seg <=8'h86;
434'hF:seg <=8'h8E;
44default:seg <=8'hFF;//8'b1111_1111
45endcase
46
47//通過查找表的方式,在不同位選下,顯示數(shù)據(jù)的相應(yīng)位
48always@(*)
49begin
50case(sel)
51000:data <=num[7:4];
52001:data <=num[3:0];
53default:;
54endcase
55end
56
57always@(posedgeclk_r ornegedgerst_n)
58begin
59if(!rst_n)
60sel <=3'd0;
61elseif(sel ==3'd1)
62sel <=3'd0;
63else
64sel <=sel +1'b1;
65end
66
67endmodule
top頂層模塊代碼:
0moduletop (clk,rst_n,ps2_sclk,ps2_sda,sel,seg);
1
2//外部接口
3inputclk;//系統(tǒng)時(shí)鐘50MHz
4inputrst_n;//低電平復(fù)位
5inputps2_sclk;//ps2時(shí)鐘
6inputps2_sda;//ps2數(shù)據(jù)
7output[2:0]sel;//數(shù)碼管位選
8output[7:0]seg;//數(shù)碼管段選
9
10wire[7:0]out_data,tx_out;
11
12/*****鍵盤掃描模塊*****/
13ps2scan ps2scan_inst(
14.clk(clk),
15.rst_n(rst_n),
16.ps2_sclk(ps2_sclk),
17.ps2_sda(ps2_sda),
18.out_data(out_data)
19);
20
21/*****數(shù)據(jù)轉(zhuǎn)ASCII碼模塊*****/
22ASCII ASCII_inst(
23.out_data(out_data),
24.tx_out(tx_out)
25);
26
27/*****數(shù)碼管顯示模塊*****/
28seg_num seg_num_inst(
29.num(tx_out),
30.clk(clk),
31.rst_n(rst_n),
32.sel(sel),
33.seg(seg)
34);
35
36endmodule
top_tb頂層測(cè)試代碼:
0`timescale1ns/1ns
1
2moduletop_tb;
3
4regclk;
5regrst_n;
6regps2_sda;
7regps2_sclk;
8wire[7:0]seg;
9wire[2:0]sel;
10
11top top_dut(
12.clk(clk),
13.rst_n(rst_n),
14.ps2_sclk(ps2_sclk),
15.ps2_sda(ps2_sda),
16.sel(sel),
17.seg(seg)
18);
19
20initialbegin
21clk =1;
22rst_n =0;
23ps2_sda =1;
24ps2_sclk =1;
25
26#200;
27rst_n =1;
28Key_Event(8'h1A);/* Z */
29#40000;
30Key_Event(8'h22);/* X */
31#80000;
32Key_Event(8'h44);/* O */
33#13200;
34Key_Event(8'h4D);/* P */
35#25600;
36Key_Event(8'h24);/* E */
37#12300;
38Key_Event(8'h31);/* N */
39
40#2000000;
41$stop;
42end
43
44/*---------生成工作時(shí)鐘-----------*/
45always#10clk =~clk;
46
47/*----任務(wù):以PS2協(xié)議發(fā)送一個(gè)字節(jié)的數(shù)據(jù)-----*/
48taskSend_data;
49input[7:0]data;
50begin
51ps2_sda =0;/*發(fā)送起始位*/
52#20000;ps2_sclk =0;
53#40000;ps2_sclk =1;
54
55#20000;ps2_sda =data[0];/*發(fā)送第0位*/
56#20000;ps2_sclk =0;
57#40000;ps2_sclk =1;
58
59#20000;ps2_sda =data[1];/*發(fā)送第1位*/
60#20000;ps2_sclk =0;
61#40000;ps2_sclk =1;
62
63#20000;ps2_sda =data[2];/*發(fā)送第2位*/
64#20000;ps2_sclk =0;
65#40000;ps2_sclk =1;
66
67#20000;ps2_sda =data[3];/*發(fā)送第3位*/
68#20000;ps2_sclk =0;
69#40000;ps2_sclk =1;
70
71#20000;ps2_sda =data[4];/*發(fā)送第4位*/
72#20000;ps2_sclk =0;
73#40000;ps2_sclk =1;
74
75#20000;ps2_sda =data[5];/*發(fā)送第5位*/
76#20000;ps2_sclk =0;
77#40000;ps2_sclk =1;
78
79#20000;ps2_sda =data[6];/*發(fā)送第6位*/
80#20000;ps2_sclk =0;
81#40000;ps2_sclk =1;
82
83#20000;ps2_sda =data[7];/*發(fā)送第7位*/
84#20000;ps2_sclk =0;
85#40000;ps2_sclk =1;
86
87#20000;ps2_sda =0;/*暫時(shí)忽略校驗(yàn)位*/
88#20000;ps2_sclk =0;
89#40000;ps2_sclk =1;
90
91#20000;ps2_sda =1;/*停止位*/
92#20000;ps2_sclk =0;
93#40000;ps2_sclk =1;
94end
95endtask
96
97/*-----任務(wù):模擬按下按鍵的操作------*/
98taskpress_key;
99input[7:0]Key_Number;
100begin
101Send_data(Key_Number);
102#50000;
103end
104endtask
105
106/*-----任務(wù):模擬釋放按鍵的操作------*/
107taskrelease_key;
108input[7:0]Key_Number;
109begin
110Send_data(8'hF0);
111#50000;
112Send_data(Key_Number);
113#50000;
114end
115endtask
116
117/*----任務(wù):模擬一次短碼的按下和釋放操作-----*/
118taskKey_Event;
119input[7:0]Key_Number;
120begin
121press_key(Key_Number);
122#30000;
123release_key(Key_Number);
124end
125endtask
126
127endmodule
仿真圖:
仿真結(jié)果如下圖:
測(cè)試文件中發(fā)送的‘Z’、‘X’、‘O’、‘P’、‘E’、‘N’等字母,在仿真圖中顯示,通過與ASCII碼表對(duì)應(yīng),得知是正確的。分配引腳,下板后,數(shù)碼管也得到了與之對(duì)應(yīng)的ASCII碼值。
-
FPGA
+關(guān)注
關(guān)注
1620文章
21510瀏覽量
598932
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論