文章目录

  • 一、项目要求
  • 二、问题分析与思路设计
    • 2.1 从基本的动态显示入手
    • 2.2 算法设想
  • 三、实际操作
    • 3.1 程序架构
    • 3.2 Verilog代码
      • 3.2.1 main模块
      • 3.2.2 100ms定时器模块
        • 3.2.1.1 100ms定时器Testbench文件
      • 3.2.2 1ms定时器模块
        • 3.2.2.1 1ms定时Testbench文件
      • 3.2.3 数码管显示模块
    • 3.3 实验结果

一、项目要求

任务:使用FPGA开发板上的6位数码管以动态方式从0开始计数,每100ms计数值增加一,当计数值从0增加到999999后重新从0开始计数。

二、问题分析与思路设计

2.1 从基本的动态显示入手

我们首先下图这种两个数码管的情况来进行分析:假设我们现在需要让这两个数码管显示:“12”,那应该怎么做呢?

通过上图我们可以看出:数码管的位选信号(10引脚和5引脚)是独立的,而且是高电平有效。这也就意味着如果我们给 10 引脚高电平,5引脚低电平(即 “10” 信号),那么就可以让左边的数码管亮,右边的数码管不亮。反之,如果给 “01” 信号,那么就是左边的数码管不亮,右边的数码管亮。

不过值得注意的是:如果只是看上图的位选,那么确实是高电平有效。但是在实际的FPGA开发板,驱动数码管所需要的电流要比较大,因此需要使用三极管来对位选信号进行放大,笔者所使用的FPGA开发板上位选信号输入的原理图如下:

上图中的 SEL0_TSEL0\_TSEL0_T ~ SEL5_TSEL5\_TSEL5_T就是我们刚刚所讨论的位选信号,而 SEL0SEL0SEL0~SEL5SEL5SEL5就是真正作用于数码管的信号,可见位选信号是 PNP 三极管的基级,因此当 SEL0_TSEL0\_TSEL0_T ~ SEL5_TSEL5\_TSEL5_T 中某一些位是低电平时,SEL0SEL0SEL0~SEL5SEL5SEL5 中的对应位才变为高电平,用于驱动对应位置的数码管。因此在本例中,数码管的位选信号是低电平有效的
【不过在2.1节的剩余部分,考虑到内容的连贯性,还是假设位选信号就是第一幅图里面的10口和5口,且为高电平有效,但是在代码部分,我们将会重新考虑实际的原理图】

然而我们又发现:这两个数码管他们的段选信号是公共的,而且是低电平有效。 段选信号指的就是让数码管显示具体的哪一个数字,段选信号与数字显示的对应关系如下图所示。 比如说,咱们现在给位选信号是 “10”,这样就是左边的数码管亮,右边的数码管不亮;同时我们给段选信号是:【注:我们这里暂且假设a位是高位,这个具体看实际电路的情况】(abcdefgDP)=(10011111)(a\space b\space c\space d \space e \space f \space g \space D_P)= (1\space 0\space 0\space 1 \space 1\space 1\space1\space1) (a b c d e f g DP​)=(1 0 0 1 1 1 1 1)

那么就是说我们让左边的数码管显示 “1”,而右边的数码管不亮。

那么如果我们给位选信号是 “01”,段选信号是:(abcdefgDP)=(00100101)(a\space b\space c\space d \space e \space f \space g \space D_P)= (0\space 0\space 1\space 0 \space 0\space 1\space0\space1) (a b c d e f g DP​)=(0 0 1 0 0 1 0 1)

这样一来,就是左边的数码管不亮,右边的数码管亮,且显示数字 “2”。

可是我们希望能够显示 “12”,如果说给位选信号是 “11”,也就是两个数码管同时亮,但是这样的话因为段选信号是公共的,那么也就是说两个数码管一定会显示相同的数字。

幸运的是,我们的人眼存在 “视觉暂留现象”,我们假设:左边数码管显示“1”,右边数码管不亮这个状态为 “状态1”;左边数码管不亮,右边数码管显示 “2”这个状态为 “状态2”。那么,只要状态1 和状态2 他俩之间来回切换的频率高于一定的程度,我们的人眼就分辨不出来,从而以为是这两个数码管分别显示了不同的数字。 一般来讲,状态1和状态2之间的间隔时间可以是 1ms ~ 2ms。

2.2 算法设想

现在我们已经了解了数码管的动态显示是如何工作的,那么回到我们本次项目的需求:

使用FPGA开发板上的6位数码管以动态方式从0开始计数,每100ms计数值增加一,当计数值从0增加到999999后重新从0开始计数。

