05. 1. 位操作
计数器实验升级,设计8个LED灯以每个0.5s的速率循环闪烁(跑马灯)
1.1 方法1:使用移位操作符<<来控制led灯的循环亮灭
设计代码
-
Verilog中,判断操作的时候不加位宽限定是可以的,比如if(counter == 24999999)或者if(counter == 25’d24999999)都可以,但是在赋值的时候要加,比如counter <= counter + 1’d1;(赋0可以不加)
-
[7:0] led,led有八个,所以用8'b0000_0001来代表八个led,使用移位操作符<<来控制led灯的循环亮灭。
module led_run(clk,rstn,led
);input clk;input rstn;output reg[7:0] led;reg[25:0] counter;always@(posedge clk or negedge rstn)if(!rstn)counter <= 0;else if(counter == 24999999)//else if(counter == 24999)counter <= 0;elsecounter <= counter + 1'd1;always@(posedge clk or negedge rstn)if(!rstn)led <= 8'b0000_0001;else if(counter == 24999999)begin//else if(counter == 24999)beginif(led == 8'b1000_0000)led <= 8'b0000_0001;elseled <= led << 1;endelseled <= led;endmodule
仿真代码:
`timescale 1ns/1nsmodule led_run_tb();reg clk;reg rstn;wire[7:0] led;led_run led_run(.clk(clk),.rstn(rstn),.led(led));initial clk = 1;always #10 clk = !clk;initial beginrstn = 0;#201;rstn = 1;#4000000;$stop;endendmodule
仿真波形:
1.2 方法2:利用位拼接{led[6:0], led[7]}实现循环移位
设计代码
该方法应用场景不多,了解即可。
module led_run_1(clk,rstn,led
);input clk;input rstn;output reg[7:0] led;reg[25:0] counter;always@(posedge clk or negedge rstn)if(!rstn)counter <= 0;else if(counter == 24999999)//else if(counter == 24999)counter <= 0;elsecounter <= counter + 1'd1;always@(posedge clk or negedge rstn)if(!rstn)led <= 8'b0000_0001;else if(counter == 24999999)begin//else if(counter == 24999)led <= {led[6:0], led[7]};elseled <= led;endmodule
1.3 方法3:调用其他模块
设计代码
思路:用计数器产生8种状态,然后再把这8种状态拿去用三八译码器译码,就刚好能够去对应点亮8个led灯。
- 调用了底层模块3_8译码器后(3位输入[2:0],八位输出8'b0000_0001),顶层led_run_2的输出led的数据类型需要由reg变为wire形(或者不写wire)
- 模块的调用与tb里的调用方式一样,做好对应端口的连接即可。
module led_run_2(clk,rstn,led
);input clk;input rstn;output wire[7:0] led; //注意1reg[25:0] counter;always@(posedge clk or negedge rstn)if(!rstn)counter <= 0;else if(counter == 24999999)//else if(counter == 24999)counter <= 0;elsecounter <= counter + 1'd1;reg[2:0] counter2;always@(posedge clk or negedge rstn)if(!rstn)counter2 <= 0;else if(counter == 24999999)//else if(counter == 24999)counter2 <= counter2 + 1'd1;decoder_3_8 decoder_3_8( //注意2.a(counter2[2]),.b(counter2[1]),.c(counter2[0]),.out(led)
);endmodule
调用方法:
05. 2. 参数化设计
设计代码
- 将24999999用参数代替,好处1是增加代码复用性与可读性。好处2是我们可以在板级验证的时候使用24999999,在写tb做调试的时候将参数改为2499,节约仿真时间
module led_run(clk,rstn,led
);parameter MCNT = 25'd24999999; //注意1input clk;input rstn;output reg[7:0] led;reg[25:0] counter;always@(posedge clk or negedge rstn)if(!rstn)counter <= 0;else if(counter == MCNT)//else if(counter == 24999)counter <= 0;elsecounter <= counter + 1'd1;always@(posedge clk or negedge rstn)if(!rstn)led <= 8'b0000_0001;else if(counter == MCNT)begin//else if(counter == 24999)beginif(led == 8'b1000_0000)led <= 8'b0000_0001;elseled <= led << 1;endelseled <= led;endmodule
仿真代码
- 写法一,修改例化后的模块参数,defparam led_run_inst.MCNT = 2499;
- 写法二,例化前修改module,led_run里的参数
`timescale 1ns/1nsmodule led_run_tb();reg clk;reg rstn;wire[7:0] led;led_run led_run_inst(.clk(clk),.rstn(rstn),.led(led));defparam led_run_inst.MCNT = 2499; //写法一initial clk = 1;always #10 clk = !clk;initial beginrstn = 0;#201;rstn = 1;#4000000;$stop;endendmodule
`timescale 1ns/1nsmodule led_run_tb();reg clk;reg rstn;wire[7:0] led;led_run //写法二#(.MCNT(2499))led_run_inst(.clk(clk),.rstn(rstn),.led(led));initial clk = 1;always #10 clk = !clk;initial beginrstn = 0;#201;rstn = 1;#4000000;$stop;endendmodule
仿真波形
06 使用参数化的设计实现模块的重用
让八个led灯分别以不同的频率闪烁
思路:使用八个led灯闪烁模块,为了简化,我们分别以0.1s,0.2s,0.3s,0.4s让四个led闪烁。
1.设计代码
- 先构建一个led闪烁的设计代码,再给与不同的计数参数例化4次即可
module led_run8(clk,rstn,led
);parameter MCNT = 24999999;input clk;input rstn;output led;reg[25:0] counter;reg led;always@(posedge clk or negedge rstn)if(!rstn)counter <= 0;else if(counter == MCNT)counter <= 0;elsecounter <= counter + 1'd1;always@(posedge clk or negedge rstn)if(!rstn)led <= 0;else if(counter == MCNT)led <= !led;endmodule
- 例化4个模块,使用参数化的设计实现模块的重用
module led_run8_test(clk,rstn,led
);input clk;input rstn;output wire[3:0] led;led_run8 led_run8_inst0(.clk(clk),.rstn(rstn),.led(led[0]));defparam led_run8_inst0.MCNT = 25'd2499999;led_run8 led_run8_inst1(.clk(clk),.rstn(rstn),.led(led[1]));defparam led_run8_inst1.MCNT = 25'd4999999;led_run8 led_run8_inst2(.clk(clk),.rstn(rstn),.led(led[2]));defparam led_run8_inst2.MCNT = 25'd7499999;led_run8 led_run8_inst3(.clk(clk),.rstn(rstn),.led(led[3]));defparam led_run8_inst3.MCNT = 25'd9999999;endmodule
2.仿真代码
`timescale 1ns/1nsmodule led_run8_test_tb();reg clk;reg rstn;wire[3:0] led;led_run8_test led_run8_test_inst(.clk(clk),.rstn(rstn),.led(led));initial clk = 1;always #10 clk = !clk;initial beginrstn = 0;#201;rstn = 1;#400000000;$stop;endendmodule
3.仿真波形
4.布置引脚(通过代码来布置引脚)
到此布置引脚就布置好了,后续生成bit流文件,打开硬件管理器之后就可以板级验证了。