题目:有一个中的周期信号(此处为10ms),在该10ms中定义了led的8个状态,其中每个状态为0.1ms。即在周期为10ms的程序中,前0.8msled根据控制亮灭,0,8ms到10ms这一段led灭
首先是一段错误代码
`timescale 1ns / 1ps
module ledflash4(
input clk,
input rest,
input [7:0]ctrl, //8种状态定义
// input [31:0]T, //总的周期时间
input [31:0]Time,//一个状态的周期时间
output reg led
);
reg [15:0]counter3;//总的周期的计数值
reg [31:0]counter;//一个状态的小周期时间的计数值
reg [2:0]counter2;//八种状态的计数值
reg i;//判断一个总的周期内是否要进行8状态循环,如果需要进行则赋值1,否则为0.
///判断是否达到总周期时间十毫秒counter3/
always@(posedge clk or negedge rest)
if(!rest)
counter3<=0;
else if(counter3==500000-1)
counter3<=0;
else
counter3<=(counter3+1'b1);
判断i///
always@(posedge clk or negedge rest)
if(!rest)
i<=0;
else if(counter3==0)//在每一次10ms的开始,是i为1,进行8状态循环
i<=1;
else if(counter2==7)//在完成一次8状态计时后,让i为0,10ms完成一次任务!!!!!!!!!!!!!错误的原因在此处!!!!!!!!!!!!
i<=0;
/一个状态的小周期时间counter//
always@(posedge clk or negedge rest)
if(!rest)
counter<=0;
else if(i)//只有i为1时,才能进行led亮灭。此时counter计数
begin
if(counter==Time-1)//完成一次周期
counter<=0;
else
counter<=(counter+1'b1);
end
else //i为0,led保持全灭,因此counter不计数
counter<=0;
/led八状态循环counter2
always@(posedge clk or negedge rest)
if(!rest)
counter2<=0;
else if(i)//只有i为1时,才能进行led亮灭
begin
if(counter==Time-1)//判断完成一次小周期
counter2<=counter2+1'b1;//若完成一次小周期,counter2刚好是3位,即0~7.因此不用使用else来让其counter2<=0
end
else
counter2<=0;//i=0时,counter2不计数
led八状态赋值///
always@(posedge clk or negedge rest)
if(!rest)
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
上述方程似乎看着没有问题,但通过仿真结果,可以看出问题:
可以看到led在[0]~[6]时都没有任何问题,但是在[7]处,led是很短暂的方波。其原因是程序里在判断i的状态时
always@(posedge clk or negedge rest)
if(!rest)
i<=0;
else if(counter3==0)//在每一次10ms的开始,是i为1,进行8状态循环
i<=1;
else if(counter2==7)//在完成一次8状态计时后,让i为0,10ms完成一次任务!!!!!!!!!!错误的原因在此处!!!!!!!!!
i<=0;
else if(counter2==7)
是当counter2为7时,就立刻让i=0,而此时case里面判断counter2为7的语句还没执行结束。因此会出现上面时序图的错误。
只需在判断i的程序里再添加一个条件即可:
always@(posedge clk or negedge rest)
if(!rest)
i<=0;
else if(counter3==0)
i<=1;
else if((counter2==7)&&(counter==Time-1))
i<=0;
else if((counter2==7)&&(counter==Time-1))
在counter2=7时,counter此时再经历一个小循环。这样就相当于把状态7运行结束了。这样就可以运行成功了。如下图:
看到这应该认为就结束了,但是更改ctrl后发现了一个小问题
/led八状态循环counter2
always@(posedge clk or negedge rest)
if(!rest)
counter2<=0;
else if(i)//只有i为1时,才能进行led亮灭
begin
if(counter==Time-1)//判断完成一次小周期
counter2<=counter2+1'b1;//若完成一次小周期,counter2刚好是3位,即0~7.因此不用使用else来让其counter2<=0
end
else
counter2<=0;//i=0时,counter2不计数
的最后一句
else
counter2<=0;//i=0时,counter2不计数
是当i=0,即已经结束8状态的时候,让counter2为0,回到原始状态。可是此处默认的是counter2=0,在case语句中会一直判断为case(0),使得led一直处于ctrl[0]的状态。
如下图,当ctrl=10000111,当结束完led8状态,counter2此时赋值为0,则case一直认为要赋值led<=ctrl[0]的状态,此时ctrl[0]是1。在时序图显示的就是在[7]到下一个周期的[0]之间led为1的情况。
这种错误很好解决,只需在case判断语句中添加判断i的条件语句即可
else if(i)
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
else
led<=0;
解决好的时序图
至此,该程序运用了一个i来当作判断
总结:case语句,没有列举完的情况,需要加一个默认项列举完