开发板的使用是AX301,学习资料可以在我的另一篇文章中找到。链接在如下:https://blog.csdn.net/qq_24213087/article/details/108238682
一、动态数码管介绍
上一篇我们详细地说了一下数码管的原理图和静态显示的主要方式。我们回顾一下我们使用数码管的原理图。

六位一体数码管的显示是属于动态显示, 由于人的视觉暂留现象及发光二极管的余辉效应,这个迂回效应使用的原理和我们看电影的效果是一样的。电影的放映就是一幅幅的图片,只要保证每秒20帧以上的速率,我们大脑会留下一个反应的时间,这个时间就是余晖效应带来的。所以我们看到的电影是动态连续的。因此我们将数码管的动态扫描时间大于50HZ时,尽管实际上各位数码管并非同时点亮,但给人的印象就是一组稳定的显示数据,不会有闪烁感。这里放一张我最喜欢的电影海报。

二、时钟实验
接下来言归正传,我们通过一个时钟的实验完成动态数码管的显示。首先我们使用的AX301是50MHz的晶振最小产生的时间延迟是20ns。因此我们需要对我们的时钟进行分频到1ms的时钟。

/* time   : 2020.9.12                                                                      主要功能 : 实现时钟分频功能,分别实现1ms , 20ms        端口定义 :  clock:  分频后的时钟reset:  复位信号clk_div1: 分频时钟,1msclk_div2:  分频时钟,20ms
=============================================================================================*/
module time_div(clock, reset, clk_div1, clk_div2);
input clock, reset;
output clk_div1, clk_div2;
reg clk_div1, clk_div2;
reg [15:0] cnt1;
reg [19:0] cnt2;
parameter MAX_TIME1 = 25_000;
parameter MAX_TIME2 = 1_000_000;
//1ms
always@(posedge clock or negedge reset)beginif(!reset)beginclk_div1 = 1'b0;cnt1 = 16'd0;endelse if(cnt1 < MAX_TIME1)begincnt1 = cnt1 + 1'd1;endelse if(cnt1 == MAX_TIME1)begincnt1 = 16'd0;clk_div1 = ~clk_div1;endelsebegincnt1 = cnt1;end
end
//20ms
always@(posedge clock or negedge reset)beginif(!reset)beginclk_div2 = 1'b0;cnt2 = 20'd0;endelse if(cnt2 < MAX_TIME2)begincnt2 = cnt2 + 1'd1;endelse if(cnt2 == MAX_TIME2)begincnt2 = 20'd0;clk_div2 = ~clk_div2;endelsebegincnt2 = cnt2;end
end
endmodule

时钟分频ok后,我们继续要考虑时钟设计的计数问题,在ms级的计数就是正常的十进制,但是对于秒级和分级就是60进制。因此我们需要将每毫秒的计数值进行分类。

/* time   : 2020.9.12                                                                      主要功能 : 实现时钟计时功能,计时精度1ms          端口定义 :  clock:  分频后的时钟reset:  复位信号time_sum: 当前时间
=============================================================================================*/
module time_ms (clock, reset, time_sum);
input clock,reset;
output [23:0] time_sum;
reg [23:0] time_sum ;
reg [19:0] time_MS;
parameter MAX_TIMER = 600_000;
//计算当前时间存入time_MS
always@(posedge clock or negedge reset)beginif(!reset)begintime_MS = 20'd0;endelse if(time_MS < MAX_TIMER)begintime_MS = time_MS + 1'd1; endelsebegintime_MS = 20'd0;end
end
//将time_MS转变为 分_秒_毫秒 的形式存入time_sum
always@(time_MS)begintime_sum[23:20] = time_MS/60000;time_sum[19:16] = ((time_MS/1000)%60)/10;time_sum[15:12] = ((time_MS/1000)%60)%10;time_sum[11:8] = (time_MS%1000)/100;time_sum[7:4] = ((time_MS%1000)%100)/10;time_sum[3:0] = ((time_MS%1000)%100)%10;
end
endmodule

接下来就到了这个实验最重要的部分,屏幕扫描这个功能,实现对位选的控制。

