如果点亮四个LED呢
LED位宽为4,
`timescale 1ns / 1ps
module myled(clk,rst_n,led);
input clk;
input rst_n;
output reg [3:0]led;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
led <= 4'b0000;
else
led <= 4'b1111;
end
endmodule
同样,调整测试tb文件。
wire [3:0] led ;
结果如下:
二、状态机设计实现流水灯
代码:
`timescale 1ns / 1ps
module myled(clk,rst_n,led,state);
input clk;
input rst_n;
output reg [3:0]led;
output reg[1:0] state;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
led <= 4'b0000;
state <= 0;
end
else
begin
case (state)
0:begin
led <= 4'b1011;
state <= 1;
end
1:begin
led <= 4'b1101;
state <= 2;
end
2:begin
led <= 4'b1110;
state <= 3;
end
3:begin
led <= 4'b0111;
state <= 0;
end
default:
state <= 0;
endcase
end
end
endmodule
测试代码:
`timescale 1 ns/ 1 ps
module test_tb();
reg clk;
reg rst_n;
wire [3:0]led;
wire[1:0] state;
myled i1 (
.clk(clk),
.led(led),
.rst_n(rst_n),
.state(state)
);
initial
begin
$display("Running testbench");
clk=0;
rst_n=0;
#20 rst_n=1;
end
always #10 clk=~clk;
endmodule
仿真波形
(3)设计要点
注意state变量的赋初值。
(4)频率反转太快、看不出LED效果。
改善方法1:
状态机中增加计数器。
`timescale 1ns / 1ps
module myled(clk,rst_n,led);
input clk;
input rst_n;
output reg [3:0]led;
reg[1:0] state;
reg [3:0] counter;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
led <= 4'b0000;
state <= 0;
counter<=0;
end
else
begin
case (state)
0:begin
if(counter<12)
counter <= counter+1;
else
begin
led <= 4'b1011;
state <= 1;
counter <=0;
end
end
1:begin
if(counter<12)
counter <= counter+1;
else
begin
led <= 4'b1101;
state <= 2;
counter <=0;
end
end
2:begin
if(counter<12)
counter <= counter+1;
else
begin
led <= 4'b1110;
state <= 3;
counter <=0;
end
end
3:begin
if(counter<12)
counter <= counter+1;
else
begin
led <= 4'b0111;
state <= 0;
counter <=0;
end
end
default:
state <= 0;
endcase
end
end
endmodule
测试代码:
`timescale 1 ns/ 1 ps
module myled_tb();
reg clk;
reg rst_n;
wire [3:0]led;
myled i1 (
.clk(clk),
.led(led),
.rst_n(rst_n)
);
initial
begin
$display("Running testbench");
clk=0;
rst_n=0;
#20 rst_n=1;
end
always #10 clk=~clk;
endmodule
波形结果:
符合我们的要求。
仔细检查代码,case条件下时,应该直接给赋值,case (state)
即led <= 4'b1011;由原来的位置放在begin:后面,这才符合我们的设计。
0:begin
led <= 4'b1011;
if(counter<12)
counter <= counter+1;
else
begin
state <= 1;
counter <=0;
end
end
仿真波形:
三、分频
问题来了,如上图所示:state 一次是260ns,即counter0~12是260ns,led在counter12的位置,延后了一个节拍变化 。这是因为是寄存器,等于是一个触发器,led输出端等于get输入端 在上升沿来的时候,代码(posedge clk or negedge rst_n),在counter=12的下一个节拍,counter=0,state=1,在state=1的下个clk的上升沿,led更新为1101。
怎么解决??
分频,控制上升沿。
所谓分频,即新增加一个信号,如clk_show,在一个state状态下,完成上升下降时序,从而保证在下一个state变化以后,直接clk_show出现上升沿。即在state开始为1时,clk_show直接为上升沿,从而实现实时变化。即1101和state=1同步。
state一次提到520ns,一个state有两个counter循环,
设计思路:
先设计一个信号,clk_show根据clk和counter计数,13次变化一次,循环一次得26*10ns,再在clk_show上升沿时,变化led和state状态。即并行执行的“always @ ( posedge clk_show or negedge rst_n)”,在clk_show上升沿时,即变化 。
module myled2(clk,rst_n,led,state,counter,clk_show);
input clk ;
input rst_n ;
output reg [3:0]led ;
output reg[1:0] state;
output reg [3:0] counter;
output reg clk_show;
always @ ( posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
clk_show<=0;
counter<=0;
end
else
if(counter<12)
counter<=counter+1;
else
begin
counter<=0;
clk_show=~clk_show;
end
end
always @ ( posedge clk_show or negedge rst_n)
begin
if(!rst_n)
begin
led<=4'b1111;
state<=0;
end
else
begin
case(state)
0:begin
led<=4'b0111;
state<=1;
end
1:begin
led<=4'b1011;
state<=2;
end
2:begin
led<=4'b1101;
state<=3;
end
3:begin
led<=4'b1110;
state<=0;
end
default:
state<=0;
endcase
end
end
endmodule
测试代码
`timescale 1 ns/ 1 ps
module myled2_tb();
reg clk;
reg rst_n;
wire [3:0]led;
wire[1:0] state;
wire [3:0] counter;
wire clk_show;
myled2 i1 (
.clk(clk),
.led(led),
.rst_n(rst_n),
.state(state),
.counter(counter),
.clk_show(clk_show)
);
initial
begin
$display("Running testbench");
clk=0;
rst_n=0;
#20 rst_n=1;
end
always #10 clk=~clk;
endmodule
最多仿真波形:
同一变量不能同时在两个always块内复制,如分频和状态机的两个always块,复位时复位什么变量由本块内用到的变量决定。