module keytest (clk, key, ledout, weiout, key_count);
input clk;
input [4:0] key;
output reg [7:0] ledout;
output reg [7:0] weiout;
parameter key_init = 0;
parameter key_delay = 1;
parameter key_check = 2;
reg [15:0] state_clk_count;
output reg [3:0] key_count ;
reg state_clk;
reg [1:0] key_state;
reg [4:0] key_temp;
initial
begin
key_state = key_init;
state_clk = 0;
state_clk_count = 4'b0000;
key_count = 4'b0000;
key_temp = 4'b1111;
ledout = 7'b11000000;
weiout = ~8'b1000_0000;
end
//状态机时钟分频
always @(posedge clk)
begin
state_clk_count <= state_clk_count + 1;
if(state_clk_count == 16'hffff)
state_clk <= ~ state_clk;
end
//状态机
always @(posedge state_clk )
begin
//key_temp <= key; //把键码的值赋给寄存器
case (key_state)
key_init :
if(key == 5'b11111)
key_state <= key_init;
else
key_state <=key_delay;
key_delay :
if(key == 5'b11111)
key_state <= key_init;
else
key_state <=key_check;
key_check :
if(key == 5'b11111) //释放按键后,按键计数+1
begin
key_count <= key_count +1;
key_state <= key_init;
end
else //按键按下时,维持此状态,直到按键释放
begin
key_state <= key_check;
key_temp <= key; //把键码的值赋给寄存器
end
default :
key_state <= key_init;
endcase
end
always @(state_clk or key_count)
begin
case (key_count)
4'b0001 : ledout = 7'b11111001; // 1
4'b0010 : ledout = 7'b10100100; // 2
4'b0011 : ledout = 7'b10110000; // 3
4'b0100 : ledout = 7'b10011001; // 4
4'b0101 : ledout = 7'b10010010; // 5
4'b0110 : ledout = 7'b10000010; // 6
4'b0111 : ledout = 7'b11111000; // 7
4'b1000 : ledout = 7'b10000000; // 8
4'b1001 : ledout = 7'b10010000; // 9
4'b1010 : ledout = 7'b10001000; // A
4'b1011 : ledout = 7'b10000011; // B
4'b1100 : ledout = 7'b11000110; // C
4'b1101 : ledout = 7'b10100001; // D
4'b1110 : ledout = 7'b10000110; // E
4'b1111 : ledout = 7'b10001110;
default : ledout = 7'b11000000;
endcase
end
endmodule
程序如上,主要思想是将按键按下分为几个状态:初始化、延时消抖、按键检测,同时,为了实现按键的计数,在本程序中的key_check状态中,当按键按下时,把键值赋值给键值寄存器,等到按键松开后,才进行键值处理,这样可以较好的实现按键按下计数。当有几个按键时,程序如下所示,思想与上例相同。
module keytest (clk, key, ledout, weiout, key_id,key_count_o);
input clk;
input [4:0] key;
output reg [7:0] ledout;
output reg [7:0] weiout;
output reg [3:0] key_id; //键码
output reg [3:0] key_count_o; //连续按键次数
parameter key_init = 0; //按键状态
parameter key_delay = 1;
parameter key_check = 2;
reg [15:0] state_clk_count; //状态机时钟分频计数
reg [3:0] key_count [4:0]; //5个按键中,每个按键连续按键次数寄存
reg state_clk; //状态机时钟
reg [1:0] key_state; //按键状态寄存
reg [4:0] key_temp; //键值寄存器
initial
begin
key_state = key_init;
state_clk = 0;
state_clk_count = 4'b0000;
key_id = 4'b0000;
key_temp = 4'b1111;
ledout = 7'b11000000;
weiout = ~8'b1000_0000;
end
//状态机时钟分频
always @(posedge clk)
begin
state_clk_count <= state_clk_count + 1;
if(state_clk_count == 16'hffff)
state_clk <= ~ state_clk;
end
//状态机
always @(posedge state_clk )
begin
case (key_state)
key_init :
if(key == 5'b11111)
key_state <= key_init;
else
key_state <=key_delay;
key_delay :
if(key == 5'b11111)
key_state <= key_init;
else
key_state <=key_check;
key_check :
if(key == 5'b11111) //释放按键后,按键计数+1
begin
case (key_temp)
5'b01111:
begin
key_id <= 1;
key_count_o <= key_count[0];
key_count[0] <= key_count[0] + 1;
key_count[1] <= 0;
key_count[2] <= 0;
key_count[3] <= 0;
key_count[4] <= 0;
end
5'b10111:
begin
key_id <= 2;
key_count_o <= key_count[1];
key_count[1] <= key_count[1] + 1;
key_count[0] <= 0;
key_count[2] <= 0;
key_count[3] <= 0;
key_count[4] <= 0;
end
5'b11011:
begin
key_id <= 3;
key_count_o <= key_count[2];
key_count[2] <= key_count[2] + 1;
key_count[0] <= 0;
key_count[1] <= 0;
key_count[3] <= 0;
key_count[4] <= 0;
end
5'b11101 :
begin
key_id <= 4;
key_count_o <= key_count[3];
key_count[3] <= key_count[3] + 1;
key_count[4] <= 0;
key_count[0] <= 0;
key_count[1] <= 0;
key_count[2] <= 0;
end
5'b11110 :
begin
key_id <= 5;
key_count_o <= key_count[4];
key_count[4] <= key_count[4] + 1;
key_count[0] <= 0;
key_count[1] <= 0;
key_count[2] <= 0;
key_count[3] <= 0;
end
default :
begin
key_id <= 0;
key_count[0] <= 0;
key_count[1] <= 0;
key_count[2] <= 0;
key_count[3] <= 0;
key_count[4] <= 0;
key_count_o <= 0;
end
endcase
key_state <=key_init;
end
else //按键按下时,维持此状态,直到按键释放
begin
key_state <= key_check;
key_temp <= key; //把键码的值赋给寄存器
end
default :
key_state <= key_init;
endcase
end
always @(state_clk or key_count_o or key_id)
begin
case (key_count_o) //数码管段选
4'b0001 : ledout = 7'b11111001; // 1
4'b0010 : ledout = 7'b10100100; // 2
4'b0011 : ledout = 7'b10110000; // 3
4'b0100 : ledout = 7'b10011001; // 4
4'b0101 : ledout = 7'b10010010; // 5
4'b0110 : ledout = 7'b10000010; // 6
4'b0111 : ledout = 7'b11111000; // 7
4'b1000 : ledout = 7'b10000000; // 8
4'b1001 : ledout = 7'b10010000; // 9
4'b1010 : ledout = 7'b10001000; // A
4'b1011 : ledout = 7'b10000011; // B
4'b1100 : ledout = 7'b11000110; // C
4'b1101 : ledout = 7'b10100001; // D
4'b1110 : ledout = 7'b10000110; // E
4'b1111 : ledout = 7'b10001110;
default : ledout = 7'b11000000;
endcase
case (key_id) //按照键码进行数码管位选
1 : weiout = ~8'b1000_0000;
2 : weiout = ~8'b0100_0000;
3 : weiout = ~8'b0010_0000;
4 : weiout = ~8'b0001_0000;
5 : weiout = ~8'b0000_1000;
default : weiout = ~8'b1000_0000;
endcase
end
|