/* time   : 2020.9.12                                                                      主要功能 : 实现位选扫屏功能,计时精度1ms,位选信号确定后,并给出当前应显示的段选信号          端口定义 :  clock:  分频后的时钟reset:  复位信号sel:   位选信号time_sum: 当前时间cnt:   位选标志
=============================================================================================*/
module scan(clock, reset, sel, time_sum, ctl_seg, dot);
input clock, reset;
input [23:0] time_sum;
output [5:0] sel;
output [3:0] ctl_seg;
output dot;
reg [3:0] ctl_seg;
reg [5:0] sel = 6'b0;
reg dot;
reg [2:0] cnt = 0;
//段选
always@(posedge clock)beginif(cnt < 3'd5)begincnt <= cnt + 1;endelsebegincnt <= 0;end
end
always@(posedge clock)begincase (cnt)3'd0:  beginsel = 6'b111_110;ctl_seg = time_sum[3:0];dot = 1;end3'd1:  beginsel = 6'b111_101;ctl_seg = time_sum[7:4];dot = 1;end    3'd2:  beginsel = 6'b111_011;ctl_seg = time_sum[11:8];dot = 1;end3'd3:  beginsel = 6'b110_111;ctl_seg = time_sum[15:12];dot = 0;end3'd4:  beginsel = 6'b101_111;ctl_seg = time_sum[19:16];dot = 1;end3'd5:  beginsel = 6'b011_111;ctl_seg = time_sum[23:20];dot = 0;enddefault: beginsel = sel;ctl_seg = ctl_seg;dot = 1;endendcase
end
endmodule

最后就是对每个数码管显示的字符进行段选控制实现当前数字的显示

/* time   :2020.9.12                                                                      主要功能 :实现段选功能         端口定义 :  clock:  分频后的时钟reset:  复位信号seg_led:  段选信号cnt:   位选后当前应显示的数值标志
=============================================================================================*/
module seg_led_show(clock, reset, seg_led, ctl_seg, dot);
input clock, reset;
input [3:0] ctl_seg;
input dot;
output [7:0] seg_led;
reg [7:0] seg_led = 8'b1111_1111;
always@(ctl_seg)begincase (ctl_seg)8'd0:   seg_led = {dot,7'b1000000};  //08'd1:   seg_led = {dot,7'b1111001};  //18'd2:   seg_led = {dot,7'b0100100};  //28'd3:   seg_led = {dot,7'b0110000};  //38'd4:   seg_led = {dot,7'b0011001};  //48'd5:   seg_led = {dot,7'b0010010};  //58'd6:   seg_led = {dot,7'b0000010};  //68'd7:   seg_led = {dot,7'b1111000};  //78'd8:   seg_led = {dot,7'b0000000};  //88'd9:   seg_led = {dot,7'b0010000};  //9default: seg_led = 8'b1111_1111;endcase
end
endmodule

最最后就是我们的顶层代码,实现各个模块之间的连接

/* time   : 2020.9.12                                                                      主要功能 : 实现时钟功能,六位数码管,依次为分、秒、毫秒。例如1.20.123,为1分钟20秒123毫秒          端口定义 : clock:  分频后的时钟reset:  复位信号seg_led:  段选信号sel:   位选信号
=============================================================================================*/
module top(clock, reset, sel, seg_led);
input clock, reset;
output [5:0] sel;
output [7:0] seg_led;
//reg [5:0] sel;
//reg [7:0] seg_led;
wire clk_div1, clk_div2;
wire [23:0] time_sum;
wire [4:0] ctl_seg;
wire dot;
time_div time_div(
.clock(clock),
.reset(reset),
.clk_div1(clk_div1),
.clk_div2(clk_div2)
);
time_ms time_ms(
.clock(clk_div1),
.reset(reset),
.time_sum(time_sum)
);
scan scan(
.clock(clk_div1),
.reset(reset),
.sel(sel),
.time_sum(time_sum),
.ctl_seg(ctl_seg),
.dot(dot)
);
seg_led_show seg_led_show(
.clock(clk_div1),
.reset(reset),
.seg_led(seg_led),
.ctl_seg(ctl_seg),
.dot(dot)
);
endmodule

总结一下写代码的一些小知识点,首先由于模块的编写慢慢地加多,当我们在修改其中一个模块的一个端口后一定要注意下其他模块中这个端口的修改,以及顶层模块该端口的修改。尤其是位宽的这个数值的修改。稍不注意就会让你出现不可理解的BUG。愿我们的代码BUG越来越少,
最后放一个小视频,展示一下这个实验的一个成果。

AX301数码管显示时钟小视频

声明:该文只适用于学习,其内容包含来自书本的摘抄和总结,欢迎大家补充,共同学习进步。

