1.数码管简介:
本人用的FPGA板子用的是Cyclone IV ,这个板子的数码管是共阳极的,即当给的信号为0时,才会点亮它,而且数码管的段选信号是六个位置共用的,意味着它不能在同一时间两个位置显示不同的内容,而要想达到同时看到时分秒,只能不断将每个位置的数码管赋予不同的值,并循环亮灭,将时间设置的很短,就能出现“余晖效应”,眼睛能看见的就是六个不同位置同时显示不同的内容。
2.实验思想:
做一个计时器,闹钟,使用六个计数器,分别是对
时的高位,低位
分的高位,低位
秒的高位,低位
秒的低位0-9,逢时进一,即用一个flag1,当计十秒后,flag1=1,并归零,当秒的高位收到flag1,执行+1操作;
秒的高位0-6, 逢六进一,用一个flag2,当计满过6过后,flag2 = 1,并归零 ,当分的低位收到flag2,执行+1操作;
分的低位,0-9,逢十进一,用一个flag3,当计满过10,flag3 = 1,归零 ,分的高位+1;
分的高位,0-6,当计满六,flag4 =1,归零,时的低位+1;
时的低位,0-10, 计满 flag5 = 1,归零,时的高位+1;
时的高位 0-2
当时间为23:59:59时,当计时一秒满的标志传来,将六个计数器全部清零,就意味着这个计时器只能计满24个小时。
3.系统框图
4.程序代码
module clock (
input clk,
input rst_n,
output reg[5:0] sel,
output reg[7:0] seg
);
reg [25:0] cnt; //1s寄存器
reg [25:0] cnt_10ms; //10ms寄存器
parameter MAX_NUM = 26'd5000_0000;//1s
parameter MIN_NUM = 26'd5_0000 ; //1ms数码管每1ms变换一次亮的位置,由于时间太短,人眼看着就是都在亮着。
reg [3:0] sec_low;//秒的低位寄存器,0-9
reg [3:0] sec_high;//秒的高位寄存器 ,0-5
reg [3:0] min_low;//分的低位寄存器0-9
reg [3:0] min_high;//分的低位寄存器0-5
reg [3:0] h_low;//时的低位寄存器0-9
reg [3:0] h_high;//时的低位寄存器0-2
reg flag1; //秒低位寄存满标志,计满为1,然后高位加一
reg flag2; //秒高位寄存满标志,计满唯一,然后分低位加一
reg flag3; //分低位寄存满标志,计满唯一,然后分高位加一
reg flag4;//分高位寄存满标志,计满为1,然后时低位加一
reg flag5;//时低位寄存满编制,计满为1,然后时高位加一
reg [2:0]flag6;//10ms计满标志,为1时数码管位选信号切换
reg [3:0] value; //对数码管数值的寄存
always @(posedge clk or negedge rst_n) begin //1s计时模块
if(!rst_n)begin
cnt <= 26'd0;
end
else if(cnt == MAX_NUM - 1'd1)begin
cnt <= 26'd0;
end
else begin
cnt <= cnt + 1'd1;
end
end
always @(posedge clk or negedge rst_n) begin //10ms计时模块,且每10ms flag6加一,在0-5循环,代表位选信号。
if(!rst_n)begin
cnt_10ms <= 26'd0;
flag6 <= 3'd0;
end
else if(cnt_10ms == MIN_NUM - 1'd1 && flag6 < 3'd5)begin
cnt_10ms <= 26'd0;
flag6 <=flag6+ 1'd1;
end
else if(cnt_10ms == MIN_NUM -1'd1 && flag6 == 3'd5)begin
flag6 <= 3'd0;
cnt_10ms <= 26'd0;
end
else begin
cnt_10ms <= cnt_10ms +1;
flag6 <= flag6;
end
end
always @(posedge clk or negedge rst_n) begin //秒的低位计数模块
if(!rst_n)begin
sec_low <= 4'd0;
flag1 <= 1'b0;
end
else if(cnt == MAX_NUM - 1'd1)begin
if(sec_low == 4'd9)begin //计满1s并且秒的低位为9时。将sec_low 变为0,flag1变成1,信号给到高位,高位加1;
sec_low <= 4'd0;
flag1 <= 1'b1;
end
else begin
sec_low <= sec_low + 1;
flag1 <=1'b0;
end
end
else if(h_high == 2 && h_low == 3 && min_high ==5 && min_low == 9 && sec_high ==5 && sec_low == 9 && cnt == MAX_NUM _1'd1)begin // 当时间为23:59:59时,并加一秒后,全部归零。
sec_low <= 4'd0;
end
else begin
sec_low <= sec_low;
flag1 <= 1'b0;
end
end
always @(posedge clk or negedge rst_n) begin //秒的高位计数模块
if(!rst_n)begin
sec_high <= 4'd0;
flag2 <= 1'b0;
end
else if(flag1)begin
if(sec_high == 4'd5)begin //当秒的高位为5,且低位计满,传过来flag1==1 时,将flag2赋值为1,并将高位归零。
sec_high <= 4'd0;
flag2 <= 1'b1;
end
else begin
sec_high <= sec_high + 1'd1;
flag2 <= 1'b0;
end
end
else if(h_high == 2 && h_low == 3 && min_high ==5 && min_low == 9 && sec_high ==5 && sec_low == 9 && cnt == MAX_NUM _1'd1)begin // 当时间为23:59:59时,并加一秒后,全部归零。
sec_high <= 4'd0;
end
else begin
sec_high <= sec_high;
flag2 <= 1'b0;
end
end
always @(posedge clk or negedge rst_n) begin //分的低位计数模块
if(!rst_n)begin
min_low <= 4'd0;
flag3 <= 1'b0;
end
else if(flag2)begin
if(min_low == 4'd9)begin //当分的低位为9,且秒的高位计满,传过来flag2==1 时,将flag3赋值为1,并将低位归零。
min_low <= 4'd0;
flag3 <= 1'b1;
end
else begin
min_low <= min_low + 1'd1;
flag3 <= 1'b0;
end
end
else if(h_high == 2 && h_low == 3 && min_high ==5 && min_low == 9 && sec_high ==5 && sec_low == 9 && cnt == MAX_NUM _1'd1)begin // 当时间为23:59:59时,并加一秒后,全部归零。
min_low <= 4'd0;
end
else begin
min_low <= min_low;
flag3 <= 1'b0;
end
end
always @(posedge clk or negedge rst_n) begin //分的高位计数模块
if(!rst_n)begin
min_high <= 4'd0;
flag4 <= 1'b0;
end
else if(flag3)begin
if(min_high == 4'd5)begin //当分的高位为5,且分的低位计满,传过来flag3==1 时,将flag4赋值为1,并将低位归零。
min_high <= 4'd0;
flag4 <= 1'b1;
end
else begin
min_high <= min_high + 1'd1;
flag4 <= 1'b0;
end
end
else if(h_high == 2 && h_low == 3 && min_high ==5 && min_low == 9 && sec_high ==5 && sec_low == 9 && cnt == MAX_NUM _1'd1)begin // 当时间为23:59:59时,并加一秒后,全部归零。
min_high <= 4'd0;
end
else begin
min_high <= min_high;
flag4 <= 1'b0;
end
end
always @(posedge clk or negedge rst_n) begin //时的低位计数模块
if(!rst_n)begin
h_low <= 4'd0;
flag5 <= 1'b0;
end
else if(flag4)begin
if(h_low == 4'd9)begin //当时的低位为9,flag4 ==1 时,将低位归零,flag5变1;
h_low <= 4'd0;
flag5 <= 1'b1;
end
else begin
h_low <= h_low + 1'd1;
flag5 <=1'b0;
end
end
else if(h_high == 2 && h_low == 3 && min_high ==5 && min_low == 9 && sec_high ==5 && sec_low == 9 && cnt == MAX_NUM _1'd1)begin // 当时间为23:59:59时,并加一秒后,全部归零。
h_low <= 4'd0;
end
else begin
h_low <= h_low;
flag5 <= 1'b0;
end
end
always @(posedge clk or negedge rst_n) begin //时的高位计数模块
if(!rst_n)begin
h_high <= 4'd0;
end
else if(flag5)begin
h_high <= h_high +1;
end
else if(h_high == 2 && h_low == 3 && min_high ==5 && min_low == 9 && sec_high ==5 && sec_low == 9 && cnt == MAX_NUM _1'd1)begin // 当时间为23:59:59时,并加一秒后,全部归零。
h_high <= 4'd0;
end
else begin
h_high <= h_high;
end
end
这里开始可以将以下代码做成一个数码管控制模块,诶,我就是不换,就是玩,换的话可以将flag6做成输出传递到此模块,其他都不用改
always @(posedge clk or negedge rst_n) begin //位选信号定义
if(!rst_n)begin
sel <= 6'b000_000;
value <= 4'd0;
end
else begin
case (flag6)
3'd0 :begin
sel <= 6'b111_110;
value <= h_high;
end
3'd1 :begin
sel <= 6'b111_101;
value <= h_low;
end
3'd2 : begin
sel <= 6'b111_011;
value <= min_high;
end
3'd3 :begin
sel <= 6'b110_111;
value <= min_low;
end
3'd4 :begin
sel <= 6'b101_111;
value <= sec_high;
end
3'd5 :begin
sel <= 6'b011_111;
value <= sec_low;
end
default: sel <= 6'b111_111;
endcase
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
seg <= 8'b1100_0000;//初始化显示0
end
else begin
case(value)
4'd0: seg <= 8'b1100_0000;//数码管显示0
4'd1: seg <= 8'b1111_1001;//数码管显示1
4'd2: seg <= 8'b1010_0100;//数码管显示2
4'd3: seg <= 8'b1011_0000;//数码管显示3
4'd4: seg <= 8'b1001_1001;//数码管显示4
4'd5: seg <= 8'b1001_0010;//数码管显示5
4'd6: seg <= 8'b1000_0010;//数码管显示6
4'd7: seg <= 8'b1111_1000;//数码管显示7
4'd8: seg <= 8'b1000_0000;//数码管显示8
4'd9: seg <= 8'b1001_0000;//数码管显示9
default: seg <= 8'b1100_0000;//数码管显示0
endcase
end
end
endmodule
6还有两种方法实现时钟,
第一,使用一个计数器,每一秒加一,然后用除法,取余等操作将时分秒的高低位计算出来,然后通过数码管显示出来。
第二,可使用三个计时器,分别是时分秒的计时器,上限分别为23,59,59,再通过除法和取余计算。
这两种虽然计数器数量较少,但是消耗的组合逻辑比较多,而FPGA正好缺的就是组合逻辑资源,触发器资源反倒不缺,所以,使用六个计数器的方法比较适合FPGA。
5.测试代码
`timescale 1ns/1ps
module tb_clock();
reg clk;
reg rst_n;
defparam u_clock.MAX_NUM = 50;
defparam u_clock.MIN_NUM = 5;
always #10 clk = ~clk;
initial begin
clk = 1'b0;
rst_n = 1'b0;
#10 rst_n = 1'b1;
#10000 $stop;
end
clock u_clock(
.clk (clk ),
.rst_n (rst_n),
.sel (sel ),
.seg(seg)
);
endmodule
6.仿真截图
文章来源:https://www.toymoban.com/news/detail-449560.html
7.上板测试
数码管时钟文章来源地址https://www.toymoban.com/news/detail-449560.html
到了这里,关于数码管电子时钟的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!