二、用秒计数器驱动数码管实现0-9秒循环显示逻辑设计
所需软件
Verilog编程软件:Lattice Diamond(3.11.0.396.4_Diamond_x64)
Verilog仿真软件:ModelSim SE-64 10.2c(modelsim-win64-10.2c-se)
方法:用always语句实现秒计数器驱动数码管循环显示0-9秒逻辑设计
符号图:
Verilog代码:
Part1:Test11_top.v文件(Verilog工程文件)
//2022-06-02
//用秒计时器驱动数码管实现0-9秒循环显示
module Test11_top(clk,res,a_g);
input clk;
input res;
output[6:0] a_g; //顶层内部信号,若只是为了连接,则定义成wire型即可
parameter frequency_clk=24; //假设系统时钟为24KHz
reg[24:0] con_t; //基于系统时钟的秒脉冲分频计数器。0到23999999计数,每循环一圈就是1秒。设系统时钟频率为24MHz。十进制的24兆(24000000D=?0001011011100011011000000000?B)转化为二进制需要占用25位。
reg s_pulse; //秒脉冲尖。1秒出现一次。两个秒脉冲尖之间表示一个系统时钟宽度。当秒脉冲分频计数器con_t计数为0后,秒脉冲尖为1;当秒脉冲分频计数器con_t计数为1后时起,秒脉冲尖为0(无秒脉冲尖),直到秒脉冲分频计数器计数再次为0后,秒脉冲尖再次为1,如此反复。
reg[3:0] s_num=0; //秒计数。对秒脉冲出现的次数进行计数,计数范围是0-9。
//对s_num赋初值0
//虽然a_g是输出端口,但是若想在always语句里赋值,也需要把它定义成reg型变量。等同于一个触发器,故需要对其复位。
reg[6:0] a_g=7'b1111111; //对数码管赋初值,显示“8”
always@(posedge clk or negedge res) begin
if(~res) begin
con_t<=0;s_pulse<=0;s_num<=0;a_g=7'b1111111;
end
else begin
//秒脉冲分频计数器con_t,计数范围0-23999999
if(con_t==frequency_clk*1000-1) begin //如果秒脉冲分频计数器con_t的计数值(1秒之内秒脉冲的个数)达到分频系数:frequency_clk*1000-1
con_t<=0; //对秒脉冲分频计数器清零
end
else begin //如果秒脉冲分频计数器con_t的计数值(1秒之内秒脉冲的个数)未达到分频系数:frequency_clk*1000-1
con_t<=con_t+1; //秒脉冲分频计数器继续计数
end
//秒脉冲尖发生器s_pulse,电平状态1或0
if(con_t==0) begin //如果秒脉冲分频计数器con_t的计数值为零
s_pulse<=1; //将秒脉冲发生器s_pulse置1,秒脉冲是“尖”的形态,得到秒脉冲尖
end
else begin //如果秒脉冲分频计数器con_t的计数值不为零
s_pulse<=0; //将秒脉冲发生器s_pulse置0,秒脉冲不是“尖”的形态
end
//秒(秒脉冲尖)计数器s_num,计数范围0-9
if(s_pulse) begin //如果秒脉冲发生器s_pulse不为0
if(s_num==9) begin //如果秒计数器s_num记录的秒脉冲尖(秒脉冲发生器s_pulse为1的状态)的个数已经达到9个
s_num<=0; //对秒计数器清零
end
else begin //如果秒计数器s_num记录的秒脉冲尖(秒脉冲发生器s_pulse为1的状态)的个数未达到9个
s_num<=s_num+1; //秒计数器+1,用于对秒脉冲尖(秒脉冲发生器s_pulse为1的状态)计数。两个秒脉冲尖之间的时间间隔是1秒。
end
end
//用case语句实现数码管逻辑
case(s_num) //用case语句实现组合逻辑
4'd0: begin a_g<=7'b1111110; end //当num为十进制的0时,a_g输出为1111110,数码管显示0。
4'd1: begin a_g<=7'b0110000; end //当num为十进制的1时,a_g输出为011_0000,数码管显示1。
4'd2: begin a_g<=7'b1101101; end //当num为十进制的2时,a_g输出为110_1101,数码管显示2。
4'd3: begin a_g<=7'b1111001; end //当num为十进制的3时,a_g输出为111_1001,数码管显示3。
4'd4: begin a_g<=7'b0010011; end //当num为十进制的4时,a_g输出为001_0011,数码管显示4。
4'd5: begin a_g<=7'b1011011; end //当num为十进制的5时,a_g输出为101_1011,数码管显示5。
4'd6: begin a_g<=7'b1011111; end //当num为十进制的6时,a_g输出为101_1111,数码管显示6。
4'd7: begin a_g<=7'b1110000; end //当num为十进制的7时,a_g输出为111_0000,数码管显示7。
4'd8: begin a_g<=7'b1111111; end //当num为十进制的8时,a_g输出为111_1111,数码管显示8。
4'd9: begin a_g<=7'b1111011; end //当num为十进制的9时,a_g输出为111_1011,数码管显示9。
//Verilog中的数字表达式:<位宽><进制><数字>
//'b:二进制,eg 4'b1010,表示4位二进制数1010
//'h:十六进制,eg 8'hef、4'ha
//'d:十进制,eg 2'd3(二位的十进制数3)、4'd15(不能写16,4位最大是15,意为十进制数15,0000001111)
default: begin a_g<=7'b0000001; end //当num不在0-9范围时,a_g输出为000_0001,数码管显示中杠“-”。
endcase
end
end
endmodule
Part2:Test11_top_tb.v文件(Verilog仿真文件)
//2022-06-02
//用秒计时器驱动数码管实现0-9秒循环显示-testbench of Test11_top
`timescale 1ns/10ps
module Test11_top_tb;
reg clk_in;
reg res_in;
wire[6:0] a_g_out; //仿真输出变量
Test11_top Test11_top( //s_counter:module名;U1:例化名。为module名,不要带上“_tb”
.clk(clk_in),
.res(res_in),
.a_g(a_g_out) //括号中是顶层信号名,若不是端口,则需要定义成wire型完成连接
);
initial begin
clk_in<=0;res_in<=0;
#17 res_in<=1; //过17ns,解除对时钟的复位
#3000000 $stop; //运行时长3000000ns。24KHz,计数24000次,一次10ns,循环一周期(计数一秒)为240000ns,则完成0~9的计数需要运行2400000ns。
end
always #5 clk_in<=~clk_in; //设定一个以10ns为周期的运行时钟
endmodule
仿真波形:
注意事项
1、对于顶层的内部信号,若只是为了连接,则定义成wire型即可;
2、若设定系统时钟为24KHz,且把分频系数选为23999,则需计数24000次,设定计数一次用时10ns(设定运行时钟周期为10ns),则循环一周期(计数1秒)为240000ns,那么完成0~9秒的计数需要运行2400000ns。