FPGA动态数码管应用——60S计数
目录
1.实验描述
2.系统模块框图
3.软件程序
3.1数据生成模块
3.2按键消抖模块
3.3二进制转BCD码模块
3.4数码驱动模块
3.5测设程序
1.实验描述
实现60s计数器的数码显示,当计数为60后回到1又循环,过程中可以通过按键控制暂停与继续。
key:按键控制计数开始或暂停
rst:清零
2.系统模块框图
系统模块主要包含四个模块:
1.数据生成模块:每过1s在原数据基础上加1,并且在等到按键按下的高电平控制数据的计数与暂停。
2.按键消抖模块:检测按键是否按下,按下则产生一个脉冲的高电平。
3.二进制转BCD码模块:将数据生成模块中的数据进行转换为BCD码,提供给数码驱动模块。
4.数码驱动模块:得到BCD码后,每过1ms驱动一个数码管位并显示内容。
3.软件程序
3.1数据生成模块
`timescale 1ns / 1ns module top_seg
(input sys_clk, input sys_rst_n,input key , output [5:0] sel, //数码管位选信号output [7:0] seg //数码管段选信号
); wire [7:0] data; //数码管显示的数值data_gen data_gen_inst( //数据产生模块,每过0.1s数据自加一 //@2seg_data_inst ?= u_seg_data .sys_clk (sys_clk) , .sys_rst_n (sys_rst_n) , .key (key) ,.data (data) );seg_dynamic seg_dynamic_inst( //数码管动态显示模块.sys_clk (sys_clk) , .sys_rst_n (sys_rst_n) , .data (data) , .sel (sel) , .seg (seg)
);
endmodule
3.2按键消抖模块
`timescale 1ns/1nsmodule key_filter
#(parameter CNT_MAX = 20'd999_999 //计数器计数最大值
)
(input wire sys_clk , //系统时钟50Mhzinput wire sys_rst_n , //全局复位input wire key_in , //按键输入信号output reg key_flag //key_flag为1时表示消抖后检测到按键被按下//key_flag为0时表示没有检测到按键被按下
);
//reg define
reg [19:0] cnt_20ms ; //计数器//cnt_20ms:如果时钟的上升沿检测到外部按键输入的值为低电平时,计数器开始计数
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_20ms <= 20'b0;else if(cnt_20ms == CNT_MAX && key_in == 1'b0)cnt_20ms <= cnt_20ms;else if(key_in == 1'b1) //按键没有按下,不计时cnt_20ms <= 20'b0;else cnt_20ms <= cnt_20ms + 1'b1;//key_flag:当计数满20ms后产生按键有效标志位
//且key_flag在999_999时拉高,维持一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)key_flag <= 1'b0;else if(cnt_20ms == CNT_MAX - 1'b1)key_flag <= 1'b1;elsekey_flag <= 1'b0;endmodule
3.3二进制转BCD码模块
`timescale 1ns/1nsmodule bcd_8421
(input wire sys_clk , input wire sys_rst_n , input wire [7:0] data , //输入需要转换的数据output reg [3:0] unit , //个位BCD码output reg [3:0] ten , //十位BCD码output reg [3:0] hun , //百位BCD码output reg [3:0] tho , //千位BCD码output reg [3:0] t_tho , //万位BCD码output reg [3:0] h_hun //十万位BCD码
);
reg [4:0] cnt_shift ; //移位判断计数器 移动次数由十转为二进制的位数决定
reg [43:0] data_shift ; //移位判断数据 寄存器 存放BCD码与二进制码
reg shift_flag ; //移位判断标志信号 用于控制移位判断的先后顺序//cnt_shift:从0到21循环计数(当计为20时进行判断移位,21时则是取BCD码数据)
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_shift <= 5'd0;else if((cnt_shift == 5'd21) && (shift_flag == 1'b1)) cnt_shift <= 5'd0;else if(shift_flag == 1'b1)cnt_shift <= cnt_shift + 1'b1;elsecnt_shift <= cnt_shift;//data_shift:计数器为0时赋初值,计数器为1~20时进行移位判断操作
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)data_shift <= 44'b0;else if(cnt_shift == 5'd0) //计数器为0时赋初值data_shift <= {24'b0,data};else if((cnt_shift <= 20) && (shift_flag == 1'b0)) //<=为小于等于,先判断再移位 begin data_shift[23:20] <= (data_shift[23:20] > 4) ? (data_shift[23:20] + 2'd3) : (data_shift[23:20]);data_shift[27:24] <= (data_shift[27:24] > 4) ? (data_shift[27:24] + 2'd3) : (data_shift[27:24]);data_shift[31:28] <= (data_shift[31:28] > 4) ? (data_shift[31:28] + 2'd3) : (data_shift[31:28]);data_shift[35:32] <= (data_shift[35:32] > 4) ? (data_shift[35:32] + 2'd3) : (data_shift[35:32]);data_shift[39:36] <= (data_shift[39:36] > 4) ? (data_shift[39:36] + 2'd3) : (data_shift[39:36]);data_shift[43:40] <= (data_shift[43:40] > 4) ? (data_shift[43:40] + 2'd3) : (data_shift[43:40]);endelse if((cnt_shift <= 20) && (shift_flag == 1'b1))data_shift <= data_shift << 1;elsedata_shift <= data_shift;
//shift_flag:移位判断标志信号,低电平判断 高电平移位
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)shift_flag <= 1'b0;elseshift_flag <= ~shift_flag;
//当计数器等于20时,移位判断操作完成,对各个位数的BCD码进行赋值
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)beginunit <= 4'b0;ten <= 4'b0;hun <= 4'b0;tho <= 4'b0;t_tho <= 4'b0;h_hun <= 4'b0;endelse if(cnt_shift == 5'd21)beginunit <= data_shift[23:20];ten <= data_shift[27:24];hun <= data_shift[31:28];tho <= data_shift[35:32];t_tho <= data_shift[39:36];h_hun <= data_shift[43:40];end
endmodule
3.4数码驱动模块
`timescale 1ns/1nsmodule seg_dynamic
#(parameter CNT_MAX = 16'd49_999 //数码管刷新 时间计数最大值 1ms
)
(input wire sys_rst_n , input wire sys_clk , input wire [7:0] data , //数码管要显示的值output reg [5:0] sel , //数码管位选信号output reg [7:0] seg //数码管段选信号
);
//wire define
wire [3:0] unit ; //个位数
wire [3:0] ten ; //十位数
wire [3:0] hun ; //百位数
wire [3:0] tho ; //千位数
wire [3:0] t_tho ; //万位数
wire [3:0] h_hun ; //十万位数
//reg define
reg [23:0] data_reg ; //待显示数据 寄存器
reg [15:0] cnt_1ms ; //1ms计数器
reg flag_1ms ; //1ms标志信号
reg [2:0] cnt_sel ; //数码管位选计数器
reg [5:0] sel_reg ; //位选信号
reg [3:0] data_disp ; //当前数码管显示的数据//cnt_1ms:1ms计数器
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_1ms <= 16'd0;else if(cnt_1ms == CNT_MAX)cnt_1ms <= 16'd0;elsecnt_1ms <= cnt_1ms + 1'b1;
//flag_1ms:1ms标志信号
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)flag_1ms <= 1'b0;else if(cnt_1ms == CNT_MAX - 1'b1)flag_1ms <= 1'b1; // unit 为BCD码,可以总效果4'bXXXXelse // ten 为BCD码,可以总效果4'bXXXXflag_1ms <= 1'b0; // hun 为BCD码,可以总效果4'bXXXX// tho 为BCD码,可以总效果4'bXXXX
//data_reg:控制数码管显示数据 // t_tho 为BCD码,可以总效果4'bXXXXalways@(posedge sys_clk or negedge sys_rst_n) // h_hun 为BCD码,可以总效果4'bXXXXif(sys_rst_n == 1'b0) data_reg <= 24'b0;
//若显示的十进制数的 十万 位为非零数据则六个数码管全显示 else if(h_hun) //h_hun非空即数据有六位 data_reg <= {h_hun,t_tho,tho,hun,ten,unit};
//若显示的十进制数的 万 位为非零数据则值显示在5个数码管上else if(t_tho)data_reg <= {4'd11,t_tho,tho,hun,ten,unit}; //4'd11(第六位)我们定义为不显示
//若显示的十进制数的 千 位为非零数据则值显示4个数码管else if(tho)data_reg <= {4'd11,4'd11,tho,hun,ten,unit};
//若显示的十进制数的 百 位为非零数据则值显示3个数码管else if(hun)data_reg <= {4'd11,4'd11,4'd11,hun,ten,unit};
//若显示的十进制数的 十 位为非零数据则值显示2个数码管else if(ten)data_reg <= {4'd11,4'd11,4'd11,4'd11,ten,unit};
//若上面都不满足都只显示 个 位数码管elsedata_reg <= {4'd11,4'd11,4'd11,4'd11,4'd11,unit};//cnt_sel:标记0-5ms所对应显示的BCD码
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)cnt_sel <= 3'd0;else if((cnt_sel == 3'd5) && (flag_1ms == 1'b1))cnt_sel <= 3'd0;else if(flag_1ms == 1'b1)cnt_sel <= cnt_sel + 1'b1;elsecnt_sel <= cnt_sel;//数码管位选信号寄存器
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)sel_reg <= 6'b000_000;else if((cnt_sel == 3'd0) && (flag_1ms == 1'b1))sel_reg <= 6'b000_001;else if(flag_1ms == 1'b1)sel_reg <= sel_reg << 1;elsesel_reg <= sel_reg;//控制数码管的位选信号,使六个数码管轮流显示
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)data_disp <= 4'b0;else if(flag_1ms == 1'b1)case(cnt_sel)3'd0: data_disp <= data_reg[3:0] ; //给第1个数码管赋个位值3'd1: data_disp <= data_reg[7:4] ; //给第2个数码管赋十位值3'd2: data_disp <= data_reg[11:8] ; //给第3个数码管赋百位值3'd3: data_disp <= data_reg[15:12]; //给第4个数码管赋千位值3'd4: data_disp <= data_reg[19:16]; //给第5个数码管赋万位值3'd5: data_disp <= data_reg[23:20]; //给第6个数码管赋十万位值default:data_disp <= 4'b0 ;endcaseelsedata_disp <= data_disp;//控制数码管段选信号,显示数字
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)seg <= 8'b1111_1111;else case(data_disp)4'd0 : seg <= 8'b1100_0000; //显示数字04'd1 : seg <= 8'b1111_1001; //显示数字14'd2 : seg <= 8'b1010_0100; //显示数字24'd3 : seg <= 8'b1011_0000; //显示数字34'd4 : seg <= 8'b1001_1001; //显示数字44'd5 : seg <= 8'b1001_0010; //显示数字54'd6 : seg <= 8'b1000_0010; //显示数字64'd7 : seg <= 8'b1111_1000; //显示数字74'd8 : seg <= 8'b1000_0000; //显示数字84'd9 : seg <= 8'b1001_0000; //显示数字9default:seg <= 8'b1111_1111;endcase//sel:数码管位选信号赋值
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)sel <= 6'b000_000;elsesel <= sel_reg;bcd_8421 bcd_8421_inst
(.sys_clk (sys_clk ), //系统时钟,频率50MHz.sys_rst_n (sys_rst_n), //复位信号,低电平有效.data (data ), //输入需要转换的数据.unit (unit ), //个位BCD码.ten (ten ), //十位BCD码.hun (hun ), //百位BCD码.tho (tho ), //千位BCD码.t_tho (t_tho ), //万位BCD码.h_hun (h_hun ) //十万位BCD码
);
endmodule
3.5测试程序
`timescale 1ns/1ns
module tb_top_seg();reg sys_clk ; reg sys_rst_n ; reg key ; wire [5:0] sel ; wire [7:0] seg ;initialbegin sys_clk = 1'b0;sys_rst_n <= 1'b0;key <= 1'b1;#20;sys_rst_n <= 1'b1;#60;key <= 1'b0; //按键第一次拉低#500;key <= 1'b1;#80000key <= 1'b0; //按键第二次拉低#500;key <= 1'b1;end always #10 sys_clk = ~sys_clk;defparam top_seg_inst.data_gen_inst.KEY_CNT = 20'd11;
defparam top_seg_inst.data_gen_inst.CNT_MAX_1S = 26'd49;
defparam top_seg_inst.seg_dynamic_inst.CNT_MAX = 16'd20;top_seg top_seg_inst
(.sys_clk (sys_clk ) ,.sys_rst_n (sys_rst_n ) ,.key (key ) ,.sel (sel ) , .seg (seg )
);
endmodule
烧入板子后可以成功实现相关功能,欢迎评论区讨论!
FPGA动态数码管应用——60S计数相关推荐
- FPGA 动态数码管显示实验
参考:正点原子开拓者 FPGA 开发指南 一.数码管动态显示简介 由于一般的静态驱动操作虽然方便,但占用的I/0口较多,例如要驱动6位8段数码管,以静态驱动方式让数码管各个位显示不同的数值,如&quo ...
- 基于FPGA的两位按键控制LED数码管加减计数实验
两位按键控制LED数码管加减计数实验 这是一篇拖了一个多月的文章,主要是基于FPGA利用按键消抖原理与动态数码管驱动原理相结合,来实现一个利用两位按键来控制数码管实现0-99的加法计数或者减法计数功能 ...
- FPGA之动态数码管显示实验
1.试验任务 完成6位数码管以动态方式从0开始计数,没100ms计数值增加1,当计数值从0增加到999999后重新从0开始计数. 2.硬件原理图 3.程序框图 程序设计思想: FPGA顶层(top_s ...
- FPGA实战篇——【6】动态数码管
FPGA实战--动态数码管 rtl文件 模块设计: 计数模块,产生数码管的数据 数码管显示驱动模块 时钟分频 数字转码(二进制->BCD码) 位选信号切换 调试warning: ucf文件 ** ...
- 实验三 基于FPGA的数码管动态扫描电路设计 quartus/数码管/电路模块设计
实验三 基于FPGA的数码管动态扫描电路设计 源文件的链接放在最后啦 实验目的: (1) 熟悉7段数码管显示译码电路的设计. (2) 掌握数码管显示原理及静态.动态扫描电路的设计. 实验任务: (1) ...
- 数字IC-1.8 子模块组建整模块-动态数码管设计代码实例
感谢野火开源教程的支持!EmbedFire – 东莞野火电子技术有限公司 本实验采用阳极6位数码管,其中段选是共用的. 一.实验目标 让六位数码管显示从十进制数 0 开始计数,每 0.1s 加 1,一 ...
- 动态数码管verilog模块功能分析
学习正点原子FPGA开发板关于动态数码管章节: 实验任务是使用FPGA 开发板上的 6 位数码管以动态方式从 0 开始计数,每 100 ms 计数值增加 一,当计数值从 0 增加到 999999 后重 ...
- 74HC595工作原理及FPGA实现数码管驱动方法
74HC595,移位寄存器,串行输入,8位并行输出,一般用于数码管电路以减少使用的IO口数量. 管脚介绍: Q0~Q7 :八位并行输出位 Q7' : 级联位,若输入位数大于8位,先进入的 ...
- 黑金AX301开发板学习(3)——动态数码管的时钟实验
开发板的使用是AX301,学习资料可以在我的另一篇文章中找到.链接在如下:https://blog.csdn.net/qq_24213087/article/details/108238682 一.动 ...
最新文章
- 话里话外:信息资源整合失败之痛(二)
- 查找内存泄漏的一个思路
- java replaceall lt_static lt;Tgt; boolean replaceAll(Listlt;Tgt; list, T oldVal, T newVal)_Java...
- PHP7新增的主要特性
- 系统架构师-基础到企业应用架构-业务逻辑层
- java day55【 Mybatis 连接池与事务深入 、 Mybatis 的动态 SQL 语句、 Mybatis 多表查询之一对多 、 Mybatis 多表查询之多对多】...
- 德国Java工程师_1886年,德国工程师。
- gtest的介绍和使用
- 【系统分析师之路】系统分析师历年真题大汇总
- 省市区三级数据-MySQL
- ptc转4-20mA热电阻变送器NI1000 NTC转0-10ma输出PWM
- Thymeleaf介绍和基操(附截图和代码)
- C# dataGridView上下移动选中行
- centos7安装otrs
- 计算机为什么不读500g硬盘,为什么我的500g硬盘的实际容量只有46 5. 1G
- jmeter断言(自动判断实际和预期结果是否相符的jmeter组件)
- java update 8_java 8 update 77可以删除吗
- 三阶魔方有多少种状态
- apache http server 停止工作_(二)http协议的网站装ssl升级成https
- java如何读取word文档内容并修改指定内容文本颜色