一、状态机实现
问题:根据以下描述功能用verilog编写一段代码,并用状态机来实现该功能。
(1)状态机:实现一个测试过程,该过程包括启动准备状态、启动测试、停止测试、查询测试结果、显示测试结果、测试结束返回初始化6个状态;用时间来控制该过程,90秒内完成该过程;
(2)描述状态跳转时间;
(3)编码实现。
1.思路
定义6个状态值,通过计数器计时,满足计时条件改变状态
2.verilog代码实现
module fsm(
input wire clk, //1秒震荡50_000_000次,周期是20ns
input wire rst_n, //1s = 1_000_000_000ns,震荡一次是20ns,
output reg [3:0] led
);
reg [32:0] cnt;
reg [1:0] cstate;
localparam s0_on = 0;
localparam s1_on = 1;
localparam s2_on = 2;
localparam s3_on = 3;
localparam s4_on = 4;
localparam s5_on = 5;
//计数器模块
always@(posedge clk or negedge rst_n)begin
if(!rst_n) //按下复位键
cnt <= 0; //计数清零
else if(cnt == 33'd4_500_000_000 - 1) //计数达到最大值
cnt <= 1'b0; //计数清零
else
cnt <= cnt + 1'b1; //否则计数自增1
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
begin
cstate<=s0_on;
led<=4'b1111;
end
else
case(cstate)
s0_on : begin
led<=4'b1111;
if(cnt==50_000_000 -1) //50_000_000为1s
cstate <=s1_on;
else
cstate <=cstate;
end
s1_on : begin
led<=4'b0001;
if(cnt==1_050_000_000 -1) //21s
cstate <=s2_on;
else
cstate <=cstate;
end
s2_on : begin
led<=4'b0010;
if(cnt==2_550_000_000 -1) //51s
cstate <=s3_on;
else
cstate <=cstate;
end
s3_on : begin
led<=4'b0100;
if(cnt==2_600_000_000 -1)//52s
cstate <=s4_on;
else
cstate <=cstate;
end
s4_on : begin
led<=4'b11000;
if(cnt==2_750_000_000 -1)//55s
cstate <=s5_on;
else
cstate <=cstate;
end
s5_on : begin
led<=4'b1111;
if(cnt==3_000_000_000 -1)//60s
cstate <=s0_on;
else
cstate <=cstate;
end
default : begin
led<=4'b0000;
if(cnt==50_000_000 -1)
cstate <=s1_on;
else
cstate <=cstate;
end
endcase
end
endmodule
3.实现效果
FPGA状态机
二、检测二进制01串
问题:画出可以检测10010串的状态图, 并用verilog编程实现之
1.思路
通过状态机实现
当检测到正确的0或1时改变状态,进而检测下一个01,否则一直在初始状态循环,直到检测到正确的码串
2.verilog代码实现
work.v
module work (
input wire clk,
input wire rst_n,
input wire [1:0]key,
output reg [3:0]led
);
localparam [2:0] S0 = 0;
localparam [2:0] S1 = 1;
localparam [2:0] S2 = 2;
localparam [2:0] S3 = 3;
localparam [2:0] S4 = 4;
localparam [2:0] S5 = 5;
reg [2:0] current_state;
reg flag ;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
current_state <= S0;
flag <= 0;
end
else begin
case(current_state)
S0: begin
if(key[1]) begin
current_state <= S1;
flag <= 0;
end
else if(key[0]) begin
current_state <= S0;
flag <= 0;
end
else begin
current_state <=current_state;
flag <= flag;
end
end
S1: begin
if(key[0]) begin
current_state <= S2;
flag <= 0;
end
else if(key[1]) begin
current_state <= S0;
flag <= 0;
end
else begin
current_state <=current_state;
flag <= flag;
end
end
S2: begin
if(key[0]) begin
current_state <= S3;
flag <= 0;
end
else if(key[1]) begin
current_state <= S0;
flag <= 0;
end
else begin
current_state <=current_state;
flag <= flag ;
end
end
S3: begin
if(key[1]) begin
current_state <= S4;
flag <= 0;
end
else if(key[0]) begin
current_state <= S0;
flag <= 0;
end
else begin
current_state <=current_state;
flag <= flag ;;
end
end
S4: begin
if(key[0]) begin
current_state <= S0;
flag <= 1;
end
else if(key[1]) begin
current_state <= S0;
flag <= 0;
end
else begin
current_state <=current_state;
flag <= flag;
end
end
default:begin
current_state <= S0;
flag <= 0;
end
endcase
end
end
//根据flag 决定灯是否亮
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
led <= 4'd0;
end
else if (flag) begin
led <= 4'b1111;
end
else if (!flag) begin
led <= 4'd0;
end
else begin
led <= led;
end
end
endmodule
key_debiunce.v
module key_debounce(
input wire clk,
input wire rst_n,
input wire key,
output reg flag,// 0抖动, 1抖动结束
output reg key_value//key抖动结束后的值
);
reg [19:0] delay_cnt;//1_000_000
reg key_reg;//key上一次的值
//20ms计数器
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
key_reg <= 1;
delay_cnt <= 0;
end
else begin
key_reg <= key;
//当key为1 key 为0 表示按下抖动,开始计时
if(key_reg != key ) begin
delay_cnt <= 20'd1_000_000 ;
//仿真
// delay_cnt <= 20'd10 ;
end
else begin
if(delay_cnt > 0)
delay_cnt <= delay_cnt - 20'd1;
else
delay_cnt <= 0;
end
end
end
//当计时完成,获取key的值
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
flag <= 0;
key_value <= 1;
end
else begin
// 计时完成 处于稳定状态,进行赋值
if(delay_cnt == 1) begin
flag <= 1;
key_value <= key;
end
else begin
flag <= 0;
key_value <= key_value;
end
end
end
endmodule
work_top.v
module work_top(
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;
key_debounce inst_key_debounce_key1(
.clk (clk ),
.rst_n (rst_n ),
.key (key[0] ),
.flag (flag[0] ),
.key_value (key_value[0] )
);
key_debounce inst_key_debounce_key2(
.clk (clk ),
.rst_n (rst_n ),
.key (key[1] ),
.flag (flag[1] ),
.key_value (key_value[1] )
);
work in_work(
. clk (clk),
. rst_n (rst_n),
. key ({key_value[0] && flag[0],key_value[1] && flag[1]}),
. led (led)
);
endmodule
work_tb.v
`timescale 1ns/1ns // 时间单位/时间精度
module work_tb;
reg clk;
reg rst_n;
reg [1:0]key;
wire [3:0]led;
always #10 clk = ~clk;
//初始化
initial begin
clk = 1'b1;
rst_n = 1'b0;
key =2'b00;
#20 ;
rst_n = 1'b1;
//1
#20
key = 2'b10;
#20
key = 2'b00;
//0
#20
key = 2'b01;
#20
key = 2'b00;
//0
#20
key = 2'b01;
#20
key = 2'b00;
//1
#20
key = 2'b10;
#20
key = 2'b00;
//0
#20
key = 2'b01;
#20
key = 2'b00;
#100;
$stop;
end
//实例化
work inst_work(
.clk (clk ),
.rst_n (rst_n ),
.key (key ),
.led (led)
);
endmodule
3.仿真结果
可以看到输入正确码串后led全亮