【FPGA】数码管电子时钟

这篇具有很好参考价值的文章主要介绍了【FPGA】数码管电子时钟。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一丶数码管介绍

Cyclone IV开发板上的数码管一共有6个,我们每次只能选择其中一个显示,怎么解决电子时钟时、分、秒同时显示呢?要实现电子时钟首先要了解什么是余晖效应

余晖效应一般指视觉暂留。 视觉暂留现象即视觉暂停现象(Persistence of vision,Visual staying phenomenon,duration of vision)又称“余晖效应”。只要数码管位选信号切换得足够快,数码管由亮到灭这一过程是需要一段时间的,由于时间很短,我们的眼睛是没有办法分清此时此刻数码管的状态,给人的感觉就是数码管是一直亮的。以此来达到欺骗人眼的效果,这样就可以实现同时显示时、分、秒。

【FPGA】数码管电子时钟

二丶任务描述

使用数码管设计电子时钟,计数器部分有3种实现方法:

①.采用1个计数器,模为24x60x60;
②.采用3个计数器,模分别为24、60、60;
③.采用6个计数器分别计数时、分、秒的个位、十位;

方法1:计数器个数少,设计简单,但是后面数码管译码时,需要对计数值取余、取整,分离出时、分、秒的个位和十位,比较耗费组合逻辑资源;
方法2:3个计数器,后面数码管译码时,需要对时、分、秒计数值取余、取整,分离出时、分、秒的个位和十位,比较耗费组合逻辑资源;
方法3:6个计数器,相对复杂一点,但是计数值直接就是时、分、秒的个位和十位值,不需要除法器进行取余、取整操作,使用的触发器资源略多,但节省组合逻辑资源。

因为本文是作为作者stark-lin: 数码管电子时钟的拓展,原文使用了方法1,我们这里选择方法3

【FPGA】数码管电子时钟

最后实现上面图片的效果,由于开发板上的数码管没有冒号(:),所以我们用小数点代替

三丶系统框图

计时器模块:我们把计时器模块细分了6个计时器,分别计时整个时间的小时的十位和个位,分钟的十位和个位,秒的十位和个位,最后将6个计时器拼接成一个dout_time输出给数码管驱动。与stark-lin的方法1不同,我们不需要对计数器做运算,只需要在数码管驱动中取出对应数码管的数字
(对应dout_time[x:y]的第x到y位,比如我要取出小时的十位,由于小时的十位最大能计时到2,换算成2进制数就是2位的,因为一天24小时嘛,所以应该对应dout_time[19:18])

数码管驱动:对dout_time数值进行译码,产生驱动数码管动态显示数字的位选信号和段选信号。
【FPGA】数码管电子时钟

四丶模块调用

【FPGA】数码管电子时钟

五丶模块原理图

【FPGA】数码管电子时钟

六丶工程源码

1.计数器模块

counter.v:

module counter (
    input  wire         clk             ,
    input  wire         rst_n           ,
    output reg [19:0]   dout_time           //输出时间 HH:MM:SS
);
//计数器
reg  [25:0]    cnt    ;
wire           add_cnt;
wire           end_cnt; 
//S计时器

//个位 (0~9)
reg  [3:0]      cnt_s_bit;
wire            add_cnt_s_bit;
wire            end_cnt_s_bit;
//十位 (0~5)
reg  [2:0]      cnt_s_ten;
wire            add_cnt_s_ten;
wire            end_cnt_s_ten;

//M计时器

//个位 (0~9)
reg  [3:0]      cnt_m_bit;
wire            add_cnt_m_bit;
wire            end_cnt_m_bit;
//十位 (0~5)
reg  [2:0]      cnt_m_ten;
wire            add_cnt_m_ten;
wire            end_cnt_m_ten;

//H计时器

//个位 (0~9)
reg  [3:0]      cnt_h_bit;
wire            add_cnt_h_bit;
wire            end_cnt_h_bit;
//十位 (0~2)
reg  [1:0]      cnt_h_ten;
wire            add_cnt_h_ten;
wire            end_cnt_h_ten;

reg [3:0]       flag;
parameter   MAX_CNT=26'd50_000_000;


//计数器
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        cnt<=0;
    end
    else if (add_cnt) begin
        if (end_cnt) begin
            cnt<=0;
        end
        else
            cnt<=cnt+1;
    end
