一:实验任务
画出可以检测10010串的状态图,并用verilog编程实现
思路:
使用按键KEY1和KEY2分别代表0和1,这里要使用按键消抖,可以参考我的另一篇博客中的按键消抖FPGA按键消抖+蜂鸣器
通过有限的6个状态进行切换,当识别到数字串10010时,LED闪烁2s。
状态图:
设计按键消抖模块
key_debounce.v
- module key_debounce(
- input wire clk,
- input wire rst_n,
- input wire key,
-
- output reg flag, //判断抖动是否消除的标志信号,0为抖动,1为抖动结束
- output reg key_value //消抖后稳定的按键值给到蜂鸣器模块和LED模块
- );
-
- //定义20ms延迟计数器,0.2s,1_000_000次
- reg [19:0] delay_cnt;
-
- //寄存依次key的值用来判断按键是否消抖成功
- reg key_reg;
-
- //按下按键20ms延时计数器
- always@(posedge clk or negedge rst_n)begin
- if(!rst_n)
- begin
- key_reg <= 1'b1; //复位信号,设置按键无效
- delay_cnt <= 1'b0; //计数器设置为0
- end
- else
- begin
- key_reg <= key;
- if(key_reg ^ key) //当这一次key值和上一次key值不一样,证明正在抖动
- delay_cnt <= 20'd1_000_000; //延迟时间20ms
- else if(delay_cnt > 0)
- delay_cnt <= delay_cnt - 1; //没有抖动,开始20ms倒计时
- else
- delay_cnt <= 1'b0;
- end
- end
-
- //根据延时计数器获取按键状态以及按键值
- always@(posedge clk or negedge rst_n)begin
- if(!rst_n)
- begin
- flag <= 1'b0; //复位信号,设置信号标志为抖动
- key_value <= 1'b1; //设置抽样值为1
- end
- else
- begin
- if(delay_cnt == 20'd1) //倒计时1_000_000到1
- begin
- flag <= 1'b1;
- key_value <= key; //稳定20ms后将key值给到key_value
- end
- else
- begin
- flag <= 1'b0;
- key_value <= key_value; //20ms内先不取样
- end
- end
- end
-
- endmodule
设计状态机模块Verilog HDL文件
fsm_10010.v
- module fsm_10010(
- input clk,
- input rst_n,
- input [1:0] key,
-
- output wire [3:0] led
- );
- parameter MAX_NUM = 24'd9_999_999;//0.2s计时器
- parameter T = 4'd10;//2s,100_000_000次
-
- reg [2:0] cstate; //现态
-
- //状态划分
- localparam state_0 = 0; //初始状态
- localparam state_1 = 1; //按下1
- localparam state_10 = 2; //按下10
- localparam state_100 = 3; //按下100
- localparam state_1001 = 4; //按下1001
- localparam state_10010 = 5; //按下10010
-
- reg [3:0] cnt = 0; //计时器赋初值为0
- reg [23:0] cnt_02 = 0;
- reg time_flag;//计时标志,1:开始计时,0:结束计时
- reg [3:0] led_r;
-
- //0.2计数器模块
- always@(posedge clk or negedge rst_n)begin
- if(!rst_n)
- cnt_02 <= 1'b0; //按下复位键,清零
- else if(cnt_02 == MAX_NUM)
- cnt_02 <= 1'b0;
- else
- cnt_02 <= cnt_02 + 1'b1;
- end
-
- //2s计数器模块
- always@(posedge clk or negedge rst_n)begin
- if(!rst_n)
- cnt <= 1'b0;//按下复位键,清零
- else if(time_flag == 1'b1)begin//开始计时
- if(cnt_02 == MAX_NUM)begin
- if(cnt < T)begin
- cnt <= cnt + 1'b1;
- end
- else begin
- cnt <= 1'b0;//cnt计数达到最大就清空
- end
- end
- else begin
- cnt <= cnt;//其余时间保持
- end
- end
- else begin
- cnt <= 1'b0;//不计时,cnt清空
- end
- end
-
- //状态切换模块
- always@(posedge clk or negedge rst_n)begin
- if(!rst_n)
- begin
- cstate <= state_0;
- end
- else
- case(cstate)
- state_0: begin
- if(key[1] == 1'b1) //该状态持续时间为1s,1s后,下一次状态更改为led1亮
- cstate <= state_1;
- else if(key[0] == 1'b1)
- cstate <= state_0;
- else
- cstate <= state_0;
- end
- state_1: begin
- if(key[0] == 1'b1)
- cstate <= state_10;
- else if(key[1] == 1'b1)
- cstate <= state_0;
- else
- cstate <= state_1;
- end
- state_10: begin
- if(key[0] == 1'b1)
- cstate <= state_100;
- else if(key[1] == 1'b1)
- cstate <= state_0;
- else
- cstate <= state_10;
- end
- state_100: begin
- if(key[1] == 1'b1)
- cstate <= state_1001;
- else if(key[0] == 1'b1)
- cstate <= state_0;
- else
- cstate <= state_100;
- end
- state_1001: begin
- if(key[0] == 1'b1)begin
- cstate <= state_10010;
- time_flag <= 1'b1;//开始计时
- end
- else if(key[1] == 1'b1)
- cstate <= state_0;
- else
- cstate <= state_1001;
- end
- state_10010: begin
- if(cnt == T)begin
- cstate <= state_0;
- time_flag <= 1'b0;//结束计时
- end
- else
- cstate <= state_10010;
- end
- default: ;
- endcase
- end
-
- //第三段:跟随状态输出
- always@(posedge clk or negedge rst_n)begin
- if(!rst_n)
- led_r <= 4'b0001;
- else
- case(cstate)
- state_10010:if(cnt_02 == 24'd4_999_999)
- led_r <= 4'b1111;
- else if(cnt_02 == MAX_NUM)
- led_r <= 4'b0000;
- else
- led_r <= led_r;
- default : led_r <= 4'b0001;
- endcase
-
- end
-
- assign led = led_r;
-
- endmodule
设计顶层模块
top_fsm_10010.v
- module top_fsm_10010(
- input wire clk,
- input wire rst_n,
- input wire [1:0] key,
-
- output wire [3:0] led
- );
- wire [1:0] flag;
- wire [1:0] key_value;
-
- //例化按键KEY1
- key_debounce inst_key_debounce(
- .clk (clk ),
- .rst_n (rst_n ),
- .key (key[0] ),
-
- .flag (flag[0] ), //判断抖动是否消除的标志信号,0为抖动,1为抖动结束
- .key_value(key_value[0]) //消抖后稳定的按键值给到蜂鸣器模块和LED模块
- );
-
- //例化按键KEY2
- key_debounce inst_key_debounce1(
- .clk (clk ),
- .rst_n (rst_n ),
- .key (key[1] ),
-
- .flag (flag[1] ), //判断抖动是否消除的标志信号,0为抖动,1为抖动结束
- .key_value(key_value[1]) //消抖后稳定的按键值给到蜂鸣器模块和LED模块
- );
-
- //例化状态机
- fsm_10010(
- .clk (clk ),
- .rst_n(rst_n ),
- .key ({~key_value[1]&&flag[1],~key_value[0]&&flag[0]}),
-
- .led (led)
- );
- endmodule
查看RTL门级电路