FPGA开发——数码管数字时钟的设计

news2024/11/15 6:59:19

一、概述

        数码管数字时钟的基本原理是通过内部的计时电路(如晶振、分频器、计数器等)产生一个稳定的时钟信号,该信号经过处理后被转换为小时、分钟和秒的时间信息。这些信息随后被发送到数码管显示模块,通过控制数码管中不同LED段的亮灭来显示当前的时间。

        数码管数字时钟的显示方式通常采用“HH:MM:SS”的格式,其中“HH”表示小时,“MM”表示分钟,“SS”表示秒。有些高级的数码管时钟还会在显示时间的同时,通过额外的数码管或LED指示灯来显示其他信息,如日期、星期、温度等。

        在本次设计中我们使用6个数码管分别进行“hh.mm.ss”的格式让数码管进行显示,这篇文章我们先进行时钟的单纯显示,在下一篇文章中往里面加入按键灯进行可调的时钟的设计。

二、工程实现

涉及到复杂的代码编写时,我们就需要使用分块化的代码编写思想对不同功能的代码进行分层、分块、分文件编写,最后将各部分进行整理总和,采取这种方式进行代码可以时我们在编写代码时条件清晰,逻辑明确,如果是全部写在一个设计文件里我们的代码就会显得非常多并且就算注释写了不少也回显示杂乱无章。

1、计数器设计代码的编写

新建cnt.v文件,如下:

module cnt(
  input  clk,
  input  rst_n,
  output reg[19:0] dout
);

parameter   TIME_1s =50_000_000;

reg [26:0] cnt_1s;
wire       add_cnt_1s;
wire       end_cnt_1s; 

/*----------------------------------------------------------------
时钟计数器
------------------------------------------------------------------*/

reg [3:0]  cnt_s;//秒数第一位
wire       add_cnt_s;
wire       end_cnt_s; 

reg [2:0] cnt_10s;//秒数第二位
wire       add_cnt_10s;
wire       end_cnt_10s; 

reg [3:0]  cnt_m;//分数第一位
wire       add_cnt_m;
wire       end_cnt_m; 

reg [2:0] cnt_10m;//分数第二位
wire       add_cnt_10m;
wire       end_cnt_10m; 

reg [3:0]  cnt_h;//小时第一位
wire       add_cnt_h;
wire       end_cnt_h; 

reg  [1:0]      cnt_10h;//小时第二位
wire       add_cnt_10h;
wire       end_cnt_10h; 


/*----------------------------------------------------------------
时钟
-----------------------------------------------------------------*/

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
      cnt_1s<=0;
    else if(add_cnt_1s)begin
      if(end_cnt_1s)
        cnt_1s<=0;
      else
        cnt_1s<=cnt_1s+1'b1;
    end
end
assign add_cnt_1s=1'b1;
assign end_cnt_1s=add_cnt_1s && (cnt_1s==TIME_1s-1);

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
      cnt_s<=0;
    else if(add_cnt_s)begin
      if(end_cnt_s)
        cnt_s<=0;
      else
        cnt_s<=cnt_s+1'b1;
    end
end
assign add_cnt_s=end_cnt_1s;
assign end_cnt_s=add_cnt_s && (cnt_s==10-1);

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
      cnt_10s<=0;
    else if(add_cnt_10s)begin
      if(end_cnt_10s)
        cnt_10s<=0;
      else
        cnt_10s<=cnt_10s+1'b1;
    end
end
assign add_cnt_10s=end_cnt_s;
assign end_cnt_10s=add_cnt_10s && (cnt_10s==6-1);

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
      cnt_m<=0;
    else if(add_cnt_m)begin
      if(end_cnt_m)
        cnt_m<=0;
      else
        cnt_m<=cnt_m+1'b1;
    end
end
assign add_cnt_m=end_cnt_10s;
assign end_cnt_m=add_cnt_m && (cnt_m==10-1);

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
      cnt_10m<=0;
    else if(add_cnt_10m)begin
      if(end_cnt_10m)
        cnt_10m<=0;
      else
        cnt_10m<=cnt_10m+1'b1;
    end
end
assign add_cnt_10m=end_cnt_m;
assign end_cnt_10m=add_cnt_10m && (cnt_10m==6-1);

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
      cnt_h<=0;
    else if(add_cnt_h)begin
      if(end_cnt_h)
        cnt_h<=0;
      else
        cnt_h<=cnt_h+1'b1;
    end