end

assign add_cnt=1'b1;    
assign end_cnt=add_cnt&&cnt==MAX_CNT-1;

//秒计时器---个位(0~9)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt_s_bit<=0;
    end
    else if (add_cnt_s_bit) begin
        if (end_cnt_s_bit) begin
            cnt_s_bit<=0;
        end
        else
            cnt_s_bit<=cnt_s_bit+1;
    end

end

assign add_cnt_s_bit=end_cnt;
assign end_cnt_s_bit=add_cnt_s_bit&&cnt_s_bit==9;

//秒计时器---十位(0~5)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt_s_ten<=0;
    end
    else if (add_cnt_s_ten) begin
        if (end_cnt_s_ten) begin
            cnt_s_ten<=0;
        end
        else
            cnt_s_ten<=cnt_s_ten+1;
    end

end

assign add_cnt_s_ten=end_cnt_s_bit;
assign end_cnt_s_ten=add_cnt_s_ten&&cnt_s_ten==5;

//分计时器---个位(0~9)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt_m_bit<=9;
    end
    else if (add_cnt_m_bit) begin
        if (end_cnt_m_bit) begin
            cnt_m_bit<=0;
        end
        else
            cnt_m_bit<=cnt_m_bit+1;
    end

end

assign add_cnt_m_bit=end_cnt_s_ten;
assign end_cnt_m_bit=add_cnt_m_bit&&cnt_m_bit==9;

//分计时器---十位(0~5)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt_m_ten<=5;
    end
    else if (add_cnt_m_ten) begin
        if (end_cnt_m_ten) begin
            cnt_m_ten<=0;
        end
        else
            cnt_m_ten<=cnt_m_ten+1;
    end

end

assign add_cnt_m_ten=end_cnt_m_bit;
assign end_cnt_m_ten=add_cnt_m_ten&&cnt_m_ten==5;

//时计时器---个位(0~9)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt_h_bit<=3;
    end
    else if (add_cnt_h_bit) begin
        if (end_cnt_h_bit) begin
            cnt_h_bit<=0;
        end
        else
            cnt_h_bit<=cnt_h_bit+1;
    end

end

assign add_cnt_h_bit=end_cnt_m_ten;
assign end_cnt_h_bit=add_cnt_h_bit&&cnt_h_bit==flag;


//时计时器---十位(0~2)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt_h_ten<=2;
    end
    else if (add_cnt_h_ten) begin
        if (end_cnt_h_ten) begin
            cnt_h_ten<=0;
        end
        else
            cnt_h_ten<=cnt_h_ten+1;
    end

end

assign add_cnt_h_ten=end_cnt_h_bit;
assign end_cnt_h_ten=add_cnt_h_ten&&cnt_h_ten==2;

//判断小时计时器十位是否记到 2
always @(*) begin
    if (cnt_h_ten==2) begin
        flag=4'd3;
    end
    else
        flag=4'd9;
end

//dout_time输出
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        dout_time<=20'b0;
    end
    else
        dout_time<={cnt_h_ten,cnt_h_bit,cnt_m_ten,cnt_m_bit,cnt_s_ten,cnt_s_bit};  //拼接成 HH:MM:SS
end
endmodule //counter

2.数码管驱动模块

seg_driver:

module seg_driver (
    input  wire          clk,
    input  wire          rst_n,
    input  wire [19:0]   dout_time,
    output reg  [5:0]    sel,
    output reg  [7:0]    seg
);
reg [3:0]       seg_flag;
reg             dot;  //小数点  用来显示  HH.MM.SS  这样的格式

//10ms计时器---用来切换数码管位选,以达到轮流显示时间的各位(肉眼可以看到动态的时间计数)
reg [15:0]      cnt;
wire            add_cnt;
wire            end_cnt;

parameter       MAX_CNT =50_000    ,
                ZERO    =7'b100_0000,
                ONE     =7'b111_1001,
                TWO     =7'b010_0100,
                THREE   =7'b011_0000,
                FOUR    =7'b001_1001,
                FIVE    =7'b001_0010,
                SIX     =7'b000_0010,
                SEVEN   =7'b111_1000,
                EIGHT   =7'b000_0000,
                NINE    =7'b001_0000;



