受控线性序列机
第六题:每隔10ms,让LED灯的一个8状态循环执行一次(每个状态的变化时间值小一点,方便测试,比如设置为10us)
counter在10ms前面才计数,所以counter有两个状态,计数和停。所以有个EN信号来控制就可以,EN =1 counter计数,EN=0 counter停止。EN可以由一个小的计数器来控制。EN拉低的条件是我们8个翻转状态结束的时候。
counter_led_6.v
module counter_led_6(
clk,
reset,
ctrl,
time,
led
);
input clk;
input reset;
input [7:0] ctrl;
input [31:0] time;
output reg led; // 在always块中 所以是reg类型
// 主要是控制counter 10ms之内,counter有两个状态
reg [31:0] counter
reg EN;
reg [18:0]counter0;
always@(posedge clk or negedge reset)
if(!reset)
counter0 <= 0;
else if(counter0 == 500000 - 1)
counter0 <= 0;
else
counter0 <= counter0 + 1'b1;
always@(posedge clk or negedge reset)
if(!reset)
EN <= 0;
else if(counter0 == 0)
EN <= 1;
else if (counter2 == 7)
EN <= 0;
always@(posedge clk or negedge reset)
if(!reset)
counter <= 0;
else if(EN) begin
if(counter = Time -1)
counter <= 0;
else
counter = counter + 1'b1;
end
else
counter <= 0;
reg [2:0] counter2;
always@(posedge clk or negedge reset)
if(!reset)
counter2 <= 0;
else if(EN) begin
if(counter = Time -1)
counter2 <= 0;
else
counter2 = counter2 + 1'b1;
end
else
counter2 <= 0;
always@(posedge clk or negedge reset)
if(!reset)
led <= 0;
else case(counter2)
0; led <= ctrl[0];
1; led <= ctrl[1];
2; led <= ctrl[2];
3; led <= ctrl[3];
4; led <= ctrl[4];
5; led <= ctrl[5];
6; led <= ctrl[6];
7; led <= ctrl[7];
default: led <= led;
endcase
endmodule
testbench
module led_flash_tb;
reg clk;
reg reset;
reg [7:0]ctrl;
reg [31:0]time;
reg led;
counter_led_6
#(
.MCNT(100000)
)
counter_led_4 counter_led_4(
.clk(clk),
.reset(reset),
.ctrl(ctrl),
.time(time),
.led(led)
)
initial clk = 1;
always #10 clk = !clk;
initial begin
reset = 0;
ctrl = 0;
time =0;
#201;
reset = 1;
#2000;
time = 2500;
ctrl = 8'b10100010;
#2000000000;
$stop;
end
endmodule
奇怪的是最后一个数据,没有保持那么长的时间,只有两个周期
前面代码有一个小的bug。
我们需要调试,在仿真中需要看到所有的信号,在scope里面,右击 add to window,添加被观测的信号,然后重新加载仿真launch。再去查看counter,发现一个问题:
发现在仿真种7 不见了,滚动滚轮发现7确实有,但是7的时钟周期很短,只保持了两个时钟周期。
再加上counter的条件:
这个时候就对了
小结:我们学到了题目的基本功能,还有调试的方法。