声明:案例和代码来自小梅哥课程,本人仅对知识点做做笔记,如有学习需要请支持官方正版。
文章目录
- 该系列目录
- 设计目标
- 设计思路
- RTL及Testbench代码
- RTL代码
- Testbench代码
- 仿真结果
- 上板视频
该系列目录
Verilog线性序列机点灯案例(一)(小梅哥课程)
Verilog线性序列机点灯案例(二)(小梅哥课程)
设计目标
使用8个拨码开关控制一个LED灯,每个拨码开关负责控制0.25秒的时间,开关为1时亮,开关为0时灭。
举例:
10101010就是亮0.25秒,灭0.25秒,如此循环
10111101就是亮0.25秒,灭0.25秒,亮1秒,灭0.25秒,亮0.25秒,如此循环
设计思路
counter0计数器每计数满0.25秒就向counter1计数器加1,
counter1计数器从0到7计数,
led灯根据当前counter1计数器的值,选中对应的拨码开关进行输出,用软件的写法就是
led = sw[counter1]
RTL及Testbench代码
RTL代码
module led_ctrl2(clk,rst_n,led_out,sw
);input clk;input rst_n;input [7:0] sw;output reg led_out;parameter MCNT = 12500_000 - 1;reg [26:0] counter0;//第一个always块负责counter0always@(posedge clk or negedge rst_n) beginif(!rst_n)counter0 <= 0 ;else if(counter0 == MCNT)counter0 <= 0;elsecounter0 <= counter0 + 1'd1;endreg [2:0] counter1;//第二个always块负责counter1always@(posedge clk or negedge rst_n) beginif(!rst_n)counter1 <= 0 ;else if(counter0 == MCNT) begincounter1 <= counter1 + 1'd1;endelsecounter1 <= counter1;end//第三个always块负责根据counter1决定led_out//每0.25秒切换一个拨码输出always@(posedge clk or negedge rst_n)if(!rst_n)led_out <= 0;else begincase(counter1)0:led_out <= sw[0];1:led_out <= sw[1];2:led_out <= sw[2];3:led_out <= sw[3];4:led_out <= sw[4];5:led_out <= sw[5];6:led_out <= sw[6];7:led_out <= sw[7];default:led_out <= led_out;endcaseend
endmodule
Testbench代码
`timescale 1ns / 1ns
module tb_led_ctrl2();reg clk;reg rst_n;wire led_out;reg [7:0] sw;initial clk = 1;always #10 clk = ~clk;led_ctrl2 led_ctrl2_inst0(.clk(clk),.rst_n(rst_n),.sw(sw),.led_out(led_out));defparam led_ctrl2.MCNT = 12500 - 1; initial beginrst_n = 0;sw = 8'b1010_1010;#201;rst_n = 1;#4_000_000;sw = 8'b0000_0001;#4_000_000;sw = 8'b1111_0001;#20_000_000;$stop;end
endmodule
仿真结果
总结这两张图可以看出来,counter1是在每次counter0计满12499时进1,即counter1每个值维持的时间是counter0等于0~12499,是0.25s,而led_out依赖于counter1,比counter1延迟一拍,所以led_out每个值维持时间也是0.25秒,时序正确。
上板视频
Verilog线性序列机点灯案例(三)(小梅哥课程)