//计时器
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        cnt<=0;
    end
    else if(add_cnt) begin
        if (end_cnt) begin
            cnt<=0;
        end
        else
            cnt<=cnt+1;
    end
end
assign add_cnt=1'b1;
assign end_cnt=add_cnt&&cnt==MAX_CNT-1;

//切换数码管位选
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        sel<=6'b111_110;
    end
    else if(cnt==MAX_CNT-1) begin
        sel<={sel[4:0],sel[5]};
    end
end  

//切换数码管段选
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        seg_flag<=0;
    end
    else begin
        case (sel)
            6'b111_110: begin seg_flag<=dout_time[19:18]; dot<=1'b1;end  //小时 十位
            6'b111_101: begin seg_flag<=dout_time[17:14]; dot<=1'b0;end  //小时 个位
            6'b111_011: begin seg_flag<=dout_time[13:11]; dot<=1'b1;end  //分钟 十位
            6'b110_111: begin seg_flag<=dout_time[10:7];  dot<=1'b0;end  //分钟 个位
            6'b101_111: begin seg_flag<=dout_time[6:4];   dot<=1'b1;end  //秒   十位
            6'b011_111: begin seg_flag<=dout_time[3:0];   dot<=1'b1;end  //秒   个位
            default :seg_flag<=0;
        endcase
    end
end


//段选译码
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        seg<=8'b1111_1111;
    end
    else begin
        case (seg_flag)     
            0:  seg<={dot,ZERO}    ;
            1:  seg<={dot,ONE}     ;
            2:  seg<={dot,TWO}     ;
            3:  seg<={dot,THREE}   ;
            4:  seg<={dot,FOUR}    ;
            5:  seg<={dot,FIVE}    ;
            6:  seg<={dot,SIX}     ;
            7:  seg<={dot,SEVEN}   ;
            8:  seg<={dot,EIGHT}   ;
            9:  seg<={dot,NINE}    ;
            default: seg<=8'b1111_1111;
        endcase
    end
end

endmodule //seg_driver

3.顶层模块

top.v:

module top (
    input  wire       clk         ,  //系统时钟
    input  wire       rst_n       ,  //复位信号
    output wire [5:0] sel         ,  //数码管位选
    output wire [7:0] seg            //数码管段选
);
wire [19:0]     dout_time;

//例化计时模块
counter u_counter(
    .clk        (clk)       ,
    .rst_n      (rst_n)     ,
    .dout_time  (dout_time)   //输出时间 HH:MM:SS
);

//例化数码管驱动
seg_driver u_seg_driver(
    .clk            (clk)   ,
    .rst_n          (rst_n) ,
    .sel            (sel)   ,
    .seg            (seg)   ,
    .dout_time      (dout_time)
);
endmodule //top

七丶仿真测试

1.TestBench