end
assign add_cnt_h=end_cnt_10m;
assign end_cnt_h=add_cnt_h && (cnt_h==10-1);

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
      cnt_10h<=0;
    else if(add_cnt_10h)begin
      if(end_cnt_10h)
        cnt_10h<=0;
      else
        cnt_10h<=cnt_10h+1'b1;
    end
end
assign add_cnt_10h=end_cnt_h;
assign end_cnt_10h=add_cnt_10h && ((cnt_10h==2)&&(cnt_h==4));


//数码管输出数据
always @(posedge clk or negedge rst_n)begin
  if(!rst_n)
    dout<= 0;
  else 
    dout<={cnt_10h,cnt_h,cnt_10m,cnt_m,cnt_10s,cnt_s};
end

endmodule

2、数码管驱动代码的编写

新建seg_driver.v文件,如下:

module seg_driver( 
    input				clk		    ,
    input				rst_n	    ,
    input       [19:0]	din		    ,//需要译码显示的数据
    
    output	reg	[5:0]	seg_sel	    ,//数码管片选信号6个
    output	reg	[7:0]	seg_dig	     //数码管段选信号8个
);								 
    //参数定义			 
    parameter TIME_SCAM =50_000 ; //1ms,数码管轮流显示的间隔时间

    //显示每个数字需要亮的灯
    localparam  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;

    //中间信号定义		 
    reg		[23:0]	cnt0    ;//数码管扫描1ms计数器
    wire		    add_cnt0;
    wire		    end_cnt0;

    reg     [3:0]   tmp_data;//每位数码管需要显示的数字
    reg             dot     ;//是否显示小数点的灯

    //1ms计数器
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            cnt0 <= 0;
        end 
        else if(add_cnt0)begin 
            if(end_cnt0)begin 
                cnt0 <= 0;
            end
            else begin 
                cnt0 <= cnt0 + 1;
            end 
        end
    end
    assign add_cnt0 = 1'b1;
    assign end_cnt0 = add_cnt0 && cnt0 == TIME_SCAM-1;

    //循环亮灯  seg_sel 片选信号选择亮哪一个灯,循环过去
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            seg_sel <= 6'b11_1110; //首先亮最右边的灯
        end 
        else if(end_cnt0)begin 
            seg_sel <= {seg_sel[4:0],seg_sel[5]};//循环亮灯
        end 
    end

    //tmp_data,根据片选信号去选择秒、分、时的个位、十位数字 以及是否显示小数点
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            tmp_data <= 0;   //开始都为0  
            dot      <= 1'b1;//开始都不亮小数点的灯
        end
        else begin
            case (seg_sel)
                6'b11_1110:begin tmp_data <= din[3:0]           ;dot <= 1'b1;end
                6'b11_1101:begin tmp_data <= {1'b0,din[6:4]}    ;dot <= 1'b1;end//因为只占了三位,所以前面需要补0,不补也可以自动取低位
                6'b11_1011:begin tmp_data <= din[10:7]          ;dot <= 1'b0;end//dot <= 1'b0亮小数点的灯 
                6'b11_0111:begin tmp_data <= {1'b0,din[13:11]}  ;dot <= 1'b1;end
                6'b10_1111:begin tmp_data <= din[17:14]         ;dot <= 1'b0;end
                6'b01_1111:begin tmp_data <= {2'b00,din[19:18]} ;dot <= 1'b1;end
                default:;
            endcase
        end
    end

    //seg_dig 根据段选信号  选择对应的数字和小数点译码,根据段选信号显示数字
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            seg_dig <= 0;
        end 
        else begin 
            case (tmp_data)
                0:seg_dig <= {dot,ZERO };
                1:seg_dig <= {dot,ONE  };
                2:seg_dig <= {dot,TWO  };
                3:seg_dig <= {dot,THREE};
                4:seg_dig <= {dot,FOUR };
                5:seg_dig <= {dot,FIVE };
                6:seg_dig <= {dot,SIX  };
                7:seg_dig <= {dot,SEVEN};
                8:seg_dig <= {dot,EIGHT};
                9:seg_dig <= {dot,NINE };
                default:;
            endcase      
        end 
    end
    
endmodule

3、顶层文件的编写

新建一个top.v顶层文件,用于将前面两个设计文件行一个链接,将计数器和数码管的数据进行连接。之后实现所需要的功能。

