|
本帖最后由 skyxjh 于 2013-5-2 21:32 编辑
刚学FPGA,基于红色飓风II开发板实现了4x4键盘翻转法扫描带消抖,4位数码管动态扫描显示,模块化设计,方便移植。
module ledbeepkeypad ( //顶层模块
input clk, //时钟50MHz
input rst, //复位信号,低电平复位
inout [7:0] keypad, //4x4键盘行线[7:4]列线[3:0]
output [7:0] ledd, //数码管段码数据接口
output [3:0] ledc, //数码管位控制接口
output beep, //蜂鸣器,高电平响,低电平停
);
reg [4:0] keycode = 5'h10; //当前按键编码,5'h0d表示编号为h0d的按键按下,5'h1x表示没有按键按下或非法按键组合
reg [15:0] lednum = 16'h1234; //4位数码管显示数据BCD码
reg [3:0] dotpoint = 4'b0000; //小数点,1表示对应位小数点显示
reg [18:0] cnt = 19'd0; //19位记数器,用于时序控制
always @ (posedge clk) cnt = cnt + 1'b1; //记数器向上记数
keypad4x4scan keypad1(.clk(cnt[18]),.keyp(keypad[7:0]),.keycode(keycode)); //4x4键盘扫描,时钟50M/(2^19)=95Hz
keylogic keylogic1(.rst(rst),.clk(cnt[18]),.keycode(keycode),.beep(beep),.lednum(lednum),.dotpoint(dotpoint)); //按键处理逻辑
led4disp disp1(.clk(cnt[16]),.lednum(lednum),.dotpoint(dotpoint),.ledd(ledd),.ledc(ledc)); //4位数码管显示,时钟50M/(2^17)=381Hz
endmodule
//////////////////////////////////////////////////////////////////
//keyp7 7 8 9 A //
//keyp6 4 5 6 B //
//keyp5 1 2 3 C //
//keyp4 0 F E D //
// keyp3 keyp2 keyp1 keyp0 //
/////////////////////////////////////////////////////////////////
module keypad4x4scan ( //键盘扫描子模块
input wire clk, //时钟>50Hz
inout wire [7:0] keyp, //键盘行(外接上拉电阻)列输入
output reg [4:0] keycode //按键编码
);
reg [7:0] keyc = 8'd0; //按键编码
reg swap = 1'b0; //行列翻转扫描标志
assign keyp = swap ? 8'h0z : 8'hz0; //swap为1时keyp[7:4]输出低电平,keyp[3:0]上拉输入;
//swap为0时keyp[7:4]上拉输入,keyp[3:0]输出低电平;
always @ (posedge clk) begin
case (swap)
1'b1: keyc[3:0] = keyp[3:0]; //swap为1时读取keyp[3:0]电平值
default: keyc[7:4] = keyp[7:4]; //swap为0时读取keyp[7:4]电平值
endcase
swap <= ~swap; //行列翻转
end
always @ (keyc) begin
case (keyc) //按键编码
8'b1110_0111: keycode = 5'h0;
8'b1101_0111: keycode = 5'h1;
8'b1011_0111: keycode = 5'h4;
8'b0111_0111: keycode = 5'h7;
8'b1110_1011: keycode = 5'hf;
8'b1101_1011: keycode = 5'h2;
8'b1011_1011: keycode = 5'h5;
8'b0111_1011: keycode = 5'h8;
8'b1110_1101: keycode = 5'he;
8'b1101_1101: keycode = 5'h3;
8'b1011_1101: keycode = 5'h6;
8'b0111_1101: keycode = 5'h9;
8'b1110_1110: keycode = 5'hd;
8'b1101_1110: keycode = 5'hc;
8'b1011_1110: keycode = 5'hb;
8'b0111_1110: keycode = 5'ha;
default: keycode = 5'h10; //无按键按下或无效按键组合
endcase
end
endmodule
module keylogic( //按键处理子模块
input wire rst, //低电平复位信号
input wire clk, //时钟>50Hz
input wire [4:0] keycode, //按键编码,5'h1x表示无按键按下或无效按键组合,5'h0x表示编号为x的按键按下
output reg [15:0] lednum, //4位数码管显示数据
output reg [3:0] dotpoint, //小数点驱动,1表示对应位显示小数点
output reg beep //蜂鸣器驱动
);
reg keypressdone = 1'b1; //按键已处理标志,1表示已处理,0表示未处理
reg [4:0] keycode1 = 5'h10; //上一次检测到的按键值,用于消抖
always @ (posedge clk) begin
if(rst) begin
if (keycode1 == keycode) begin //连续2次检测到的按键值相同,稳定
if (keycode[4]) begin //确认按键弹起
beep = 1'b0; //按键弹起时蜂鸣器停
keypressdone = 1'b1; //置按键已处理标志,准备处理下一次按键
end
else if (keypressdone) begin //有按键按下,按键处理,只处理1次
lednum = lednum << 4; //数码管前3位显示前3次按键值
lednum[3:0] = keycode1[3:0]; //数码管第4位显示当前按键值
dotpoint = 4'b0100; //小数点后2位数字
beep = 1'b1; //按键按下时蜂鸣器响
keypressdone = 1'b0; //按键未弹起之前按键已处理标志清零
end
else ; //按键已处理
end
else ; //连续2次检测到的按键值不同(抖动)
end
else begin //复位
lednum = 16'd0; //显示清零
dotpoint = 2'd0; //不显示小数点
beep = 1'b0; //蜂鸣器停
end
keycode1 = keycode; //保存当前按键值
end
endmodule
module led4disp( //4位数码管显示子模块
input wire clk, //时钟>240Hz
input wire [15:0] lednum, //4数码管显示数字BCD码
input wire [3:0] dotpoint, //小数点,1表示对应位小数点显示
output reg [7:0] ledd, //数码管段码数据接口
output reg [3:0] ledc //数码管位选接口
);
reg [4:0] ledmsk = 5'h0; //数码管驱动位图索引
reg [1:0] ledbit = 2'd0; //数码管位扫描
always @ (posedge clk) begin //动态扫描4位数码管显示,刷新频率>60Hz
ledbit = ledbit + 1'b1; //位扫描
end
always @ (ledbit,lednum) begin
case (ledbit) //数码管当前位段码
2'd3: ledmsk[3:0] = lednum[15:12]; //第1位
2'd2: ledmsk[3:0] = lednum[11:8]; //第2位
2'd1: ledmsk[3:0] = lednum[7:4]; //第3位
default: ledmsk[3:0] = lednum[3:0]; //第4位
endcase
end
assign ledc = 4'b1 << ledbit; //数码管位选择,阴极加NPN三极管反向控制,高电平位选
assign ledd[7] = (dotpoint[3:0] & ledc[3:0]) ? 1'b1 : 1'b0; //小数点驱动
always @ (ledmsk) begin
case (ledmsk) //共阴极数码管段码数据输出
5'h0: ledd[6:0] = 7'b011_1111; //显示数字0
5'h1: ledd[6:0] = 7'b000_0110; //显示数字1
5'h2: ledd[6:0] = 7'b101_1011; //显示数字2
5'h3: ledd[6:0] = 7'b100_1111; //显示数字3
5'h4: ledd[6:0] = 7'b110_0110; //显示数字4
5'h5: ledd[6:0] = 7'b110_1101; //显示数字5
5'h6: ledd[6:0] = 7'b111_1101; //显示数字6
5'h7: ledd[6:0] = 7'b000_0111; //显示数字7
5'h8: ledd[6:0] = 7'b111_1111; //显示数字8
5'h9: ledd[6:0] = 7'b110_1111; //显示数字9
5'hA: ledd[6:0] = 7'b111_0111; //显示数字A
5'hB: ledd[6:0] = 7'b111_1100; //显示数字B
5'hC: ledd[6:0] = 7'b011_1001; //显示数字C
5'hD: ledd[6:0] = 7'b101_1110; //显示数字D
5'hE: ledd[6:0] = 7'b111_1001; //显示数字E
5'hF: ledd[6:0] = 7'b111_0001; //显示数字F
default: ledd[6:0] = 7'b000_0000; //不显示
endcase
end
endmodule
编辑说明:排版调整 |
阿莫论坛20周年了!感谢大家的支持与爱护!!
知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)
|