本次学习的内容来自B站:Verilog零基础入门
目录
一、秒计数器
1.原理及代码设计
秒计数器是计数器的一种,昨天学习了计数器的知识。我们知道计数器可以通过时钟的变化进行+1的操作,但是这个变化是由时钟周期决定的,在仿真中可以我们自定义,但是在实际开发板中,每一块开发板的晶振都是固定的,也就是时钟周期是固定的。如果在这种情况下我们想进行精准的秒计数,又应该怎么做呢?这时,我们就需要进行分频操作。以50MHz晶振源为例,在1秒钟内会产生50M个时钟周期,那么我们就可以每过50M个时钟周期对计数器进行加一。这样就可以实现任意时间段的计数器了,比如0.5s(每过25M个时钟周期对计数器进行加一),这样就构成了我们的秒计数器。(对于分频,由于本人只是初学者,也有许多地方不太明白,以上只是我的个人理解,如果有错请大佬们纠正)。
下面就让我们来实现代码的编写吧!
//2023.4.13 Bread
//秒计数器,0-9循环
`timescale 1ns/1ps
module s_counter(
clk,
rst,
s_num
);
input clk;
input rst;
output[3:0] s_num;
parameter frequency_clk=24;//24KHz
reg[15:0] con_t;//秒脉冲分频计数器
reg s_pulse;//秒脉冲尖;
reg[3:0] s_num;
always@(posedge clk or negedge rst)
if(~rst)begin
con_t<=0;s_pulse<=0;s_num<=0;
end
else begin
if(con_t==frequency_clk*1000-1)begin
con_t<=0;
end
else begin
con_t<=con_t+1;
end
if(con_t==0)begin
s_pulse<=1;
end
else begin
s_pulse<=0;
end
if(s_pulse) begin
if(s_num==9) begin
s_num<=0;
end
else begin
s_num<=s_num+1;
end
end
end
endmodule
本次示例假设时钟频率为24KHz(Hz太大仿真太麻烦,在实际开发板实验中需要使用开发板的时钟频率!)
其中con_t用于记录时钟周期数,每过一个时钟周期加一,当con_t累加到23999时,产生一个秒脉冲s_pulseb,表示过了一秒,计数器加一,这样我们的秒计数器就完成了。下面编写testbench文件:
module s_counter_tb;
reg clk;
reg rst;
wire[3:0] s_num;
s_counter s_counter(
.clk(clk),
.rst(rst),
.s_num(s_num)
);
initial begin
clk<=0;rst<=0;
#17 rst<=1;
#1000 $stop;
end
always #5 clk<=~clk;
endmodule
这里要注意以下,我们在这里只经过1000ns就stop是很不合理的,但是把他写大一点又太奇怪了 但是这里不用担心,一会仿真的时候会有解决办法!同时这里的时钟周期也要注意,如果使用开发板实验,一定要根据开发板的时钟周期来,我们这里只是为了方便,随便选择的一个数(10ns),其实这也是不合理的,因为我们假设的时钟频率是24KHz,那么他真正的周期应该是纳秒!
2.Modelsim仿真
Modelsim仿真与之前的类似,但是因为我们这里的时钟频率和截至时间太短,所以需要一点额外的步骤才能得到想要的结果:
首先我们对编写的文件编译后,simulate我们的tb文件,将想要观察的波形加入到波形图中,点击Restart和Runall后,得到如下结果:
可以看到,这里的计数器只得到了1就停止了,原因就是上面说的我们的时间太短,这里我们需要点击上方的ContinueRun,点击之后再点击Break,就可以得到我们想要的波形啦。
这里我们就得到了一个从0-9计数的秒计数器了。
二、七段数码管动态显示
1.原理及代码设计
我们之前所设计的七段数码管同样只能根据一个时钟周期(准确的说是根据输入值)改变显示的内容,下面我们将秒计数器加入到里面实现七段数码管的动态显示吧!
//2023.4.14 Bread
//七段数码管动态显示
module seq_dec_dyn(clk,rst,a_g);
input clk;
input rst;
output[6:0] a_g;
reg[6:0] a_g;
reg[3:0] s_num;
reg[24:0] con_t;//秒脉冲分频计数器
reg s_pulse;//秒脉冲尖;
parameter frequency_clk=24;
always@(posedge clk or negedge rst)
if(~rst)begin
con_t<=0;s_pulse<=0;s_num<=0;
end
else begin
if(con_t==frequency_clk*1000-1)begin
con_t<=0;
end
else begin
con_t<=con_t+1;
end
if(con_t==0)begin
s_pulse<=1;
end
else begin
s_pulse<=0;
end
if(s_pulse) begin
if(s_num==9) begin
s_num<=0;
end
else begin
s_num<=s_num+1;
end
end
end
always @ (s_num) begin
case(s_num)
4'd0: begin a_g<=7'b111_1110; end
4'd1: begin a_g<=7'b011_0000; end
4'd2: begin a_g<=7'b110_1101; end
4'd3: begin a_g<=7'b111_1100; end
4'd4: begin a_g<=7'b011_0011; end
4'd5: begin a_g<=7'b101_1011; end
4'd6: begin a_g<=7'b101_1111; end
4'd7: begin a_g<=7'b111_0000; end
4'd8: begin a_g<=7'b111_1111; end
4'd9: begin a_g<=7'b111_1011; end
default begin a_g<=7'b000_0001; end
endcase
end
endmodule
相应的testbench如下:
//----testbench----
module seq_dec_dyn_tb;
reg clk;
reg rst;
wire[6:0] a_g;
seq_dec_dyn seq_dec_dyn(
.clk(clk),
.rst(rst),
.a_g(a_g)
);
initial begin
clk<=0;rst<=0;
#17 rst<=1;
#3000 $stop;
end
always #5 clk<=~clk;
endmodule
这里是我根据这两个模块整合重新编写的,按照视频中老师的方法是编写一个top文件,将这两个模块例化进去(应该是这样?)。
但是我这样编写在Modelsim里将信号添加到波形图中不会产生任何波形,加入initial语句又会报错有知道的大佬麻烦不吝赐教!(在Modelsim仿真,top层应该怎么写呢?)
2.Modelsim仿真
按照之前的方法在Modelsim进行仿真,得到的结果如下:
到这里我们的七段数码管动态显示就完成了。可以看到随着计数器数字的改变,我们数码管的显示也是跟着变的,而且刚好显示的数字是和计数器一一对应,这样我们就实现数码管0-9的动态显示了!
总结
以上就是本文的全部内容,实际上对于分频我还有很多不明白的地方,也不知道我自己理解的是否正确,学会fpga还有很长的路要走,希望可以坚持下去吧!