黑金AX301开发板学习(3)——动态数码管的时钟实验相关推荐

  1. 黑金AX301开发板学习(1)——流水灯实验及黑金AX301开发板资料

    第一次尝试使用AX301开发板进行学习,本篇文章主要通过一个流水灯的小实验聊一下AX301这块开发板的使用. 一.黑金AX301是一款基础的学生实验板,用来学习FPGA是一个不错的选择.此款开发板是A ...

  2. 黑金AX301开发板学习(2)——静态数码管的加法器实验

    开发板的使用是AX301,学习资料可以在我的另一篇文章中找到.链接在如下:https://blog.csdn.net/qq_24213087/article/details/108238682 一.静 ...

  3. 黑金AX301开发板SPI通信详解

    前言: 对黑金的AX301开发板的SPI工程进行了波形仿真,写一下自己的理解. 背景: 项目地址: https://download.csdn.net/download/a792544191/1287 ...

  4. 用stm32开发时是直接买现成的开发板还是芯片?开发板学习,芯片硬件设计

    视情况而言,买开发板用于评估和学习,然后买芯片做硬件设计 开发板 开发板上手即可使用,并附带很多模块. 拿到开发板后即可直接根据开发板提供的原理图进行程序编写,学习. 优点:简单快捷,上手快,拿到手就 ...

  5. 海思SD3403开发板学习(二)

    海思SD3403开发板学习系列:二 配置基础环境 文章目录 海思SD3403开发板学习系列:二 配置基础环境 前言 一.交叉编译工具安装 1. 工具链名 1. 安装 二.NFS挂载 1.安装NFS 2 ...

  6. Xilinx 黑金ZYNQ开发板AX7020,利用VIVADO进行FPGA程序烧录

    参考黑金的AX7020开发板资料中的SDK实验篇PDF教程文件. (1)创建工程,步骤与SDK实验篇中的步骤一致:配置PS端时应该可以只选需要的加载方式,如QSPI或者SD,我目前是两种都勾选了,但是 ...

  7. 【STM32 .Net MF开发板学习-02】GPIO测试

    前段时间我借用市面上现成的Corex-M3开发板,打造了最低价的.Net Micro Framework开发板(参见<免费发放firmwave,打造史上最低价.Net MF开发板>),在此 ...

  8. 阿里云HaaS100物联网开发板学习笔记(六)做个智能灯---一个完整的开发例子

    摘要:本篇文章将前期几个专题综合起来,基于阿里云HaaS100的新固件设计制作一个智能灯.这个智能灯由云平台.手机APP端和设备端组成,基本上涵盖了一个物联网小项目所需的主要步骤. 目录 1.在阿里云 ...

  9. 阿里云HaaS100物联网开发板学习笔记(二)硬件控制初步--让小灯闪烁起来

    摘要:无论是哪种开发板,要想开发特定的功能,必先从GPIO开始,HaaS100开发也是一样.如果仅仅利用HaaS100的联网功能,那简直是太浪费了.HaaS100拥有其他开发板所具备的所有的功能,比如 ...

最新文章

  1. 旋转角度_办公娱乐新神器!这款稳固的创意支架,360°旋转随便换角度
  2. CentOS 安装Nginx
  3. Symantec Backup Exec 2012 Agent For Linux安装
  4. pythondocumentation是什么_怎样阅读Python官方文档
  5. LeetCode 589. N叉树的前序遍历(前序遍历)
  6. python图片转字符_二十行python代码实现图片转字符
  7. [转]Linux TCP/IP 协议栈的关键数据结构Socket Buffer(sk_buff )
  8. springMVC异常拦截
  9. 应用机器学习(九):主成分分析
  10. 最新老韩泰牛PHP基础班+大牛班+大牛班高级课程
  11. 论文后面的参考文献格式应该如何写
  12. Echart自定义图片绘制热力图实现图片适配
  13. 关于保利威视平台的API调用签名
  14. win10系统修改电脑 hosts 地址
  15. 【办公自动化】基于Python开发的PDF批量转换-合并应用程序
  16. 所有职位 岗位 大全 看看都有些什么岗位 职位
  17. MLAT-Autoencoders---下篇-关键代码及结果展示(1)
  18. [转载]Eclipse开发工具简介
  19. 高中计算机应用基础试题及答案,春学期职业高中计算机应用基础试卷
  20. 【单镜头反光相机】相机与小孔成像

热门文章

  1. 计算机组成原理实验报告 实验三:控制器实验(源码全)
  2. 关于Kubernetes 中通过 Kustomize 实现YAML资源文件组合与继承的一些笔记
  3. Python OpenCV putText() 在图像中放置文本
  4. javaWeb(七)ajax远程调用
  5. (8.1.5.5)Android Testing Support Library翻译之Espresso 意图
  6. jersey的简单使用原理(jersey1.15版本)
  7. Windows Server 2008 R2安装openSSH服务
  8. PHP1c型GNAS,8盘位HP ML110 G9开箱测试,刷群晖改装20盘位
  9. QSL Server SQL语句实例
  10. 我的2018——上懂机器学习,下懂微信建群