设计方法第一课
四个小任务实现线性序列机
任务1
让led灯亮0.25s,灭0.75s,不再是等长时间反转
计数器有时是最大值减1,有时候只是某个值,区别在于周期性计数时,由最大值变0会占一个时钟周期
always@(posedge clk or negedge rst_n)
if(!rst_n)
counter <= 0;
else if(counter == maxcnt - 1)
counter <= 0;
else
counter <= counter + 1'd1;
always@(posedge clk or negedge rst_n)
if(!rst_n)
led <= 0;
else if(counter == 0)
led <= 1;
**else if(counter == maxcnt/4)**
led <= 0;
仿真图
亮灯持续时间0.25ms,可测得灭时间0.75ms,少三个数量级是因为仿真时参数重定义,减少三个0,加快仿真进度。
任务1总结
计数器不仅可以取最大值,还可以取中间的任意值。
可以将计数器当作一把时间的尺子,用计数器的每一个计数值当作一个刻度,从而得到各个需要的时刻。
在指定的时刻,执行需要的操作。
任务2
让led以亮0.25s 灭0.5s,亮0.75s,灭1s的规律,持续循环闪烁。
设计思路:顶一个0.25s的最小单位,每过0.25s的若干整数倍对led进行赋值操作
parameter maxcnt = 12_500_000;
always@(posedge clk or negedge rst_n)
if(!rst_n)
counter <= 0;
else if(counter == maxcnt*10 - 1)
counter <= 0;
else
counter <= counter + 1'd1;
always@(posedge clk or negedge rst_n)
if(!rst_n)
led <= 1;
else if(counter == 0)
led <= 1;
else if(counter == maxcnt)
led <= 0;
else if(counter == maxcnt*3)
led <= 1;
else if(counter == maxcnt*6)
led <= 0;
else if(counter == maxcnt*10)
led <= 1;
任务2仿真图
波形查看,右键grid,在timeunint中由ns改为ms,方便查看时间刻度
思路改进
可以再定义一个计数器,让counter每次计数到最大值时,新定义的counter1加1,如此,不用再给maxcnt*整数,只需在相应的counter1到时,用case语句对led赋值
任务三_由用户指定(第一个可以在程序运行时对led进行状态操作)
以0.25s为一个最小时间单元,以八个小段(2s)为一个循环周期,led在每一小段的状态由一个8位的输入端口指定(用八个开关,决定灯的亮灭)
新增一个input[7:0] switch;
always@(posedge clk or negedge rst_n)
if(!rst_n)
led <= 1;
else begin
case(counter0)
0:led <= switch[0];
1:led <= switch[1];
2:led <= switch[2];
3:led <= switch[3];
4:led <= switch[4];
5:led <= switch[5];
6:led <= switch[6];
7:led <= switch[7];
default:led <= led;
endcase
当counter0计数到几时,led就按照8位的开关第几位状态亮灭
任务四_受控线性序列机
在第三个任务基础上,实现每隔一定的时间,执行一轮led8个状态的切换控制
处理方法:每隔一定的时间,时间不一定是1s。将两个状态分开处理,各使用一个计数器来实现。
-
空闲态的间隔时间,用一个计数器实现counter2
-
变化态的最小时间段,也就是0.25s,用一个计数器实现counter0
-
8个状态,在用一个三位计数器来实现counter1
-
用于控制led切换时间间隔的counter0
计数最大值:maxcnt0 = 0.2510001000*1000/20 - 1 = 12_500_000 - 1
计数条件:1秒时间到,也就是counter2计数满,8个状态切换还没完,也就是counter1一轮还没结束
清零条件:技术到最大值,或者是空闲等待计数器counter2处于计数过程中 -
用于计数当前输出led第几个状态的计数器counter1
技术最大值:maxcnt 1= 8-1 = 7
计数条件:0.25秒counter2计数器计满
清零条件:计数到最大值 -
用于空闲状态计时的计数器counter2
计数最大值:maxcnt2 = 110001000*1000/20 -1 =50000000-1
计数条件:led八个状态输出完成
清零条件:计数到最大值
counter0(0.25s定时器)
- 等待空闲时间,此时间内counter0不计数
- 8个0.25秒时间段内,循环计数
parameter maxcnt0 = 12_500_000 - 1;
always@(posedge clk or negedge rst_n)
if(!rst_n)
counter0 <= 0;
else if(en_counter0)begin
if(counter0 == maxcnt0)
counter0 <= 0;
else
counter0 <= counter + 1'd1;
end
else
counter0 <= 0;
counter1(8状态计数器)
reg[2:0]counter1;
always@(posedge clk or negedge rst_n)
if(!rst_n)
counter1 <= 0;
else if (counter0 == maxcnt0)
counter1 <= counter1+1'd1;
counter2(空闲状态寄存器)
always@(posedge clk or negedge rst_n)
if(!rst_n)
counter2 <= 0;
else if(en_counter2)begin
if(counter2 = maxcnt2)
counter2 <= 0;
else
counter2<=counter2+1'd1;
end
else
counter2 <= 0;
使能信号分析
en_counter2
always@(posedge clk or negedge rst_n)
if(!rst_n)
en_counter2 <= 1'd1;
else if((counter1 == 7) &&(counter0 == maxcnt0)
en_counter2 <= 1;
else if (counter2 == maxcnt2)
en_counter2 <= 0;
en_counter1和空闲状态想法
assign en_counter0 =~en_counter2
always@(posedge clk or negedge rst_n)
if(!rst_n)
en_counter2 <= 1'd1;
led在en_counter0拉高时计数,变化规律按switch中的由低到高规律变化