工程说明:
(1)在FPGA上设计一个控制电路,用于将ps/2接口的键盘输入的按键显示在VGA接口的屏幕上。
(2)采用verilog作为设计输入,实验平台是Altera公司的DE2-70开发板、quartus Ⅱ 9.0
直接上图:
各模块定义及功能说明如下:
(一)键盘响应模块:
ps2_keyboard.v :
=========================ps2_keyboard模块开始=======================
1 module ps2_keyboard(clk,clrn,ps2_clk,ps2_data,data,char_count);
2 input clk,clrn,ps2_clk,ps2_data;
3 output [7:0] data;//8bit scan code
4 reg [7:0] data;
5 output [5:0] char_count;//input key counter
6 reg [5:0] char_count;
7
8 reg ready;
9 reg [3:0] count; // count ps2_data bits
10 // internal signal, for test
11 reg [9:0] buffer; // ps2_data bits
12 reg last_f0;//last scan code is 0xF0 or not
13 reg [7:0] fifo[7:0]; // data fifo
14 reg [2:0] w_ptr,r_ptr; // fifo write and read pointers
15 // detect falling edge of ps2_clk
16 reg [2:0] ps2_clk_sync;
17
18 always @ (posedge clk)
19 begin
20 ps2_clk_sync <= {ps2_clk_sync[1:0],ps2_clk};
21 end
22 wire sampling = ps2_clk_sync[2] & ~ps2_clk_sync[1];//falling edge:last time 1 this time 0
23
24 always @ (posedge clk)
25 begin
26 if (clrn == 0) // reset
27 begin
28 count <= 0; w_ptr <= 0; r_ptr <= 0; last_f0 <= 1'b0; char_count <= 0;
29 end
30 else if (sampling)
31 begin
32 if (count == 4'd10)//10bits
33 begin
34 if ((!buffer[0]) && ps2_data && (^buffer[9:1]))// start bit, stop bit, odd parity
35 begin
36 if(last_f0)
37 begin
38 fifo[w_ptr] <= buffer[8:1]; // kbd scan code
39 last_f0 <= 1'b0;
40 w_ptr <= w_ptr+3'b1;
41 ready <= 1'b1;
42 end
43 else if(buffer[8:1] == 8'hf0)
44 last_f0 <= 1'b1;
45 else
46 last_f0 <= 1'b0;
47 end
48 count <= 0; // for next
49 end
50 else
51 begin
52 buffer[count] <= ps2_data; // store ps2_data
53 count <= count + 4'b1;
54 end
55 end
56 if ( ready ) // read to output next data
57 begin
58 data <= fifo[r_ptr];
59 if(char_count == 6'd48)
60 char_count <= 6'd1;
61 else
62 char_count <= char_count + 1'b1;
63 r_ptr <= r_ptr + 3'd1;
64 ready <= 1'b0;
65 end
66 end
67 endmodule
=========================ps2_keyboard模块结束=======================
(二)键值解析模块:
(这部分有很多不足,只能解析数字0~9字母A~Z和部分标点符号,无法解析组合键、回车、退格等,有待改进)
encoder6_3.v :
=========================encoder6_3模块开始=========================
1 module encoder6_3(in,out_en,out_skew_x,out_skew_y);
2 input [5:0] in;
3 output reg out_en;
4 output reg [6:0] out_skew_x;//max_skew_x = 120
5 output reg [5:0] out_skew_y;//max_skew_y = 32
6
7 always @ (in) begin
8 if(in <= 0 || in > 48)
9 begin
10 out_en = 1'b0;
11 out_skew_x = 7'd0;
12 out_skew_y = 6'd0;
13 end
14 else if(in < 17)//char_count -> [1,16], the 1st line
15 begin
16 out_en = 1'b1;
17 out_skew_x = ({1'b0,in[5:0]} - 7'd1) << 3;
18 out_skew_y = 6'd0;
19 end
20 else if(in < 33)//char_count -> [17,32],the 2nd line
21 begin
22 out_en = 1'b1;
23 out_skew_x = ({1'b0,in[5:0]} - 7'd17) << 3;
24 out_skew_y = 6'd16;
25 end
26 else//char_count -> [33,48],the 3rd line
27 begin
28 out_en = 1'b1;
29 out_skew_x = ({1'b0,in[5:0]} - 7'd33) << 3;
30 out_skew_y = 6'd32;
31 end
32 end
33
34 endmodule
=========================encoder6_3模块结束=========================
scan_code2dot_matrix.v :
====================scan_code2dot_matrix模块开始======================
1 module scan_code2dot_matrix(scan_code,dot_matrix);
2 input [7:0] scan_code;
3 output reg [127:0] dot_matrix;
4
5 //transfer scan code to dot matrix font
6 always @ (scan_code) begin
7 case (scan_code)//0~9A~Z-,.;[]
8 8'h45 : dot_matrix <= 128'h00000018244242424242424224180000;//0
9 8'h16 : dot_matrix <= 128'h000000107010101010101010107C0000;//1
10 8'h1E : dot_matrix <= 128'h0000003C4242420404081020427E0000;//2
11 8'h26 : dot_matrix <= 128'h0000003C424204180402024244380000;//3
12 8'h25 : dot_matrix <= 128'h000000040C14242444447E04041E0000;//4
13 8'h2E : dot_matrix <= 128'h0000007E404040586402024244380000;//5
14 8'h36 : dot_matrix <= 128'h0000001C244040586442424224180000;//6
15 8'h3D : dot_matrix <= 128'h0000007E444408081010101010100000;//7
16 8'h3E : dot_matrix <= 128'h0000003C4242422418244242423C0000;//8
17 8'h46 : dot_matrix <= 128'h0000001824424242261A020224380000;//9
18 8'h1C : dot_matrix <= 128'h0000001010182828243C444242E70000;//A
19 8'h32 : dot_matrix <= 128'h000000F8444444784442424244F80000;//B
20 8'h21 : dot_matrix <= 128'h0000003E424280808080804244380000;//C
21 8'h23 : dot_matrix <= 128'h000000F8444242424242424244F80000;//D
22 8'h24 : dot_matrix <= 128'h000000FC424848784848404242FC0000;//E
23 8'h2B : dot_matrix <= 128'h000000FC424848784848404040E00000;//F
24 8'h34 : dot_matrix <= 128'h0000003C44448080808E844444380000;//G
25 8'h33 : dot_matrix <= 128'h000000E7424242427E42424242E70000;//H
26 8'h43 : dot_matrix <= 128'h0000007C1010101010101010107C0000;//I
27 8'h3B : dot_matrix <= 128'h0000003E0808080808080808080888F0;//J
28 8'h42 : dot_matrix <= 128'h000000EE444850705048484444EE0000;//K
29 8'h4B : dot_matrix <= 128'h000000E0404040404040404042FE0000;//L
30 8'h3A : dot_matrix <= 128'h000000EE6C6C6C6C5454545454D60000;//M
31 8'h31 : dot_matrix <= 128'h000000C7626252524A4A4A4646E20000;//N
32 8'h44 : dot_matrix <= 128'h00000038448282828282828244380000;//O
33 8'h4D : dot_matrix <= 128'h000000FC424242427C40404040E00000;//P
34 8'h15 : dot_matrix <= 128'h00000038448282828282B2CA4C380600;//Q
35 8'h2D : dot_matrix <= 128'h000000FC4242427C4848444442E30000;//R
36 8'h1B : dot_matrix <= 128'h0000003E4242402018040242427C0000;//S
37 8'h2C : dot_matrix <= 128'h000000FE921010101010101010380000;//T
38 8'h3C : dot_matrix <= 128'h000000E74242424242424242423C0000;//U
39 8'h2A : dot_matrix <= 128'h000000E7424244242428281810100000;//V
40 8'h1D : dot_matrix <= 128'h000000D692929292AAAA6C4444440000;//W
41 8'h22 : dot_matrix <= 128'h000000E7422424181818242442E70000;//X
42 8'h35 : dot_matrix <= 128'h000000EE444428281010101010380000;//Y
43 8'h1A : dot_matrix <= 128'h0000007E840408081020204242FC0000;//Z
44 8'h4E : dot_matrix <= 128'h00000000000000007F00000000000000;//-
45 8'h41 : dot_matrix <= 128'h000000000000000000000000606020C0;//,
46 8'h49 : dot_matrix <= 128'h00000000000000000000000060600000;//.
47 8'h4C : dot_matrix <= 128'h00000000000000100000000000101020;//;
48 8'h54 : dot_matrix <= 128'h001E1010101010101010101010101E00;//[
49 8'h5B : dot_matrix <= 128'h00780808080808080808080808087800;//]
50 default : dot_matrix <= 128'h0;//default;
51 endcase
52 end
53 endmodule
====================scan_code2dot_matrix模块结束======================
(三)存储器模块
ram_48x128.v :
=======================ram_48x128模块开始==========================
1 // Quartus II Verilog Template
2 // Simple Dual Port RAM with separate read/write addresses and
3 // separate read/write clocks
4
5 module ram_48x128//3 lines, 16 chars/line, a char takes 16x8 pixel
6 #(parameter DATA_WIDTH=128, parameter ADDR_WIDTH=6, parameter X_DIS=384, parameter Y_DIS=194)
7 //X_DIS=384=240+96+48, Y_DIS=194=160+32+2, display start:(x,y)=(240,160)
8 (
9 //write port
10 input we, write_clock,clrn,
11 input [6:0] wr_start_x,
12 input [5:0] wr_start_y,
13 input [127:0] char_data, //8bit scan code
14 //read port
15 input [9:0] read_addr_x,read_addr_y,
16 output reg q
17 );
18
19 // Declare the RAM variable
20 reg [DATA_WIDTH-1:0] ram[2**ADDR_WIDTH-17:0];
21
22 integer i,j,k;
23 always @ (posedge write_clock or negedge clrn)
24 begin
25 // Write
26 if (clrn == 0)
27 begin
28 for(i=0; i<48; i=i+1)
29 ram[i] <= 128'b0;
30 end
31 else if (we)
32 begin
33 //write dot matrix font to the ram
34 for(i=0,j=127,k=wr_start_y; i<16; i=i+1,j=j-8,k=k+1)
35 begin
36 ram[k][wr_start_x] <= char_data[j];
37 ram[k][wr_start_x+1] <= char_data[j-1];
38 ram[k][wr_start_x+2] <= char_data[j-2];
39 ram[k][wr_start_x+3] <= char_data[j-3];
40 ram[k][wr_start_x+4] <= char_data[j-4];
41 ram[k][wr_start_x+5] <= char_data[j-5];
42 ram[k][wr_start_x+6] <= char_data[j-6];
43 ram[k][wr_start_x+7] <= char_data[j-7];
44 end
45 end
46 end
47
48 always @ (read_addr_x or read_addr_y)
49 begin
50 // Read Y_DIS <= y < Y_DIS+16 X_DIS <= x < X_DIS + 8
51 if(read_addr_y < Y_DIS || read_addr_y >= Y_DIS+48 || read_addr_x < X_DIS || read_addr_x >= X_DIS+128)
52 q <= 1'b0;
53 else
54 q <= ram[read_addr_y-Y_DIS][read_addr_x-X_DIS];
55 end
56
57 endmodule
=======================ram_48x128模块结束==========================
(四)VGA显示控制模块:
vga_display.v :
=======================vga_display模块开始===========================
1 module vga_display(
2 iCLK_50,iCLRN,iPIXEL,
3 o_ADDR_X,o_ADDR_Y,
4 oVGA_R,oVGA_G,oVGA_B,
5 oVGA_SYNC_N,oVGA_BLANK_N,oVGA_CLOCK,
6 oVGA_HS,oVGA_VS
7 );
8
9 input iCLK_50;
10 input iCLRN;
11 input iPIXEL;
12 output [9:0] o_ADDR_X,o_ADDR_Y;
13 output [9:0] oVGA_R,oVGA_G,oVGA_B;
14 output oVGA_SYNC_N,oVGA_BLANK_N,oVGA_CLOCK;
15 output oVGA_HS,oVGA_VS;
16
17 reg vga_clk;
18 reg [9:0] h_count,v_count;
19 wire video_out;
20
21 //Horizontal Parameter(pixel)
22 parameter H_SYNC_CYC = 96;
23 parameter H_SYNC_BACK = 48;
24 parameter H_SYNC_ACT = 640;
25 parameter H_SYNC_FRONT = 16;
26 parameter H_SYNC_TOTAL = 800;
27 //Virtical parameter(line)
28 parameter V_SYNC_CYC = 2;
29 parameter V_SYNC_BACK = 32;
30 parameter V_SYNC_ACT = 480;
31 parameter V_SYNC_FRONT = 11;
32 parameter V_SYNC_TOTAL = 525;
33 //Start Offset
34 parameter X_START = H_SYNC_CYC + H_SYNC_BACK;
35 parameter Y_START = V_SYNC_CYC + V_SYNC_BACK;
36
37 //oVGA_CLK Generator
38 always @ (posedge iCLK_50 or negedge iCLRN) begin
39 if(iCLRN == 0) vga_clk <= 1'b1;
40 else vga_clk <= ~vga_clk;
41 end
42
43 // H_Sync Counter
44 always @ (posedge vga_clk or negedge iCLRN) begin
45 if(iCLRN==0) h_count <= 10'd0;
46 else if (h_count == H_SYNC_TOTAL) h_count <= 10'd0;
47 else h_count <= h_count + 10'd1;
48 end
49 // V_Sync Counter
50 always @ (posedge vga_clk or negedge iCLRN) begin
51 if(iCLRN==0) v_count <= 10'd0;
52 else if (h_count == H_SYNC_TOTAL) begin
53 if(v_count == V_SYNC_TOTAL) v_count <= 10'd0;
54 else v_count <= v_count + 10'd1;
55 end
56 end
57
58 assign video_out = ((h_count>=X_START)
59 &&(h_count<X_START+H_SYNC_ACT))
60 &&((v_count>=Y_START)
61 &&(v_count<Y_START+V_SYNC_ACT));
62 assign o_ADDR_X = h_count;
63 assign o_ADDR_Y = v_count;
64 assign oVGA_HS = (h_count >= 10'd96);
65 assign oVGA_VS = (v_count >= 10'd2);
66
67 assign oVGA_R = (video_out) ? ((iPIXEL)?10'b0000000000:10'b1111111111):10'b0;
68 assign oVGA_G = (video_out) ? ((iPIXEL)?10'b1111111111:10'b1111111111):10'b0;
69 assign oVGA_B = (video_out) ? ((iPIXEL)?10'b1111111111:10'b1111111111):10'b0;
70 assign oVGA_SYNC_N = 1'b0;
71 assign oVGA_BLANK_N = oVGA_HS & oVGA_VS;
72 assign oVGA_CLOCK = vga_clk;
73 endmodule
=========================vga_display模块结束==========================
注:本文版权属于所有程序猿,你可以将之用于任何目的,转载无需注明出处。
code is open