PS2键盘扫描码分为通码和断码,按下发送通码,松开发送断码,这期间肯定有抖动,接收通码,然后根据通码(8位)判断按下的是哪个键
最后一个应答位在FPGA不用,所以数据帧取11位 ,8位数据位才是我们需要的,注意它是LSB在前
PS2键盘自带时钟,板子上50m的clk用来控制消抖
任务基本要求:
PS2键盘连接到FPGA,按下键盘某个键,然后在数码管上显示其通码
端口:
input clk,key_clock,data,rst;//其中key_clock是键盘时钟(5脚),data是键盘的数据(1脚)
output [1:0] dig_en;//数码管使能,8位通码,两个数码管显示就OK
output [7:0] dig_data;//数码管 ,共阳,最高位保持为1(随意,可以不要),从高到低是gfedcba.这个可以看自己的开发板管脚安排,随意
代码以及相关思路:(因为是初学verilog,再写一遍,加深印象,)
以下代码接上键盘测试完成。。。。。
----------------------------------------------------------------------------------------------
//ps2键盘编码的复习
module ps2_code(
input clk,
input rst_n,
input key_clock,
input key_data,
output [1:0] dig_en,
output [7:0] dig_data
);
//第一步,消抖以及数码管扫描频率的设定( 在这个频率下,计数,计数位数和使用的数码管个数相关联,然后由这个计数值来决定dig_en的值,就可以完成相关功能)
//跳过20ms,100hz(50_000_000/500_000)是10ms n/2-1=249_999 2^18=262_144
reg [17:0] cnt;
reg clk100hz;
always @ (posedge clk,negedge rst_n)
if(!rst_n) begin
cnt<=18'd0;clk100hz<=1'b0;
end
else if(cnt==18'd249_999) begin
cnt<=18'd0;clk100hz<=~clk100hz;
end
else cnt<=cnt+1'b1;
reg key_tmp1,key_tmp2;
always @(posedge clk,negedge rst_n)
if(!rst_n) begin
key_tmp1<=1'b1;
key_tmp2<=1'b1;
end
else begin
key_tmp1<=key_clock;
key_tmp2<=key_tmp1;
end
/////////////////////////////////////////////////////////
//先写一个串转并的过程,因为key_data是1位1位的送过来的
reg [3:0] cnt2;
reg [10:0] data_r;
reg key_data_r;
always @ (posedge clk,negedge rst_n)
//位数变化用一个计数器,帧11bits
if(!rst_n)
cnt2<=4'd0;
else if((key_tmp1) && (~key_tmp2))begin//按键按下,锁存接受到的数据
data_r[cnt2]<= key_data;
if(cnt2==4'd10) cnt2<=4'd0; //0-10位共11位。写成了0-11,又SB了一次
else cnt2<=cnt2+1'b1;
end
//上面用到if的嵌套,注意细节和begin end就可以了,我就是因为把[]写成了()而出错,看了半天。。。是vhdl的影响
//assign key_data_r = key_data;
wire [3:0] low_data;
wire [3:0] high_data;
assign low_data=data_r[4:1];
assign high_data=data_r[8:5];
//分频1khz(扫描)50_000/50_000/2-1=24_999 2^15=32768
reg [14:0] cnt1;
reg clk1khz;
always @ (posedge clk,negedge rst_n)
if(!rst_n) begin
cnt1<=15'd0;clk1khz<=1'b0;
end
else if(cnt1==15'd24_999) begin
cnt1<=15'd0;clk1khz<=~clk1khz;
end
else cnt1<=cnt1+1'b1;
reg [1:0] cnt3;//dig_en的设定
always @ (posedge clk1khz)
if(cnt3==1) cnt3<=2'd0;
else cnt3<=cnt3+1'b1;
reg [1:0] dig_en_r;
reg [3:0] data;
always @(cnt3)
if(cnt3==2'd0) begin// 第一个数码管有效,并且输出数据位的低4位
dig_en_r<=2'b10;
data<=low_data;
end
else if(cnt3==2'd1) begin
dig_en_r<=2'b01;
data<=high_data;
end
assign dig_en=dig_en_r;
//上面写的是第一个(板子最右边那个)锁存低4位low_data,第二个数码管锁存高四位high_data
////////////////////////////////////////////////////////////////
//数码管显示,查看共阳数码管对照表
reg [7:0] dig_data_r;
always @(data)
case(data)
4'd0:dig_data_r<= 8'hc0;
4'd1:dig_data_r<= 8'hf9;
4'd2:dig_data_r<= 8'ha4;
4'd3:dig_data_r<= 8'hb0;
4'd4:dig_data_r<= 8'h99;
4'd5:dig_data_r<= 8'h92;
4'd6:dig_data_r<= 8'h82;
4'd7:dig_data_r<= 8'hf8;
4'd8:dig_data_r<= 8'h80;
4'd9:dig_data_r<= 8'h90;
4'd10:dig_data_r<= 8'h88;
4'd11:dig_data_r<= 8'h83;
4'd12:dig_data_r<= 8'hc6;
4'd13:dig_data_r<= 8'ha1;
4'd14:dig_data_r<= 8'h86;
4'd15:dig_data_r<= 8'h84;
default:dig_data_r<=8'hc0;
endcase
assign dig_data = dig_data_r;
endmodule
用户1634340 2011-7-30 21:27