那么显示 1到999999之间的任何数字 这一环节就是用我们在上一个section 里面提到的方法.

那么我们可以知道需要两个定时器:

  1. 一个是 1ms 定时器(也就是我们在 2.1 节提到的在每隔 1ms 就分别让6个数码管中的其中一个点亮,其余不亮),它每隔1ms就可以输出一个 flag 信号指示数码管的切换。
  2. 另外一个就是 100ms 定时器,他的作用是每隔100ms就产生一个 data信号(1到999999)。

然后我们还需要一个数码管显示模块,它接收来自 1ms 定时器输出的 flag 信号,每隔1ms就切换数码管的显示状态,同时它也需要接受 100ms 定时器输出的 data 信号,用于给当前时刻被点亮的数码管赋予一个需要显示的数字

这里数码管显示模块又涉及到两种问题:

  1. 如何切换数码管的显示状态?
  2. 如何给当前时刻被点亮的数码管赋予数字?

对于第一个问题,首先我们的 1ms定时器 在定时到1ms时会给我们的数码管显示模块发送一个切换指示信号 flag,那么我们可以再在数码管显示模块里面设一个 reg 类型的信号 cnt_selcnt\_selcnt_sel,每来一个 flag,那么我的 cnt_selcnt\_selcnt_sel 就加一(最多到5),因此 cnt_selcnt\_selcnt_sel 每隔 1ms 就会在 0, 1,2,3,4,5这五个数字之间来回变化,那么最后我们只需要给一个 case 语句,分配好这6个数字与每一个数码管亮的对应关系即可。

对于第二个问题,我们可以首先获取输入到数码管显示模块的 data 的各个位。把他们分别转换成二进制,最后还是用一个 case 判断不同的二进制对应的段选信号情况。(值得注意的是:由于我们将要显示的数字里面没有 A,B,C,D,E,F这几个情况,因此在case的default里面,除了1~10其他情况都应该给所有段选信号高电平)。

三、实际操作

3.1 程序架构

显然,对于我们的工程,1个verilog文件是不够用的,元件例化就非常重要,我们可以设计好一个一个的小模块,然后把这些小模块连接起来。下面是笔者的工程文件架构:

3.2 Verilog代码

3.2.1 main模块

module main(input clk,input rst,output wire[5:0] sel,output wire[7:0] seg_led);wire [19:0] data;
wire en;
wire flag;counter_100ms u0(.clk(clk),.rst(rst),.en(en),.data(data));counter_1ms u1(.clk(clk),.rst(rst),.flag(flag));seg u2(.clk(clk),.rst(rst),.data(data),.flag(flag),.sel(sel),.seg_led(seg_led));
endmodule

3.2.2 100ms定时器模块

module counter_100ms(input clk,input rst,output reg en,output reg[19:0] data);parameter max_count_100ms = 23'd5000_000;
reg[22:0] cnt;
reg flag1;always@(posedge clk or negedge rst)
beginif(!rst) begincnt <= 23'b0;flag1 <= 1'b0;endelse beginif(cnt < max_count_100ms -1) begincnt <= cnt + 23'b1;flag1 <= 1'b0;endelse begincnt <= 23'b0;flag1 <= 1'b1; //When flag1 = 1'b1,it means that the data should be self increasingendend
endalways@(posedge clk or negedge rst)
beginif(!rst) beginen <= 1'b0;    //close the enable signaldata <= 20'b0; //clear the data endelse beginen <= 1'b1;if(flag1) beginif(data < 20'd999_999)data <= data + 20'b1;elsedata <= 20'b0;endelsedata <= data;end
end
endmodule

3.2.1.1 100ms定时器Testbench文件

`timescale 1ns/1ns
module counter_100ms_tb();reg clk;
reg rst;
wire en;
wire[19:0] data;parameter T = 20;always #(T/2) clk = ~clk;initial beginclk = 0;rst = 0;#(T) rst = 1;
endcounter_100ms u0(.clk(clk),.rst(rst),.en(en),.data(data));
endmodule

3.2.2 1ms定时器模块

module counter_1ms(input clk,input rst,output reg flag);parameter max_count_1ms = 50000;
reg[15:0] cnt1;always@(posedge clk or negedge rst)
beginif(!rst) begincnt1 <= 16'b0;flag <= 1'b0;endelse beginif(cnt1 < max_count_1ms - 1) begincnt1 <= cnt1 + 16'b1;flag <= 1'b0; endelse begincnt1 <= 16'b0;flag <= 1'b1;endend
end
endmodule

3.2.2.1 1ms定时Testbench文件

`timescale 1ns/1ns
module counter_1ms_tb();reg clk;
reg rst;
wire flag;parameter T = 20;always #(T/2) clk = ~clk;initial beginclk = 0;rst = 0;#(T) rst = 1;
endcounter_1ms u0(.clk(clk),.rst(rst),.flag(flag));
endmodule

