1.设计一个led灯,亮0.5s暗0.5s循环亮暗。
0.5s是0.5s/20ns=25M 1s就是50M
module counter_led_0(
clk,
rst,
led
);
input clk,rst;
output reg led;
reg [25:0]counter;
parameter MCNT=50000000;
//这里面定义了参数MCNT,在仿真的时候修改参数,防止仿真时间太长不方便观察
always@(posedge clk,negedge rst)
begin
if (!rst)
counter<=0;
else if (counter==MCNT-1)
counter<=0;
else
counter<=counter+1;
end
always@(posedge clk,negedge rst)
begin
if (!rst)
led<=0;
else if (counter==MCNT/2-1)
led<=1; //这里代表0.5秒后由暗变亮
else if (counter==MCNT-1)
led<=0; //亮0.5秒后变暗
else led<=led;
end
endmodule
`timescale 1ns / 1ns
module counter_led_0_tb;
reg clk,rst;
wire led;
counter_led_0
#(.MCNT(50000))
counter_led_0(
.clk(clk), .rst(rst), .led(led)
);
initial clk=1;
always #10 clk=~clk;
initial begin
rst=0;
#205;
rst=1;
#20000000;
$stop;
end
endmodule
2.设计一个led灯,亮0.25s暗0.75s循环亮暗。
仅需修改这部分代码
always@(posedge clk,negedge rst)
begin
if (!rst)
led<=0;
else if (counter==MCNT*3/4-1)
led<=1; //这里代表0.75秒后由暗变亮
else if (counter==MCNT-1)
led<=0; //亮0.25秒后变暗
else led<=led;
end
3.设计一个led灯,亮0.25s暗0.5s,再亮0.75s随后暗1s循环亮暗。
一个循环2.5s,也就是2.5s/20ns=125M
reg [26:0]counter;
parameter MCNT=125000000
把led赋值那段代码改成下述形式
always@(posedge clk,negedge rst)
begin
if (!rst)
led<=0;
else if (counter==(MCNT*2/5)-1) //灭1s也就是2/5的总时间(2.5s)
led<=1;
else if (counter==MCNT/2-1) //亮0.25s(1/10),1/10+2/5=1/2
led<=0;
else if (counter==MCNT*7/10-1) //灭0.5s(1/5),1/5+1/2=7/10
led<=1;
else if (counter==MCNT-1) //亮0.75s
led<=0;
else led<=led;
end
放大
4.让led灯按照指定的亮灭模式亮灭,亮灭模式未知,由用户随机指定。以0.25s为一个变化周期,8个变化状态为一个循环。
2s为一个周期,那么也就是一个周期的频率为2s/20ns=100M
module counter_led_3(
clk,
rst,
ctrl,
led
);
input clk,rst;
output reg led;
input [7:0]ctrl; //用户指定控制亮暗
reg [26:0]counter;
parameter MCNT=100000000; //2s为一个循环周期
always@(posedge clk,negedge rst)
begin
if (!rst)
counter<=0;
else if (counter==MCNT-1)
counter<=0;
else
counter<=counter+1;
end
always@(posedge clk,negedge rst)
begin
if (!rst)
led<=0;
else if (counter==MCNT/8-1)
led<=ctrl[0];
else if (counter==MCNT/4-1)
led<=ctrl[1];
else if (counter==MCNT*3/8-1)
led<=ctrl[2];
else if (counter==MCNT/2-1)
led<=ctrl[3];
else if (counter==MCNT*5/8-1)
led<=ctrl[4];
else if (counter==MCNT*3/4-1)
led<=ctrl[5];
else if (counter==MCNT*7/8-1)
led<=ctrl[6];
else if (counter==MCNT-1)
led<=ctrl[7];
else led<=led;
end
endmodule
这里添加了应该指定的亮灭状态的输入端口input [7:0]ctrl;因为一共8个状态为一个变化周期。并注意对led赋值时的变化。
在对led进行赋值的时候,我们使用的是if语句,但是由于这里语句分支太长了最好改为case语句,执行的功能是相同的。
always@(posedge clk,negedge rst)
begin
if (!rst)
led<=0;
else
case (counter)
MCNT/8-1:led<=ctrl[0];
MCNT/4-1:led<=ctrl[1];
MCNT*3/8-1:led<=ctrl[2];
MCNT/2-1:led<=ctrl[3];
MCNT*5/8-1:led<=ctrl[4];
MCNT*3/4-1:led<=ctrl[5];
MCNT*7/8-1:led<=ctrl[6];
MCNT-1:led<=ctrl[7];
default:led<=led;
endcase
end
// always@(posedge clk,negedge rst)
// begin
// if (!rst)
// led<=0;
// else if (counter==MCNT/8-1)
// led<=ctrl[0];
// else if (counter==MCNT/4-1)
// led<=ctrl[1];
// else if (counter==MCNT*3/8-1)
// led<=ctrl[2];
// else if (counter==MCNT/2-1)
// led<=ctrl[3];
// else if (counter==MCNT*5/8-1)
// led<=ctrl[4];
// else if (counter==MCNT*3/4-1)
// led<=ctrl[5];
// else if (counter==MCNT*7/8-1)
// led<=ctrl[6];
// else if (counter==MCNT-1)
// led<=ctrl[7];
// else led<=led;
// end
仿真验证代码
`timescale 1ns / 1ns
module counter_led_3_tb;
reg clk,rst;
reg [7:0]ctrl;
wire led;
counter_led_3
#(.MCNT(100000))
counter_led_3(
.clk(clk),
.rst(rst),
.led(led),
.ctrl(ctrl)
);
initial clk=1;
always #10 clk=~clk;
initial begin
rst=0;
ctrl=0;
#205;
rst=1;
#2000;
ctrl=8'b1000_0110; //指定亮灭顺序是1000_0110
#20000000;
$stop;
end
endmodule
ctrl=8'b1000_0110; //指定亮灭顺序是1000_0110
这里再看led的波形图的时候应该是反过来看(01100001)而不是1000_0110.因为是从低往高位看的。
5.让led灯按照指定的亮灭模式亮灭,亮灭模式未知,由用户随机指定。8个变化状态为一个循环,每个状态的时间值可以根据不同的应用场景选择。
每个状态的时间长短位置,所以在输入端引入一个时间值input [31:0]T; 这里为了让每个状态的时间够长,所以特意设置为32位。
module counter_led_4(
clk,
rst,
ctrl,
T,
led
);
input clk,rst;
input [31:0]T; //T代表的是单个状态的时间T
output reg led;
input [7:0]ctrl;
reg [31:0]counter; //第一个计数器的位数要和T的位数相同,防止不够算
always@(posedge clk,negedge rst)
begin
if (!rst)
counter<=0;
else if (counter==T-1) //当计数到T时,置0
counter<=0;
else
counter<=counter+1;
end
reg [2:0]counter2; //这里引入第二个计数器,来计算什么时候切换下一个状态
always@(posedge clk,negedge rst)
begin
if (!rst)
counter2<=0;
else if(counter==T-1)
counter2<=counter2+1'b1; //如果计数到T时间,切换下一个状态
else
counter2<=counter2;
end
always@(posedge clk,negedge rst)
begin
if (!rst)
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
end
endmodule
这里一共引入了两个计数器,和一个输入端T。T的含义是:每个状态的时间长短(由用户来定义)。第一个计数器的目的是,当技术时间达到T时,就切换下一个状态(共八个状态)。
仿真验证代码
`timescale 1ns / 1ns
module counter_led_4_tb;
reg clk,rst;
reg [7:0]ctrl;
reg [31:0]T;
wire led;
counter_led_4 counter_led_4(
.clk(clk),
.rst(rst),
.led(led),
.ctrl(ctrl),
.T(T)
);
initial clk=1;
always #10 clk=~clk;
initial begin
rst=0;
ctrl=0;
T=0;
#205;
rst=1;
#2000;
T=2500;
ctrl=8'b1010_0110;
#20000000;
$stop;
end
endmodule
这里为了仿真波形方便观察,并没有给T设置一个很大的指4,只设置了2500.给八个状态的控制端ctrl设置为10100_110。
在运行仿真前,现将刚刚的tb文件设置为顶层,在观察。不然观察到的波形就是原来顶层文件的波形。
仿真波形与理论相符。