动态数码管verilog模块功能分析
学习正点原子FPGA开发板关于动态数码管章节:
实验任务是使用FPGA 开发板上的 6 位数码管以动态方式从 0 开始计数,每 100 ms 计数值增加 一,当计数值从 0 增加到 999999 后重新从 0 开始计数。
1.硬件连接:
为了减少数码管占用的I/O 口, 将所有数码管的段选(数码管的 a 、b 、 c 等引脚)连接在一起,而位选(数码管的公共端)独立控制。数码管采用共阳接法,当八位段选信号接低电平时点亮。而位选信号所接I/O也是接低电平时被选中,这是为了输出信号的驱动能力,我们使用了 PNP 型三极管驱动数码管的位选段。所以给三极管基极提供低电平时, 位选信号为高电平,所选中的数码管共阳极接到了高电平,数码管被选中。
利用人眼的分辨不足和LED灯的余辉作用,当要显示多位数字时,依次位选激活每一个数码管,即每隔1ms切换数码管显示不同的数字,即可实现显示多位数字。
2.程序设计
我们需要一个静态数码管显示模块在数码管上显示数据,其次需要一个计时模块每当计时到0.1s 时改变数码管显示的数值。由此画出系统的功能框图如下所示:
首先需要一个数码管动态显示模块,能够依次点亮6个数码管,并将对应的数据输出至数码管,也就是需要分别控制段选和位选信号;同时还需要一个计数模块,能够将0—999999 依次输出至数码管动态显示模块。由此画出系统的功能框图如下所示:
计数模块(count):显示的数字每100ms 加“1”。
数码管动态显示模块(seg_led):数码管动态显示模块在数码管上以动态方式显示数值。
3.程序分析
计数器模块:该模块可以每隔100ms计数加一,第一个always块进行计时100ms;
module count(//mudule clockinput clk , // 时钟信号input rst_n, // 复位信号//user interfaceoutput reg [19:0] data , // 6个数码管要显示的数值output reg [ 5:0] point, // 小数点的位置,高电平点亮对应数码管位上的小数点output reg en , // 数码管使能信号output reg sign // 符号位,高电平时显示负号,低电平不显示负号
);//parameter define
parameter MAX_NUM = 23'd5000_000; // 计数器计数的最大值//reg define
reg [22:0] cnt ; // 计数器,用于计时100ms
reg flag; // 标志信号//*****************************************************
//** main code
//*****************************************************//计数器对系统时钟计数达100ms时,输出一个时钟周期的脉冲信号
always @ (posedge clk or negedge rst_n) beginif (!rst_n) begincnt <= 23'b0;flag<= 1'b0;endelse if (cnt < MAX_NUM - 1'b1) begincnt <= cnt + 1'b1;flag<= 1'b0;endelse begincnt <= 23'b0;flag <= 1'b1;end
end
第二个always块累计加数,显示0—999999的数据,此外还有sign(符号)和point(小数点)设置。
//数码管需要显示的数据,从0累加到999999
always @ (posedge clk or negedge rst_n) beginif (!rst_n)begindata <= 20'b0;point <=6'b000000;en <= 1'b0;sign <= 1'b0;end else beginpoint <= 6'b000000; //不显示小数点en <= 1'b1; //打开数码管使能信号sign <= 1'b0; //不显示负号if (flag) begin //显示数值每隔0.1s累加一次if(data < 20'd999999) data <= data +1'b1; elsedata <= 20'b0;end end
end endmodule
数码管动态显示模块:该模块assign语句将所要显示的data转换成6位数码管要显示的数字;
module seg_led(input clk , // 时钟信号input rst_n , // 复位信号input [19:0] data , // 6位数码管要显示的数值input [5:0] point , // 小数点具体显示的位置,从高到低,高电平有效input en , // 数码管使能信号input sign , // 符号位(高电平显示“-”号)output reg [5:0] seg_sel, // 数码管位选,最左侧数码管为最高位output reg [7:0] seg_led // 数码管段选);//parameter define
localparam CLK_DIVIDE = 4'd10 ; // 时钟分频系数
localparam MAX_NUM = 13'd5000 ; // 对数码管驱动时钟(5MHz)计数1ms所需的计数值//reg define
reg [ 3:0] clk_cnt ; // 时钟分频计数器
reg dri_clk ; // 数码管的驱动时钟,5MHz
reg [23:0] num ; // 24位bcd码寄存器
reg [12:0] cnt0 ; // 数码管驱动时钟计数器
reg flag ; // 标志信号(标志着cnt0计数达1ms)
reg [2:0] cnt_sel ; // 数码管位选计数器
reg [3:0] num_disp ; // 当前数码管显示的数据
reg dot_disp ; // 当前数码管显示的小数点//wire define
wire [3:0] data0 ; // 个位数
wire [3:0] data1 ; // 十位数
wire [3:0] data2 ; // 百位数
wire [3:0] data3 ; // 千位数
wire [3:0] data4 ; // 万位数
wire [3:0] data5 ; // 十万位数//*****************************************************
//** main code
//*****************************************************//提取显示数值所对应的十进制数的各个位
assign 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块通过计数五个系统时钟然后翻转即可产生十分频;
//对系统时钟10分频,得到的频率为5MHz的数码管驱动时钟dri_clk
always @(posedge clk or negedge rst_n) beginif(!rst_n) beginclk_cnt <= 4'd0;dri_clk <= 1'b1;endelse if(clk_cnt == CLK_DIVIDE/2 - 1'd1) beginclk_cnt <= 4'd0;dri_clk <= ~dri_clk;endelse beginclk_cnt <= clk_cnt + 1'b1;dri_clk <= dri_clk;end
end
从第二个alway块开始时钟触发改成十分频时钟,根据是否显示符号、小数点和要显示的数据位数,将要显示的数码管状态存放到24位reg变量num中(具体自己分析吧);
//将20位2进制数转换为8421bcd码(即使用4位二进制数表示1位十进制数)
always @ (posedge dri_clk or negedge rst_n) beginif (!rst_n)num <= 24'b0;else beginif (data5 || point[5]) begin //如果显示数据为6位十进制数,num[23:20] <= data5; //则依次给6位数码管赋值num[19:16] <= data4;num[15:12] <= data3;num[11:8] <= data2;num[ 7:4] <= data1;num[ 3:0] <= data0;endelse begin if (data4 || point[4]) begin //如果显示数据为5位十进制数,则给低5位数码管赋值num[19:0] <= {data4,data3,data2,data1,data0};if(sign) num[23:20] <= 4'd11; //如果需要显示负号,则最高位(第6位)为符号位elsenum[23:20] <= 4'd10; //不需要显示负号时,则第6位不显示任何字符endelse begin //如果显示数据为4位十进制数,则给低4位数码管赋值if (data3 || point[3]) beginnum[15: 0] <= {data3,data2,data1,data0};num[23:20] <= 4'd10; //第6位不显示任何字符if(sign) //如果需要显示负号,则最高位(第5位)为符号位num[19:16] <= 4'd11;else //不需要显示负号时,则第5位不显示任何字符num[19:16] <= 4'd10;endelse begin //如果显示数据为3位十进制数,则给低3位数码管赋值if (data2 || point[2]) beginnum[11: 0] <= {data2,data1,data0};//第6、5位不显示任何字符num[23:16] <= {2{4'd10}};if(sign) //如果需要显示负号,则最高位(第4位)为符号位num[15:12] <= 4'd11;else //不需要显示负号时,则第4位不显示任何字符num[15:12] <= 4'd10;endelse begin //如果显示数据为2位十进制数,则给低2位数码管赋值if (data1 || point[1]) beginnum[ 7: 0] <= {data1,data0};//第6、5、4位不显示任何字符num[23:12] <= {3{4'd10}};if(sign) //如果需要显示负号,则最高位(第3位)为符号位num[11:8] <= 4'd11;else //不需要显示负号时,则第3位不显示任何字符num[11:8] <= 4'd10;endelse begin //如果显示数据为1位十进制数,则给最低位数码管赋值num[3:0] <= data0;//第6、5位不显示任何字符num[23:8] <= {4{4'd10}};if(sign) //如果需要显示负号,则最高位(第2位)为符号位num[7:4] <= 4'd11;else //不需要显示负号时,则第2位不显示任何字符num[7:4] <= 4'd10;endendendendendend
end
第三个always块计数,每隔1ms产生一个脉冲标志flag;
//每当计数器对数码管驱动时钟计数时间达1ms,输出一个时钟周期的脉冲信号
always @ (posedge dri_clk or negedge rst_n) beginif (rst_n == 1'b0) begincnt0 <= 13'b0;flag <= 1'b0;endelse if (cnt0 < MAX_NUM - 1'b1) begincnt0 <= cnt0 + 1'b1;flag <= 1'b0;endelse begincnt0 <= 13'b0;flag <= 1'b1;end
end
第四个always块根据flag来改变数码管的位选状态,共六种状态;
//cnt_sel从0计数到5,用于选择当前处于显示状态的数码管
always @ (posedge dri_clk or negedge rst_n) beginif (rst_n == 1'b0)cnt_sel <= 3'b0;else if(flag) beginif(cnt_sel < 3'd5)cnt_sel <= cnt_sel + 1'b1;elsecnt_sel <= 3'b0;endelsecnt_sel <= cnt_sel;
end
第五个always块根据上一步的位选状态选择要位选的一个数码管,并将其要显示的数字状态和小数点状态赋给num_disp和dot_disp;
//控制数码管位选信号,使6位数码管轮流显示
always @ (posedge dri_clk or negedge rst_n) beginif(!rst_n) beginseg_sel <= 6'b111111; //位选信号低电平有效num_disp <= 4'b0; dot_disp <= 1'b1; //共阳极数码管,低电平导通endelse beginif(en) begincase (cnt_sel)3'd0 :beginseg_sel <= 6'b111110; //显示数码管最低位num_disp <= num[3:0] ; //显示的数据dot_disp <= ~point[0]; //显示的小数点end3'd1 :beginseg_sel <= 6'b111101; //显示数码管第1位num_disp <= num[7:4] ;dot_disp <= ~point[1];end3'd2 :beginseg_sel <= 6'b111011; //显示数码管第2位num_disp <= num[11:8];dot_disp <= ~point[2];end3'd3 :beginseg_sel <= 6'b110111; //显示数码管第3位num_disp <= num[15:12];dot_disp <= ~point[3];end3'd4 :beginseg_sel <= 6'b101111; //显示数码管第4位num_disp <= num[19:16];dot_disp <= ~point[4];end3'd5 :beginseg_sel <= 6'b011111; //显示数码管最高位num_disp <= num[23:20];dot_disp <= ~point[5];enddefault :beginseg_sel <= 6'b111111;num_disp <= 4'b0;dot_disp <= 1'b1;endendcaseendelse beginseg_sel <= 6'b111111; //使能信号为0时,所有数码管均不显示num_disp <= 4'b0;dot_disp <= 1'b1;endend
end
最后一个always块根据要显示的数字状态和小数点状态翻译成八位段选信号的高低电平(10不显示任何字符,11显示符号)。
//控制数码管段选信号,显示字符
always @ (posedge dri_clk or negedge rst_n) beginif (!rst_n)seg_led <= 8'hc0;else begincase (num_disp)4'd0 : seg_led <= {dot_disp,7'b1000000}; //显示数字 04'd1 : seg_led <= {dot_disp,7'b1111001}; //显示数字 14'd2 : seg_led <= {dot_disp,7'b0100100}; //显示数字 24'd3 : seg_led <= {dot_disp,7'b0110000}; //显示数字 34'd4 : seg_led <= {dot_disp,7'b0011001}; //显示数字 44'd5 : seg_led <= {dot_disp,7'b0010010}; //显示数字 54'd6 : seg_led <= {dot_disp,7'b0000010}; //显示数字 64'd7 : seg_led <= {dot_disp,7'b1111000}; //显示数字 74'd8 : seg_led <= {dot_disp,7'b0000000}; //显示数字 84'd9 : seg_led <= {dot_disp,7'b0010000}; //显示数字 94'd10: seg_led <= 8'b11111111; //不显示任何字符4'd11: seg_led <= 8'b10111111; //显示负号(-)default: seg_led <= {dot_disp,7'b1000000};endcaseend
endendmodule
分析完成,这个代码是真的长,继续学习(>﹏<)
https://www.bilibili.com/video/BV1vA411c72b?p=26
动态数码管verilog模块功能分析相关推荐
- 51单片机入门——动态数码管显示详解
51单片机:动态数码管显示 - 模块图 - 显示原理 – 消抖 静态数码管技术 + 人眼视觉停留 显示原理类似于以前的 胶片机放影视,也就是只要我切换的速度足够快你就看不出来其实我是一次次显示的(滑稽 ...
- 黑金AX301开发板学习(3)——动态数码管的时钟实验
开发板的使用是AX301,学习资料可以在我的另一篇文章中找到.链接在如下:https://blog.csdn.net/qq_24213087/article/details/108238682 一.动 ...
- 数字IC-1.8 子模块组建整模块-动态数码管设计代码实例
感谢野火开源教程的支持!EmbedFire – 东莞野火电子技术有限公司 本实验采用阳极6位数码管,其中段选是共用的. 一.实验目标 让六位数码管显示从十进制数 0 开始计数,每 0.1s 加 1,一 ...
- FPGA 动态数码管显示实验
参考:正点原子开拓者 FPGA 开发指南 一.数码管动态显示简介 由于一般的静态驱动操作虽然方便,但占用的I/0口较多,例如要驱动6位8段数码管,以静态驱动方式让数码管各个位显示不同的数值,如&quo ...
- FPGA之动态数码管显示实验
1.试验任务 完成6位数码管以动态方式从0开始计数,没100ms计数值增加1,当计数值从0增加到999999后重新从0开始计数. 2.硬件原理图 3.程序框图 程序设计思想: FPGA顶层(top_s ...
- 51单片机——动态数码管实验,小白讲解,相互学习
多位数码管介绍: 多位数码管,即两个或两个以上单个数码管并列集中在一起形成一体的数码管.当多位一体时,他们内部的公共端是独立的,二负责显示什么数字的段线(a-dp)全部是连接在一起的,独立的公共端可以 ...
- 51单片机静态动态数码管显示
51单片机静态动态数码管显示 通过此实训了解动态数码管的显示原理,掌握编码方法.共阴极和其阴极数码管的不同之处及常用设计方法. 实训设备 这里使用的377锁存器模块控制的数码管下面就是电路图 显示内容 ...
- 动态数码管原理解释及多种写法,消影
动态数码管涉及到很多写法:原理其实和点LED差不多,都是通过寄存器,找到引脚,对二极管进行点亮. 相比之下,管子多了,因此无法一次控制这么多,那不得写死你. 这是就需要借助芯片控制 38译码器 通过P ...
- 【STC单片机学习】第七课:单片机控制静态/动态数码管
[朱老师课程总结 侵删] 第一部分.章节目录 1.7.1.什么是数码管 1.7.2.静态数码管的初步驱动 1.7.3.静态数码管显示数字 1.7.4.让数码管依次显示0到f 1.7.5.动态数码管 1 ...
最新文章
- 入门深度学习,但你知道哪些情况下不该使用深度学习吗?
- 微服务该如何设计缓存?
- Lucene教程具体解释
- 怎么修改与服务器的操作系统,怎么修改与服务器的操作系统
- 想回家吗?先用腾讯刚上线的这个功能查一查!
- java 服务端客户端数据传输出现乱码
- Bigpipe---FaceBook使用的页面加载技术
- matlab ode45求解齿轮动力学,Matlab拟合动力学参数遇到问题(ode45)
- 分布式锁 动态代理 Java数据结构List,Set,Map,Spring执行流程,Spring MVC组件
- DesiredCapabilities内容详解(摘)
- 数据结构C++版-图
- 传奇服务器怎么修改背包金刚石显示,教你在服务器加自己的装备
- android实现带下划线的密码输入框
- 超滤膜助力料酒生产 美味十里飘香
- 淘宝/天猫、1688、京东按图搜索淘宝商品(拍立淘)API接口
- K-mean clustering(K均值聚类算法)
- 操作系统4————进程同步
- 做好产品需求文档的这十步
- php import mdf,mdf文件用什么打开 mdf是什么文件
- SpringCloud-11-解决[NACOS HTTP-GET] The maximum number of tolerable server reconnection errors has bee
热门文章
- 计算机专业学生参加igem,中国科大2019iGEM代表队斩获一金一银 再续辉煌
- 漫谈互联网历史【8】- 90年代:现代互联网的诞生
- 干货分享 | 大数据零基础学习路线:新手从入门到精通
- Android :RxTools一款强大实用的工具类集合
- ZGC这是要上天吗?
- java String计算MD5的三种方法以及文件计算MD5的方法
- 我的服务器上的无线网络显禁用,无线网络被禁用怎么开启,点启用不好使
- 【每日随笔】马太效应 ① ( 社会中的一些现象 - 富人/穷人 好学生/坏学生 | 马太效应由来 | 天之道与人之道 - 道德经 )
- yolov5-计算fps(新加入:4. 记录运行B导yolov7-tiny后计算fps的方法)
- Java性能优化四、性能测试工具