*在第一篇密码锁驱动开发完之后,就可以构思密码设置驱动了
需求如下:
1、要准确输入6位密码,输入位数不足就判定密码设置失败
2、只有在解锁状态下可以进行密码修改
3、在密码设置完成后要通知到密码锁模块
4、密码设置的输入设备仍然是键盘模块
*
构思完之后,模块接口大致如下:
module password_set_dri(
//================System Signal================
input clk ,
input rst_n ,
//================Interface====================
output password_set_req ,//通知密码锁有密码设置需求的端口
output reg [23:0] password_out ,//密码输出接口
output password_set_done ,//通知密码锁密码设置完成的端口
input [3:0] key_val ,//与键盘的键值接口
input key_flag //键盘脉冲接口
);
接下来首先构思状态机逻辑
大致有以下几个状态
1、空闲态
2、密码0-5位输入态
3、密码输出态
定义如下:
//state machine
localparam S_IDLE = 8'b0000_0001 ;
localparam S_NUM0_INPUT = 8'b0000_0010 ;
localparam S_NUM1_INPUT = 8'b0000_0100 ;
localparam S_NUM2_INPUT = 8'b0000_1000 ;
localparam S_NUM3_INPUT = 8'b0001_0000 ;
localparam S_NUM4_INPUT = 8'b0010_0000 ;
localparam S_NUM5_INPUT = 8'b0100_0000 ;
localparam S_PASSWORD_OUT = 8'b1000_0000 ;
和密码锁驱动同样的,需要检测按键脉冲的上升沿
方法都是一样的,如下:
reg key_flag_tmp0;
reg key_flag_tmp1;
reg key_flag_tmp2;
wire flag_key_trig_t1;
wire flag_key_trig_t0;
//key_flag_tmp
always @(posedge clk)begin
key_flag_tmp0 <= key_flag;
key_flag_tmp1 <= key_flag_tmp0;
key_flag_tmp2 <= key_flag_tmp1;
end
assign flag_key_trig_t1 = key_flag_tmp1&(~key_flag_tmp2);
assign flag_key_trig_t0 = key_flag_tmp0&(~key_flag_tmp1);
然后需要有一个寄存器来寄存每次捕获到的键值,键值在flag_key_trig_t0时捕获,代码如下
//key_val_reg
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
key_val_reg <= 'd0;
else if(flag_key_trig_t0==1'b1)
key_val_reg <= key_val;
end
然后需要定义密码设置命令
assign CMD_PASSWORD_SET = (flag_key_trig_t1==1'b1)&&(key_val_reg==`PASSWORD_SET);
接着就是三段式状态机了,这里值得一提的是整个第三段就是来处理password_out的,在空闲态时密码寄存器是不变的,但会在空闲态跳变至输入态时清空
//state machine one
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
cur_state <= S_IDLE;
else
cur_state <= next_state;
end
//state machine two
always @(*)begin
next_state = cur_state;
case(cur_state)
S_IDLE:begin
if(CMD_PASSWORD_SET==1'b1)
next_state = S_NUM0_INPUT;
end
S_NUM0_INPUT:begin
if(flag_time_out==1'b1)
next_state = S_IDLE;
else if(flag_key_trig_t1==1'b1)
next_state = S_NUM1_INPUT;
end
S_NUM1_INPUT:begin
if(flag_time_out==1'b1)
next_state = S_IDLE;
else if(flag_key_trig_t1==1'b1)
next_state = S_NUM2_INPUT;
end
S_NUM2_INPUT:begin
if(flag_time_out==1'b1)
next_state = S_IDLE;
else if(flag_key_trig_t1==1'b1)
next_state = S_NUM3_INPUT;
end
S_NUM3_INPUT:begin
if(flag_time_out==1'b1)
next_state = S_IDLE;
else if(flag_key_trig_t1==1'b1)
next_state = S_NUM4_INPUT;
end
S_NUM4_INPUT:begin
if(flag_time_out==1'b1)
next_state = S_IDLE;
else if(flag_key_trig_t1==1'b1)
next_state = S_NUM5_INPUT;
end
S_NUM5_INPUT:begin
if(flag_time_out==1'b1)
next_state = S_IDLE;
else if(flag_key_trig_t1==1'b1)
next_state = S_PASSWORD_OUT;
end
S_PASSWORD_OUT:begin
next_state = S_IDLE;
end
default:next_state = S_IDLE;
endcase
end
//state machine three
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
password_reg <= 'd0;
else case(cur_state)
S_NUM0_INPUT,S_NUM1_INPUT,S_NUM2_INPUT,S_NUM3_INPUT,S_NUM4_INPUT,S_NUM5_INPUT:begin
if(flag_key_trig_t1==1'b1)
password_reg <= {password_reg[19:0],key_val_reg};
end
S_IDLE:begin
if(next_state==S_NUM0_INPUT)
password_reg <= 'd0;
end
default:;
endcase
end
状态机中有无操作超时跳回空闲态的逻辑,写法和密码锁驱动中的是一样的
//cnt_1s
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
cnt_1s <= 'd0;
else case(cur_state)
S_NUM0_INPUT,S_NUM1_INPUT,S_NUM2_INPUT,S_NUM3_INPUT,S_NUM4_INPUT,S_NUM5_INPUT:begin
if(cur_state!=next_state)
cnt_1s <= 'd0;
else if(cnt_1s==CNT_1s)
cnt_1s <= 'd0;
else
cnt_1s <= cnt_1s + 1'b1;
end
default:cnt_1s <= 'd0;
endcase
end
//cnt_1s_10th
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
cnt_1s_10th <= 'd0;
else case(cur_state)
S_NUM0_INPUT,S_NUM1_INPUT,S_NUM2_INPUT,S_NUM3_INPUT,S_NUM4_INPUT,S_NUM5_INPUT:begin
if(cur_state!=next_state)
cnt_1s_10th <= 'd0;
else if(cnt_1s_10th==9&&cnt_1s==CNT_1s)
cnt_1s_10th <= 'd0;
else if(cnt_1s==CNT_1s)
cnt_1s_10th <= cnt_1s_10th + 1'b1;
end
default:cnt_1s_10th <= 'd0;
endcase
end
//flag_time_out
assign flag_time_out = (cnt_1s==CNT_1s&&cnt_1s_10th==9);
最后再处理一下通知密码锁模块的password_set_req和password_set_done即可,利用状态机的跳变沿触发即可。
//password_set_req
assign password_set_req = (cur_state==S_IDLE)&&(next_state==S_NUM0_INPUT);
//password_set_done
assign password_set_done = (cur_state==S_PASSWORD_OUT)&&(next_state==S_IDLE);
//==================defines=====================
`define SIM
`include "local_defines.v"
module password_set_dri(
//================System Signal================
input clk ,
input rst_n ,
//================Interface====================
output password_set_req ,//通知密码锁有密码设置需求的端口
output reg [23:0] password_out ,//密码输出接口
output password_set_done ,//通知密码锁密码设置完成的端口
input [3:0] key_val ,//与键盘的键值接口
input key_flag //键盘脉冲接口
);
//================parameters===================
`ifndef SIM
localparam CNT_1s = 49_999_999;
`else
localparam CNT_1s = 49;
`endif
//state machine
localparam S_IDLE = 8'b0000_0001 ;
localparam S_NUM0_INPUT = 8'b0000_0010 ;
localparam S_NUM1_INPUT = 8'b0000_0100 ;
localparam S_NUM2_INPUT = 8'b0000_1000 ;
localparam S_NUM3_INPUT = 8'b0001_0000 ;
localparam S_NUM4_INPUT = 8'b0010_0000 ;
localparam S_NUM5_INPUT = 8'b0100_0000 ;
localparam S_PASSWORD_OUT = 8'b1000_0000 ;
//================System regs==================
reg key_flag_tmp0;
reg key_flag_tmp1;
reg key_flag_tmp2;
wire flag_key_trig_t1;
wire flag_key_trig_t0;
wire CMD_PASSWORD_SET;
reg [3:0] key_val_reg;
reg [7:0] cur_state;
reg [7:0] next_state;
reg [25:0] cnt_1s;
reg [3:0] cnt_1s_10th;
wire flag_time_out;
reg [23:0] password_reg;
//================Main Codes===================
//key_val_reg
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
key_val_reg <= 'd0;
else if(flag_key_trig_t0==1'b1)
key_val_reg <= key_val;
end
//key_flag_tmp
always @(posedge clk)begin
key_flag_tmp0 <= key_flag;
key_flag_tmp1 <= key_flag_tmp0;
key_flag_tmp2 <= key_flag_tmp1;
end
assign flag_key_trig_t1 = key_flag_tmp1&(~key_flag_tmp2);
assign flag_key_trig_t0 = key_flag_tmp0&(~key_flag_tmp1);
//cmd define
assign CMD_PASSWORD_SET = (flag_key_trig_t1==1'b1)&&(key_val_reg==`PASSWORD_SET);
//state machine one
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
cur_state <= S_IDLE;
else
cur_state <= next_state;
end
//state machine two
always @(*)begin
next_state = cur_state;
case(cur_state)
S_IDLE:begin
if(CMD_PASSWORD_SET==1'b1)
next_state = S_NUM0_INPUT;
end
S_NUM0_INPUT:begin
if(flag_time_out==1'b1)
next_state = S_IDLE;
else if(flag_key_trig_t1==1'b1)
next_state = S_NUM1_INPUT;
end
S_NUM1_INPUT:begin
if(flag_time_out==1'b1)
next_state = S_IDLE;
else if(flag_key_trig_t1==1'b1)
next_state = S_NUM2_INPUT;
end
S_NUM2_INPUT:begin
if(flag_time_out==1'b1)
next_state = S_IDLE;
else if(flag_key_trig_t1==1'b1)
next_state = S_NUM3_INPUT;
end
S_NUM3_INPUT:begin
if(flag_time_out==1'b1)
next_state = S_IDLE;
else if(flag_key_trig_t1==1'b1)
next_state = S_NUM4_INPUT;
end
S_NUM4_INPUT:begin
if(flag_time_out==1'b1)
next_state = S_IDLE;
else if(flag_key_trig_t1==1'b1)
next_state = S_NUM5_INPUT;
end
S_NUM5_INPUT:begin
if(flag_time_out==1'b1)
next_state = S_IDLE;
else if(flag_key_trig_t1==1'b1)
next_state = S_PASSWORD_OUT;
end
S_PASSWORD_OUT:begin
next_state = S_IDLE;
end
default:next_state = S_IDLE;
endcase
end
//state machine three
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
password_reg <= 'd0;
else case(cur_state)
S_NUM0_INPUT,S_NUM1_INPUT,S_NUM2_INPUT,S_NUM3_INPUT,S_NUM4_INPUT,S_NUM5_INPUT:begin
if(flag_key_trig_t1==1'b1)
password_reg <= {password_reg[19:0],key_val_reg};
end
S_IDLE:begin
if(next_state==S_NUM0_INPUT)
password_reg <= 'd0;
end
default:;
endcase
end
//password_out
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
password_out <= 24'haaaaaa;
else if(password_set_done==1'b1)
password_out <= password_reg;
else if(cur_state==S_IDLE&&next_state==S_NUM0_INPUT)
password_out <= 24'haaaaaa;
end
//password_set_req
assign password_set_req = (cur_state==S_IDLE)&&(next_state==S_NUM0_INPUT);
//password_set_done
assign password_set_done = (cur_state==S_PASSWORD_OUT)&&(next_state==S_IDLE);
//cnt_1s
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
cnt_1s <= 'd0;
else case(cur_state)
S_NUM0_INPUT,S_NUM1_INPUT,S_NUM2_INPUT,S_NUM3_INPUT,S_NUM4_INPUT,S_NUM5_INPUT:begin
if(cur_state!=next_state)
cnt_1s <= 'd0;
else if(cnt_1s==CNT_1s)
cnt_1s <= 'd0;
else
cnt_1s <= cnt_1s + 1'b1;
end
default:cnt_1s <= 'd0;
endcase
end
//cnt_1s_10th
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)
cnt_1s_10th <= 'd0;
else case(cur_state)
S_NUM0_INPUT,S_NUM1_INPUT,S_NUM2_INPUT,S_NUM3_INPUT,S_NUM4_INPUT,S_NUM5_INPUT:begin
if(cur_state!=next_state)
cnt_1s_10th <= 'd0;
else if(cnt_1s_10th==9&&cnt_1s==CNT_1s)
cnt_1s_10th <= 'd0;
else if(cnt_1s==CNT_1s)
cnt_1s_10th <= cnt_1s_10th + 1'b1;
end
default:cnt_1s_10th <= 'd0;
endcase
end
//flag_time_out
assign flag_time_out = (cnt_1s==CNT_1s&&cnt_1s_10th==9);
endmodule