//在数码管显示计数24h24m24s 顶层模块
module top( 
    input				clk		,
    input				rst_n	,

    output		[5:0]	sel	    ,//片选信号,选择哪位数码管显示
    output		[7:0]	dig	     //段选信号,选择哪个led灯点亮
);								 
    //中间信号定义		 
    wire	[19:0]	    dout    ;//在count.v中dout输出为reg,这里连接出去需要更改为wire型

    //模块例化 
    cnt #() cnt_inst(
        .clk        (clk    ),
        .rst_n      (rst_n  ),
        .dout       (dout   )
    );

    seg_driver u_seg(
        .clk        (clk    ),
        .rst_n      (rst_n  ),
        .din        (dout   ),
        .seg_sel    (sel    ),
        .seg_dig    (dig    )
    );

endmodule

三、仿真波形图

这里对于顶层文件进行仿真,所以新建一个top_tb.v文件。

图中我们可以看到在时钟秒的各级计数器计数正常并且数码管显示的值和计数器的器值相互对应,说明我们的设计没啥问题。

’ 

最后经过下板验证,我们观察到数码管从1秒开始一直计数,到这里单纯的数码管时钟设计完成。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1977193.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android读取拨号记录功能

Android读取拨号记录功能 Android读取拨号记录功能 首先会检测应用是否有读取拨号记录的权限 MainActivity.java public class MainActivity extends AppCompatActivity {private ListView listCalls;private List<Map<String, Object>> mapList;private static f…

有界,可积,存在原函数和连续的关系

目录 1.可积和有界的关系 2.连续和可积的关系 3.连续和存在原函数的关系 4.可积和存在原函数没有关系 1.可积和有界的关系 可积必有界&#xff0c;有界不一定可积&#xff0c;反例可以举狄利克雷函数 2.连续和可积的关系 f(x)连续&#xff0c;则一定可积&#xff0c;可积不…

Mac安装nvm以及配置环境变量

安装nvm brew install nvm安装成功后会出现这样一段话: Add the following to your shell profile e.g. ~/.profile or ~/.zshrc:export NVM_DIR"$HOME/.nvm"[ -s "/opt/homebrew/opt/nvm/nvm.sh" ] && \. "/opt/homebrew/opt/nvm/nvm.sh&q…

Substance Painter界面介绍

1 界面介绍01_哔哩哔哩_bilibili 界面 选择texture 笔刷参数 分成不同的材质球 选择不同工具跟着变动 p4

STL序列式容器之list的使用及实现

std::list 和 std::vector 是两种不同的数据结构&#xff0c;std::vector 是基于数组的动态数组&#xff0c;而 std::list 是基于双向链表的数据结构。list适用于需要在序列中频繁执行插入和删除操作的场景。 1.list的特性 双向链表&#xff1a; list是一个双向链表&#xff…

R 语言学习教程,从入门到精通,R的安装与环境的配置(3)

1、R 基础语法 一门新的语言学习一般是从输出 “Hello, World!” 程序开始&#xff0c;R 语言的 “Hello, World!” 程序代码如下&#xff1a; myString <- "Hello, World!" print ( myString )以上示例将字符串 “Hello, World!” 赋值给 myString 变量&#x…

【hive】HiveSQL中两个json解析函数的使用json路径定位小工具

文章目录 1.HiveSQL中两个json解析函数1&#xff09;get_json_object2&#xff09;json_tuple 2.json中key所在层级路径定位小工具 关于json&#xff1a; https://blog.csdn.net/atwdy/article/details/124668815 1.HiveSQL中两个json解析函数 1&#xff09;get_json_object …

使用 Squid 搭建 Http 代理服务器隐藏 IP

在一些情况下&#xff0c;需要变更自己的访问 IP&#xff0c;可以通过 Squid 搭建代理服务器实现。 本文使用的是 CentOS 7.6 系统。 一、部署 Squid 安装 Squid。 yum install squid -y启动服 systemctl start squid二、访问控制 总有刁民想害郑&#xff0c;疯狂访问朕的…

C++ 最小生成树 洛谷

介绍&#xff1a; 最小生成树是个啥&#xff1f;其实就像杨志一行人押送生辰纲。抛开最后生辰纲被抢的结局不谈&#xff0c;杨志他们需要到好几个地方&#xff0c;每个地方都需要花点过路费给梁山好汉们打点。比如下面就是一张城市地图&#xff1a; 其中每两个图之间的路径长就…

【保姆级系列:锐捷模拟器的下载安装使用全套教程】

保姆级系列&#xff1a;锐捷模拟器的下载安装使用全套教程 1.介绍2.下载3.安装4.实践教程5.验证 1.介绍 锐捷目前可以通过EVE-NG来模拟自己家的路由器&#xff0c;交换机&#xff0c;防火墙。实现方式是把自己家的镜像导入到EVE-ng里面来运行。下面主要就是介绍如何下载镜像和…

【Unity】3D功能开发入门系列(三)

Unity3D功能开发入门系列&#xff08;三&#xff09; 一、运动脚本&#xff08;一&#xff09;物体的运动&#xff08;二&#xff09;相对运动&#xff08;三&#xff09;运动的方向 二、旋转脚本&#xff08;一&#xff09;物体的旋转&#xff08;二&#xff09;相对旋转&…

图像相关的基础知识【RGB和RGBA】—附python代码实现

文章目录 1、图像基础知识2、像素和通道的理解3、RGB和RGBARGB (Red, Green, Blue)RGBA (Red, Green, Blue, Alpha)应用场景 4、H,W,C5、小结 &#x1f343;作者介绍&#xff1a;双非本科大三网络工程专业在读&#xff0c;阿里云专家博主&#xff0c;专注于Java领域学习&#x…

aurora8b10b ip的使用(framing接口下的数据回环测试)

文章目录 一、Aurora8B/10B协议二、时钟、复位与状态指示1、时钟2、复位3、状态指示 三、数据发送、接受接口&#xff08;1&#xff09;AXI4-Stream位排序&#xff08;2&#xff09;Streaming接口&#xff08;3&#xff09;Framing接口&#xff08;帧传输接口&#xff09; 四、…

C++ | Leetcode C++题解之第319题灯泡开关

题目&#xff1a; 题解&#xff1a; class Solution { public:int bulbSwitch(int n) {return sqrt(n 0.5);} };

Python | Leetcode Python题解之第318题最大单词长度乘积

题目&#xff1a; 题解&#xff1a; class Solution:def maxProduct(self, words: List[str]) -> int:masks defaultdict(int)for word in words:mask reduce(lambda a, b: a | (1 << (ord(b) - ord(a))), word, 0)masks[mask] max(masks[mask], len(word))return…

索引:SpringCloudAlibaba分布式组件全部框架笔记

索引&#xff1a;SpringCloudAlibaba分布式组件全部框架笔记 一推荐一套分布式微服务的版本管理父工程pom模板&#xff1a;Springcloud、SpringCloudAlibaba、Springboot二SpringBoot、SpringCloud、SpringCloudAlibaba等各种组件的版本匹配图&#xff1a;三SpringBoot 3.x.x版…

字符串相关函数

文章目录 &#x1f34a;自我介绍&#x1f34a;strcpy 字符串拷贝函数&#x1f34a;strcat 字符串连接函数&#x1f34a;strlen 字符串长度计算函数&#x1f34a;strcmp 字符串比较函数 你的点赞评论就是对博主最大的鼓励 当然喜欢的小伙伴可以&#xff1a;点赞关注评论收藏&…

C++ | Leetcode C++题解之第318题最大单词长度乘积

题目&#xff1a; 题解&#xff1a; class Solution { public:int maxProduct(vector<string>& words) {unordered_map<int,int> map;int length words.size();for (int i 0; i < length; i) {int mask 0;string word words[i];int wordLength word.s…

[Git][基本操作]详细讲解

目录 1.创建本地仓库2.配置 Git3.添加文件1.添加文件2.提交文件3.其他 && 说明 4.删除文件5.跟踪修改文件6.版本回退7.撤销修改0.前言1.未add2.已add&#xff0c;未commit3.已add&#xff0c;已commit 1.创建本地仓库 创建⼀个Git本地仓库&#xff1a;git init运行该命…

模型 ESBI(财富四象限)

系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_思维模型目录。财富自由之路的4个阶段。 1 ESBI模型的应用 1.1 一名工程师的财富自由之路 有一个名叫张伟的软件工程师&#xff0c;他在一家大型科技公司工作&#xff08;E象限&#xff09;。随着时间的推移&#…