说明
来自于小梅哥AC620状态机的代码,检测字符Hello,仿真文件是自己写的,当检测到o无论如何实现不了led翻转:

最后检查设置的时钟周期和延时时间
`timescale 1ns/100ps
`define clk_cycle 50
//时钟周期100ns
always #(`clk_cycle) clk = ~clk;
//延时50ns
#(`clk_cycle)
以上表明:延时时间为时钟周期的一半,对于第
二张图:当上升沿触发检测到l后,跳转状态5开始准备检测o,但是检测l后没有跳转到o且下一次上升沿来临检测的是H,延时使得字符与时钟周期对不上,未等到时钟触发,状态就已经改变,无法实现相应的功能。
对于第
一张图:单个字符延时的时间是时钟周期的2倍;上升沿触发检测到o时,状态并未变为H且上升沿再次来临还是检测o,实际上检测了两次o。

设置延时时间等于时钟周期,正好上升沿触发检测到
o(o的持续时间在上升沿之后,且没有超过下一次上升沿来临),led实现了翻转。
最后
贴上代码,可以试试当延时时间大于/小于/等于时钟周期,电路输出的状态!
代码
module Hello(clk,rst_n,data,led);
input clk;//50MHz:1/50_000_000s=20ns时钟周期
input rst_n;//高电平有效
input [7:0] data;//ASCII码表示,实际为7位2进制编码,通常8位作为一个字节
output reg led;
//状态的定义,独热码编码方式,简化译码逻辑
localparam //本地参数只能在当前模块使用
check_H = 5'b0_001,
check_e = 5'b0_010,
check_la = 5'b0_100,
check_lb = 5'b1_000,
check_o = 5'b0_000;
//定义状态所需的寄存器
reg[4:0] state;
//一段式状态机:更利于对事件的思维理解
//三段式状态机:效率最高,时序收敛性最好
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
led <= 1'b1;
state <= check_H;//初始状态:等待'H';复位后处于检测'H'的状态
end
else begin
case(state)
check_H:
if(data == "H")//满足序列的第一个字符,跳转到下一个状态
state <= check_e;
else
state <= check_H;//循环等待
check_e:
if(data == "e")//能够综合,首先对'e'进行预编译,寻找对应ASCII码
state <= check_la;
else
state <= check_H;//重新等待'H'的到来
check_la:
if(data == "l")
state <= check_lb;
else
state <= check_H;
check_lb:
if(data == "l")
state <= check_o;
else
state <= check_H;
check_o: begin
state <= check_H;//检测成功,重新回到状态1,等待'H'到来
if(data == "o")
led <= ~led;
else
led <= led;//保持led当前状态不变
end
default:state <= check_H;//其他状态回到初始值
endcase
end
endmodule
tb
`timescale 1ns/100ps
`define clk_cycle 50
module Hello_tb;
reg clk;
reg reset;//连接待仿真文件的输入信号,肯定把它存起来,即设置为reg型
reg[7:0] ASCII;
wire led;//连接待仿真文件的输出,设置为wire型
always #(`clk_cycle) clk = ~clk;//产生测试时钟,时钟周期100ns
//always #(`clk_cycle/2) clk = ~clk;
initial begin
clk = 0;
ASCII = 0;
reset = 1;
#10 reset = 0;
#110 reset = 1;
#100000//延时0.1ms
forever begin //检测 I AM ZHANG Hello
ASCII = "I";
#(`clk_cycle*4)//延时200ns
ASCII = "A";
#(`clk_cycle*4)
ASCII = "M";
#(`clk_cycle*4)
ASCII = "Z";
#(`clk_cycle*4)
ASCII = "H";
#(`clk_cycle*4)
ASCII = "A";
#(`clk_cycle*4)
ASCII = "N";
#(`clk_cycle*4)
ASCII = "G";
#(`clk_cycle*4)
ASCII = "H";
#(`clk_cycle*4)
ASCII = "e";
#(`clk_cycle*4)
ASCII = "l";
#(`clk_cycle*4)
ASCII = "l";
#(`clk_cycle*4)
ASCII = "o";
#(`clk_cycle*4)
ASCII = "H";
#(`clk_cycle*4)
ASCII = "e";
#(`clk_cycle*4)
ASCII = "l";
#(`clk_cycle*4)
ASCII = "l";
#(`clk_cycle*4)
ASCII = "o";
#(`clk_cycle*4)
ASCII = "H";
#(`clk_cycle*2)
ASCII = "e";
#(`clk_cycle*2)
ASCII = "l";
#(`clk_cycle*2)
ASCII = "l";
#(`clk_cycle*2)
ASCII = "o";
#(`clk_cycle*2)
ASCII = "H";
#(`clk_cycle)
ASCII = "e";
#(`clk_cycle)
ASCII = "l";
#(`clk_cycle)
ASCII = "l";
#(`clk_cycle)
ASCII = "o";
end
end
Hello u1(
.rst_n(reset),
.clk(clk),
.data(ASCII),
.led(led)
);
endmodule
本文介绍了在Verilog中设计的状态机遇到的问题,即在检测字符序列'Hello'时,LED未能正确翻转。问题在于字符'o'的检测时机与时钟周期不匹配。通过调整时钟周期和延时时间,使得在'o'的上升沿触发时,状态机能够正确跳转并实现LED翻转。文章提供了完整的代码示例,并进行了不同延时时间下的仿真测试,展示了如何解决这个问题。
5441

被折叠的 条评论
为什么被折叠?