3.2.3 数码管显示模块

module seg(input clk,input rst,input [19:0] data,input flag, //flag is used for deciding which tube should be chosen.output reg[5:0] sel,  //Digital tube selectionoutput reg[7:0] seg_led);//-----------------------Set 1 ------------------------------
reg [2:0] cnt_sel;
//-----------------------------------------------------------//-----------------------Set 2 ------------------------------
reg [3:0] num_disp;wire[3:0] data0;   //Individual
wire[3:0] data1;   //Ten
wire[3:0] data2;   //Hundred
wire[3:0] data3;   //Thousand
wire[3:0] data4;   //Ten thousand
wire[3:0] data5;   //One hundred thousandreg [23:0] num;
/*Note:Why the reg num is 24 bit?
For example: if the data is 789210,it means we want the
six tube display :"7","8","9","2","1","0" respectively.
Let the digital tube display these numbers, we need to
turn them into binary.Like:
"0111","1000","1001","0010","0001","0000".
so 6-bit decimal number needs to 24 bit binary number at most
*/
//-----------------------------------------------------------//It is used to switch the state of digital tube every 1ms
always@(posedge clk or negedge rst)
begin   if(!rst)cnt_sel <= 3'b0;else beginif(flag) beginif(cnt_sel < 3'd5)cnt_sel <= cnt_sel + 1'b1;elsecnt_sel <= 3'b0;endelse cnt_sel <= cnt_sel;end
endassign data0 = data % 4'd10;
assign data1 = data / 4'd10 % 4'd10;
assign data2 = data / 7'd100 % 4'd10;
assign data3 = data / 10'd1000 % 4'd10;
assign data4 = data / 14'd10000 % 4'd10;
assign data5 = data / 17'd100000;always@(posedge clk or negedge rst)
beginif(!rst) num <= 24'b0;else beginif(data5) begin //If data is six digitsnum[23:0] <= {data5,data4,data3,data2,data1,data0};endelse beginif(data4) beginnum[19:0] <= {data4,data3,data2,data1,data0};num[23:20] <= 4'd10; //Don't show anythingendelse beginif(data3) beginnum[15:0] <= {data3,data2,data1,data0};num[23:16] <= {2{4'd10}};endelse beginif(data2) beginnum[11:0] <= {data2,data1,data0};num[23:12] <= {3{4'd10}};endelse beginif(data1) beginnum[7:0] <= {data1,data0};num[23:8] <= {4{4'd10}};endelse beginif(data0) beginnum[3:0] <= data0;num[23:4] <= {5{4'd10}};endendendendendendend
endalways@(posedge clk or negedge rst)
beginif(!rst) beginsel <= 6'b111111;  //Bit select signal low level validnum_disp <= 4'b0;endelse begincase(cnt_sel)3'd0: beginsel  <= 6'b111110; num_disp <= num[3:0];end3'd1: beginsel <= 6'b111101;num_disp <= num[7:4];end3'd2: beginsel <= 6'b111011;num_disp <= num[11:8];end3'd3: beginsel <= 6'b110111;num_disp <= num[15:12];end3'd4: beginsel <= 6'b101111;num_disp <= num[19:16];end3'd5: beginsel <= 6'b011111;num_disp <= num[23:20];endendcaseend
endalways@(posedge clk or negedge rst)
beginif(!rst) seg_led <= 8'hc0;else begincase(num_disp)4'd0 : seg_led <= 8'b1100_0000;4'd1 : seg_led <= 8'b1111_1001; 4'd2 : seg_led <= 8'b1010_0100;4'd3 : seg_led <= 8'b1011_0000;4'd4 : seg_led <= 8'b1001_1001;4'd5 : seg_led <= 8'b1001_0010;4'd6 : seg_led <= 8'b1000_0010;4'd7 : seg_led <= 8'b1111_1000;4'd8 : seg_led <= 8'b1000_0000;4'd9 : seg_led <= 8'b1001_0000;default://when num_disp is 4'd10, The default branch will be executed//hence the tube will not show anything.seg_led <= 8'b11111111;endcaseend
end
endmodule

3.3 实验结果

下图是本次项目的RTL图:

上板发现实验结果符合预期。

