基于FPGA的密码锁开发——(3)密码设置模块驱动

*在第一篇密码锁驱动开发完之后,就可以构思密码设置驱动了
需求如下:
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

你可能感兴趣的:(FPGA基础,状态机,verilog,fpga)