`timescale 1ns/1ns
module tb_top();
reg              clk;
reg              rst_n;
wire  [5:0]      sel;
wire  [7:0]      seg;
top u_top(
    .clk        (clk)       ,
    .rst_n      (rst_n)     ,
    .sel        (sel)       ,
    .seg        (seg)
);
defparam u_top.u_counter.MAX_CNT=2;
defparam u_top.u_seg_driver.MAX_CNT=2;

always #10 clk=~clk;
initial begin
    clk=1;
    rst_n=1;
    #100;
    rst_n=0;
    #100;
    rst_n=1;
    #200000;
    $stop;
end

endmodule

2.仿真结果

【FPGA】数码管电子时钟

八丶管脚信息

【FPGA】数码管电子时钟

九丶上板验证

数码管电子时钟

十丶源码

https://github.com/xuranww/digital_clock.git文章来源地址https://www.toymoban.com/news/detail-473806.html

到了这里,关于【FPGA】数码管电子时钟的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • FPGA课程设计——数字电子时钟VERILOG(基于正点原子新起点开发板,支持8位或6位共阳极数码管显示时分秒毫秒,可校时,可设闹钟,闹钟开关,led指示)

    2019   级    电子科学与技术   专业FPGA课程设计 报   告 2022  年 5 月 20 日 多功能数字电子钟的设计 摘要 电子设计自动化(EDA)是一种实现电子系统或电子产品自动化设计的技术,使用EDA技术设计的结果既可以用FPGA / CPLD来实施验证,也可以直接做成专用集成电路(ASIC)。

    2024年02月03日
    浏览(43)
  • FPGA学习—通过数码管实现电子秒表模拟

    请参阅博主以前写过的一篇电子时钟模拟,在此不再赘述。 https://blog.csdn.net/qq_54347584/article/details/130402287 项目说明:本次项目是为了通过数码管实现秒表模拟。其中,六位数码管分别显示秒表的分位,秒位,毫秒位(由于毫秒有三位,在此只取百位和十位),其中分位和秒位

    2024年02月14日
    浏览(44)
  • C51单片机的电子时钟(数码管显示+独立按键模块修改及暂停时间)

    IMG_1120 通过查看这三个原理图我们可以得知控制K1、K2、K3及K4是通过P31、P30、P32及P33来实现的,控制8个数码管是P22、P23及P24来实现, 控制发光二极管则由P00-P07来实现。 代码分为三部分分别为main.c、key.h、key.c scankey()函数的主要代码,通过软件入手提高系统的可靠性,防止外

    2024年02月05日
    浏览(52)
  • 基于RASC的keil电子时钟制作(瑞萨RA)(6)----定时器驱动数码管

    要想让每个数码管显示不同的数字,但是数码管必须依次地被持续驱动,数码管之间的刷新速度应该足够快,这样就看不出来数码管之间在闪烁。刷新频率可以设置为2ms刷新一次,这样人眼就看不出闪烁了。 首先需要准备一个开发板,这里我准备的是芯片型号R7FA2E1A72DFL的开

    2024年02月15日
    浏览(42)
  • 51单片机(数码管可调时钟)

    1.数码管(共阴极)如何显示数字:位选+段选(单个) 位选:138译码器通过P22、P23、P24三个端口输入二进制数(011、000等)来选择连同译码器右边的哪一条线,而这些线又分别连着数码管的LED12345678、决定选择哪一个来显示数字 段选:决定输出什么数字,数码管下方又连着一

    2024年02月05日
    浏览(46)
  • 单片机电子元器件-数码管

    把所有数码管的阳极接到一起形成公共阳极COM 数码管 共阳极COM 接到 5V 电源 把所有数码管的阴极接到一起形成公共阴极COM 数码管 共阴极COM 接到 地 GND 上  八段 数码管 和 七段数码管, 多了一个 小数点 DP 一个数码管有 10 个引脚  ,显示 8  字  一个数码管 有8个小的发光二

    2024年02月10日
    浏览(56)
  • 【个人笔记】51单片机串口通信的字符串接收和发送,串口通信调节数码管显示时钟(串口通信,定时器,数码管)

           目的:利用PROTUES仿真软件、串口调试助手、虚拟串口,搭建单片机与PC通信仿真平台,熟悉单片机串口的配置及与PC机的通信方法;尝试制定通信协议,单片机根据通信协议解析接收到的内容,并根据接收的指令执行相应的操作。 基本功能: 1.时分秒的动态显示。

    2024年02月11日
    浏览(59)
  • 静态数码管——FPGA

    环境: 1、Quartus18.0 2、vscode 3、板子型号:EP4CE6F17C8 要求: 六位数码管全选,每间隔0.5s轮流显示0~F。 静态与动态数码管: 静态数码管 : 在静态显示中,只考虑段选信号。在不同的时刻,各个位选信号保持不变,并根据真值表,选择要显示的数字或者字母。 动态数码管 :

    2024年02月16日
    浏览(42)
  • FPGA——静态数码管

    quartus 18.1 modelsim vscode Cyclone IV开发板 我们使用的数码管是8段数码管,每段是由led组成。通过控制每段led的亮灭,来控制数码管显示不同的数字和字母。 数码管分为共阴极和共阳极,共阳极数码管如图所示,a—dp为输入端,全部在二极管的负极,二极管的正极极共同接+5v(高电

    2024年02月16日
    浏览(36)
  • Arduino UNO驱动TM1637四位时钟数码管显示时间

    TM1637 是一种带键盘扫描接口的LED(发光二极管显示器)驱动控制专用电路,内部集成有MCU 数字接口、数据锁存器、LED 高压驱动、键盘扫描等电路。  显示模式(8 段×6 位),支持共阳数码管输出  键扫描(8×2bit),增强型抗干扰按键识别电路  辉度调节电路(占空比

    2024年02月12日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包