【FPGA开发笔记】—— 数码管动态显示项目详细剖析+个人心得体会相关推荐

  1. 正点原子FPGA开发指南——数码管动态显示

    数码管是将若干发光二极管按一定图形排列并封装在一起的一种数码显示器件.常见的数码管如下图所示: 这种数码管主要被称为八段数码管或8字形数码管,可用来显示小数点.数字0~9,和英文字母A~F. 我们的目 ...

  2. uni-app项目的收获及心得体会

    Uniapp是一种支持多端开发的框架,能够在一个项目中同时开发小程序.H5.APP等多个版本.学生教务系统包含了学籍信息.成绩查询.选课.课程表等众多模块,需要涉及到复杂的后台逻辑和数据库操作.使用U ...

  3. 云炬Android开发笔记 2-2 Android studio项目上传到Github及无法连接Github的问题处理

    本文将介绍如何将AS上的项目发布到GitHub上: 选择 VCS--enable verSion control integrate : 选择GIT: 此时可以发现左侧的类都变红了: 此处的颜色含义: ...

  4. 前端开发笔记3-开发小项目,kline遇到的知识点及问题

    1.遇到需要弹出某些信息时的思路 今天遇到的需求是触发一个点击事件后弹出对应的信息,如何弹出较为合理的信息框呢. 整体思路是  点击事件-$('body').append('<div>.. ...

  5. 做项目的一些心得体会

    原文地址:转:做项目的一些心得体会作者:快乐吧900 发信人: sunshineyaya (sunshine), 信区: Innovation 标  题: [创新实验]经验分享  系列  NO.1 发 ...

  6. VHDL编写多功能数字钟,spartan3 FPGA开发板硬件实现-学习笔记

    VHDL编写多功能数字钟,spartan3 FPGA开发板硬件实现-学习笔记 多功能数字钟硬件测试视频: https://www.bilibili.com/video/av62501230 1.数字钟 ...

  7. FPGA学习笔记-1 FPGA原理与开发流程

    1 初识FPGA 文章目录 1 初识FPGA 1.1 基本认知 1.1.1 什么是FPGA? 1.1.2 什么是HDL?什么是Verilog? 1.1.3 硬件开发与软件开发 1.1.4 FPGA与其 ...

  8. 【正点原子FPGA连载】第三十一章RTC实时时钟数码管显示实验 -摘自【正点原子】新起点之FPGA开发指南_V2.1

    1)实验平台:正点原子新起点V2开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=609758951113 2)全套实验源码+手册+视频下载地址:ht ...

  9. 共阳数码管段码表_正点原子开拓者FPGA开发板资料连载第十一章 静态数码管显示实验...

    1)实验平台:正点原子开拓者FPGA 开发板 2)摘自<开拓者FPGA开发指南>关注官方微信号公众号,获取更多资料:正点原子 3)全套实验源码+手册+视频下载地址:http://www.o ...

最新文章

  1. Nginx 使用中文URL,中文目录路径
  2. linux 以太网转wifi,LINUX-网络 - (以太网和WIFI无线)
  3. linux fedora14 u盘运行,用U盘安装Fedora的详细步骤
  4. [健康]女人喝红酒的好处
  5. python后端设计_Python后端设计模式
  6. Druid 在小米公司部分技术实践
  7. 电信光猫找不到服务器,高手说说电信光猫没网如何设置?
  8. 用Python来实现2~7阶行列式的计算
  9. Fake Location(安卓)
  10. 《Pajek社会网络探索性分析》书籍简介
  11. CMU 15213:attack实验
  12. gbk2312拼音表 按词频排好序的
  13. 小程序如何自定义组件
  14. 用js写一个功德木鱼
  15. 可惜我是水瓶座 你不懂的水瓶座,不为人知的秘密
  16. VS调用大恒相机sdk实时显示图像并进行图像处理+OPENCV
  17. VMware虚拟机开机显示you are in emergency mode 解决办法
  18. 抽象类能实例化吗?——口气很强硬——“不能”(详解)
  19. STM32学习之PWM输出
  20. 基于51单片机的上下限可调的数字温度控制系统

热门文章

  1. 考了初级会计职称到底能干什么?
  2. 微信浏览器h5分享卡片模式
  3. 基于Python将多个表格数据合成为一个表格数据
  4. 如何将视频压缩变小?
  5. java web毕业答辩_基于JAVA的WEB页面设计毕业答辩.ppt
  6. 【RenPy】关于ADV模式下say语句输出在NVL模式中文本框的问题
  7. [USACO 1.3.2] Barn Repair 修理牛棚
  8. 音频转文字用什么软件高效转换成文字
  9. git让单个文件回滚到指定版本
  10. linux 文件恢复 软件,用于Linux数据恢复的前5大软件