FPGA学习(10)-数码管

前3节视频目的是实现显示0~F的数码管仿真,后3节是用驱动芯片驱动数码管。

目录

1.数码管显示原理

2.代码过程

2.1仿真结果

3.串行移位寄存器原理

3.1原理

​编辑 3.2 数据手册

3.3 先行设计思路

4.程序 

4.1确定SRCLK的频率

4.2序列计数器

4.3 不同counter值干不同事

4.4仿真 

5.实验结果


1.数码管显示原理

分为共阳极与共阴极驱动,共阴极:发光二极管负极都接地,a~dp接入端口引脚,输出高电平就点亮,共阳极与之相反。

不同位的高低电平可以组成不同的数字符号,后面查找表的值就看这张图。 

在驱动多个数码管场景中,往往a~dg与每个数码管对应的二极管是互联的,而sel端的电压可以控制三极管是否导通,以此可以单独让某个数码管亮灭。

根据以上分析可以画出电路图:

1.首先SEL决定了点亮哪个数码管,需要用到38译码器进行选择,而38译码器的输出选择需要用到一个3位的状态计数切换器。

2.如何让状态切换,即加入一个计数器记到1ms,当大于1ms时,让状态加1,且计数器本身清0。

3.SEG决定了数码管哪段亮,在没有规律的情况下可以用查表法,把这些状态一一列出来,例如这里有16个状态,那么需要一个4位的变量来表示对应的索引号。

4.将状态计数切换器值传到8选1数据选择器,分别代表8个数码管对应的通道值,作为索引。

2.代码过程

1.实现1ms的计数器;

2.位切换逻辑,计数器每满一次,状态位切换+1;

3.38译码器实现连接哪个数码管;

4.位选择控制逻辑。

(1)查找表case,完成SEG的配置。

(2)位切换逻辑将8个数码管对应的值当作索引传进去。这里数组顺序错了。

 代码:

module Shuma_guan(input                   clk,input                   reset,input[31:0]             Dis_data,output reg[7:0]         SEL,output reg[7:0]         SEG);
reg[29:0] counter_1ms;
reg[2:0] which_sel;
reg[3:0] data_temp;         //存放索引值
//数码管亮的时间
parameter Base_freq = 50_000_000;
parameter goal_freq = 1000;
parameter cworth = Base_freq/goal_freq-1;//计数器
always@(posedge clk or negedge reset)
beginif(!reset)counter_1ms <= 1'd0;else if(counter_1ms == cworth)counter_1ms <= 1'd0;elsecounter_1ms <= counter_1ms+1'd1;
end//数码管状态切换
always@(posedge clk or negedge reset)
beginif(reset)which_sel <= 1'd0;else if(counter_1ms == cworth)which_sel <= which_sel+1'd1;elsewhich_sel <= which_sel;
end//38译码器确定哪个数码管亮
always@(posedge clk)
begincase(which_sel)0:SEL <= 8'b0000_0001;1:SEL <= 8'b0000_0010;2:SEL <= 8'b0000_0100;3:SEL <= 8'b0000_1000;4:SEL <= 8'b0001_0000;5:SEL <= 8'b0010_0000;6:SEL <= 8'b0100_0000;7:SEL <= 8'b1000_0000;endcase
end//建立查找表,共阳
always@(posedge clk)
begincase(data_temp)0:SEG <= 8'b1100_0000;1:SEG <= 8'b1111_1001;2:SEG <= 8'b1010_0100;3:SEG <= 8'b1011_0000;4:SEG <= 8'b1001_1001;5:SEG <= 8'b1001_0010;6:SEG <= 8'b1000_0010;7:SEG <= 8'b1111_1000;8:SEG <= 8'b1000_0000;9:SEG <= 8'b1001_0000;10:SEG <= 8'b1000_1000;11:SEG <= 8'b1000_0011;12:SEG <= 8'b1100_0110;13:SEG <= 8'b1010_0001;14:SEG <= 8'b1000_0110;15:SEG <= 8'b1000_1110;endcase  
end//将状态值传给索引
always@(*)
begincase(which_sel)0:data_temp <= Dis_data[3:0];1:data_temp <= Dis_data[7:4];2:data_temp <= Dis_data[11:8];3:data_temp <= Dis_data[15:12];4:data_temp <= Dis_data[19:16];5:data_temp <= Dis_data[23:20];6:data_temp <= Dis_data[27:24];7:data_temp <= Dis_data[31:28];endcase
endendmodule

仿真:

`timescale 1ns / 1nsmodule Shuma_guan_tb();
reg                   clk;
reg                   reset;
reg[31:0]             Dis_data;
wire[7:0]             SEL;
wire[7:0]             SEG;Shuma_guan Shuma_guan_inst0(.clk(clk),.reset(reset),.Dis_data(Dis_data),.SEL(SEL),.SEG(SEG)
);  initial clk = 1;
always #10 clk=~clk;initial beginreset = 0;Dis_data = 32'h12345678;#201;reset = 1;#20_000_000;Dis_data = 32'h9abcdef0;#20_000_000;$stop;
end
endmodule

2.1仿真结果

切换状态计数没有随着计数器增加到49999而加1,原因是在切换状态的时序逻辑中,复位没有取反,直接if(reset),相当于复位信号为1时,状态计数就会为0,所以一直不会增加。

修改后正确:

3.串行移位寄存器原理

3.1原理

 为了节省IO口引脚,一般会使用驱动芯片74HC595驱动数码管,芯片的原理是基于串行移位寄存器。将上节输出的SEG与SEL传输到74HC595。

基本原理为,顺次连接4个D触发器,每经过一个时钟,就依次将DATA存储的值传送到下一个D触发器,例如,经过5个时钟周期后, 此时DFF3~DFF0存储的值为:1001。如果想在这个时刻把每个D触发器存储的值取出来,就在每个D触发器的输出端再接入一个D触发器,加的这4个D触发器单独用一个时钟进行控制,然后将输出分别接至各自端口。

 当要移位8位,16位时,直接加更多的D触发器就行。

74HC595能够驱动8位移位寄存器,SER是数据传输口,SRCLK是第一路串联触发器的时钟,SRCLR非应该是复位信号,RCLK是是每个单独加入的触发器的时钟,OE非是输出的使能信号。第1个74HC595的输出串联到了第2个74HC595的输入,以此构成16位移位寄存器输出。

 左边的74HC连接的是选择使能哪个数码管,右边的74HC是决定数码管哪段亮。DIO是数据输入,SRCLK是第一路串联触发器的时钟,RCLK是加入单个D触发器的时钟。

 3.2 数据手册

从时序图可以看出,RCLK有方波时,才有输出。

移位寄存器时钟为上升沿时,其实也就是让移位寄存器存前一阶段的数据。RCLK为上升沿时,移位寄存器的数据存储在存储寄存器中。

时钟频率最低为5MHz,其中,SRCLK/RCLK的高低电平时间至少为时钟周期的一半,电平为2V时,SER在SRCLK上升沿前125ns必须稳定,SRCLK的上升沿必须RCLK上升沿之前的94ns。 

3.3 先行设计思路

4.程序 

4.1确定SRCLK的频率

取50MHz的乘除整数倍,取SRCLK的频率为12.5MHz,定义一个分频计数器,在SRCLK下降沿将数据传到DIO,上升沿DIO将数据传给驱动芯片的寄存器。计数器计数两次为1个SRCLK周期,可根据counter找到SRCLK的上升沿和下降沿。

4.2序列计数器

根据时序图与原理图,先传的SEG,后传的SEL。1ms切换了一次,人眼看不出来,实际上应该是闪烁的数字循环跳变。共32个状态,需要拉低拉高。

4.3 不同counter值干不同事

counter=0,拉低SRCLK,将SEG[7]的值传给DIO,将RCLK拉高。

counter=1,拉高SRCLK(驱动芯片自动会将DIO的数据传给寄存器),RCLK拉低。

......

counter=31,拉高SRCLK

4.4仿真 

仿真的RCLK刚开始就拉高了,这是因为if后面没有跟else,直接按照每个时钟沿开始执行程序了。

 正确的仿真波形:

 此时代码:

module tube_active(input               clk,input               reset,input[7:0]          SEL,input[7:0]          SEG,output reg          SRCLK,output reg          RCLK,output reg          DIO);reg[29:0]       divi_counter;
reg[4:0]        state_counter;          //序列计数器
//确定SRCLK的频率为12.5MHz
parameter base_frequence = 50_000_000;
parameter goal_frequence = 12500_000;
parameter goal_counter = base_frequence/(goal_frequence*2)-1;//分频计数器
always@(posedge clk or negedge reset)
beginif(!reset)divi_counter <= 1'd0;else if(divi_counter == goal_counter)divi_counter <= 1'd0;elsedivi_counter <= divi_counter +1'd1;    
end//序列计数器
always@(posedge clk or negedge reset)
beginif(!reset)state_counter <= 1'd0;else if(divi_counter == goal_counter)state_counter <= state_counter+1'd1;elsestate_counter <= state_counter;
end//不同counter值做不同事,下降沿将值传给DIO,上升沿将DIO的值送给驱动芯片
always@(posedge clk or negedge reset)
beginif(!reset)beginSRCLK <= 1'd0;RCLK <= 1'd0;DIO <= 1'd0;endelse begincase(state_counter)0:begin DIO <= SEG[7]; SRCLK <= 1'd0; RCLK <= 1'd1; end1:begin SRCLK <= 1'd1; RCLK <= 1'd0; end2:begin DIO <= SEG[6]; SRCLK <= 1'd0;end3:begin SRCLK <= 1'd1; end4:begin DIO <= SEG[5]; SRCLK <= 1'd0;end    5:begin SRCLK <= 1'd1; end6:begin DIO <= SEG[4]; SRCLK <= 1'd0;end7:begin SRCLK <= 1'd1; end8:begin DIO <= SEG[3]; SRCLK <= 1'd0;end 9:begin SRCLK <= 1'd1; end10:begin DIO <= SEG[2]; SRCLK <= 1'd0;end11:begin SRCLK <= 1'd1; end12:begin DIO <= SEG[1]; SRCLK <= 1'd0;end13:begin SRCLK <= 1'd1; end14:begin DIO <= SEG[0]; SRCLK <= 1'd0;end15:begin SRCLK <= 1'd1; end16:begin DIO <= SEL[7]; SRCLK <= 1'd0;end17:begin SRCLK <= 1'd1; end18:begin DIO <= SEL[6]; SRCLK <= 1'd0;end19:begin SRCLK <= 1'd1; end20:begin DIO <= SEL[5]; SRCLK <= 1'd0;end    21:begin SRCLK <= 1'd1; end22:begin DIO <= SEL[4]; SRCLK <= 1'd0;end23:begin SRCLK <= 1'd1; end24:begin DIO <= SEL[3]; SRCLK <= 1'd0;end 25:begin SRCLK <= 1'd1; end26:begin DIO <= SEL[2]; SRCLK <= 1'd0;end27:begin SRCLK <= 1'd1; end28:begin DIO <= SEL[1]; SRCLK <= 1'd0;end29:begin SRCLK <= 1'd1; end30:begin DIO <= SEL[0]; SRCLK <= 1'd0;end31:begin SRCLK <= 1'd1; endendcaseend
end
endmodule

仿真代码:

`timescale 1ns / 1nsmodule tube_active_tb();reg clk;reg reset;reg [7:0]SEL;reg [7:0]SEG;wire SRCLK;wire RCLK;wire DIO;tube_active tube_active_inst0(.clk(clk),      .reset(reset),  .SEL(SEL),.SEG(SEG),.SRCLK(SRCLK),.RCLK(RCLK),  .DIO(DIO)  
);initial clk = 1;
always #10 clk = ~clk;initial beginreset = 0;SEL = 8'b0000_0001;SEG = 8'b0101_0101;#201;reset = 1;#5000;SEL = 8'b0000_0010;SEG = 8'b1010_1010;        #5000;SEL = 8'b1010_0101;SEG = 8'b0000_1101;     #5000;$stop;
end
endmodule

在现有模块添加新的源文件,必须点击这里的+,左上角的会出错。新源文件调用了上面的两个模块,让这两个模块连在一起,然后引出三根线与驱动芯片连接。

module tube_shuma_test(input               clk,input               reset,output              SRCLK,output              RCLK,output              DIO,input [1:0]         SW
);wire[7:0] SEL,SEG; //将两个例化的端口连接起来
reg[31:0] Dis_data;  //调用的并转串模块
tube_active tube_active_inst0(.clk(clk),      .reset(reset),  .SEL(SEL),.SEG(SEG),.SRCLK(SRCLK),.RCLK(RCLK),  .DIO(DIO)  
);//调用的hex8模块
Shuma_guan Shuma_guan_inst0(.clk(clk),.reset(reset),.Dis_data(Dis_data),.SEL(SEL),.SEG(SEG)
);  always@(*)
begincase(SW)0:Dis_data <= 32'h01234567;1:Dis_data <= 32'h89abcdef;2:Dis_data <= 32'haaaabbbb;3:Dis_data <= 32'h66666666;endcase
endendmodule

5.实验结果

根据拨码开关的开关情况,数码管显示不同的数字。 

 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

k8s 1.28.2 集群部署 docker registry 接入 MinIO 存储

文章目录 [toc]docker registry 部署生成 htpasswd 文件生成 secret 文件 生成 registry 配置文件创建 service创建 statefulset创建 ingress验证 docker registry docker registry 监控docker registry ui docker registry dockerfile docker registry 配置文件 S3 storage dr…

软件工程笔记二—— 软件生存期模型

目录 瀑布模型 瀑布模型的特点 阶段间具有顺序性和依赖性。 推迟实现的观点 质量保证的观点 瀑布模型的优点 瀑布模型的缺点 快速原型模型 快速原型模型的优点 快速原型模型的缺点 增量模型 增量模型的优点 增量构件开发 螺旋模型 完整的螺旋模型&#xff08;顺…

万字长文解读深度学习——生成对抗网络GAN

&#x1f33a;历史文章列表&#x1f33a; 深度学习——优化算法、激活函数、归一化、正则化深度学习——权重初始化、评估指标、梯度消失和梯度爆炸深度学习——前向传播与反向传播、神经网络&#xff08;前馈神经网络与反馈神经网络&#xff09;、常见算法概要汇总万字长文解读…

【MYSQL】数据库日志 (了解即可)

一、错误日志 可以通过 tail查看文件的日志的&#xff0c;如果发生错误&#xff0c;就会在日志里出现问题。 二、二进制日志&#xff08;binlog&#xff09; BINLOG记录了insert delete update 以及 alter create drop 等语句。作用是灾难时的数据恢复&#xff0c;还有就是主…

整理iPhone空间:iphone怎么删除相簿

随着时间的积累&#xff0c;我们的iPhone中不仅会堆积大量照片&#xff0c;还可能会有多个不再需要的相簿。这些相簿不仅占用存储空间&#xff0c;还可能使相册应用变得杂乱无章。本文将探讨iphone怎么删除相簿&#xff0c;并介绍精简iPhone相册的技巧&#xff0c;使你的相册管…

ABAP关于PS模块CJ20N中项目物料的屏幕和字段增强CI_RSADD

网上搜关于CJ20N的屏幕增强,基本都是关于项目定义(CI_PROJ)、项目WBS(CI_PRPS)、项目网络活动工序(CI_AFVU)的字段与屏幕增强,几乎没有关于项目物料(CI_RSADD)的字段屏幕增强,我在这里做一个分享。 主要逻辑:实现badi增强,并自建一个函数组后创建屏幕,在badi里面调用…

Kettle配置数据源错误“Driver class ‘org.gjt.mm.mysql.Driver‘ could not be found”解决记录

问题描述 错误提示&#xff1a;“Driver class ‘org.gjt.mm.mysql.Driver’ could not be found, make sure the ‘MySQL’ driver (jar file) is installed.” 原因分析&#xff1a; 根据错误提示是缺少了相关的数据源连接jar包。 解决方案&#xff1a; 安装对应的Mysql…

基于Python 和 pyecharts 制作招聘数据可视化分析大屏

在本教程中&#xff0c;我们将展示如何使用 Python 和 pyecharts 库&#xff0c;通过对招聘数据的分析&#xff0c;制作一个交互式的招聘数据分析大屏。此大屏将通过不同类型的图表&#xff08;如柱状图、饼图、词云图等&#xff09;展示招聘行业、职位要求、薪资分布等信息。 …

人力资源招聘系统的革新之路:从传统到智能的转变

在全球化与数字化交织的今天&#xff0c;企业间的竞争日益激烈&#xff0c;而人才作为企业发展的核心驱动力&#xff0c;其重要性不言而喻。传统的人力资源招聘方式&#xff0c;如依赖纸质简历、人工筛选、面对面面试等&#xff0c;不仅效率低下&#xff0c;且难以精准匹配企业…

UE5 UE4 播放视频没有声音解决

开启AVF插件 在项目设置中&#xff0c;AVF 的调试打开。 在项目设置中,WMF Media 中&#xff0c;allow Non standard Codecs,Low Latency 和 Native Audio Out打开。

sql专题 之 where和join on

文章目录 前言where介绍使用过滤结果集关联两个表 连接外连接内连接自然连接 使用inner join和直接使用where关联两个表的区别总结 前言 从数据库查询数据时&#xff0c;一张表不足以查询到我们想要的数据&#xff0c;更多的时候我们需要联表查询。 联表查询我们一般会使用连接…

如何在CentOS 7上搭建SMB服务

如何在CentOS 7上搭建SMB服务 因项目测试需求&#xff0c;需要自行搭建SMB服务&#xff0c;**SMB&#xff08;Server Message Block&#xff09;**协议是一种常用的文件共享方式&#xff0c;它可以让不同操作系统之间共享文件、打印机等资源。本文将带你一步步搭建一个简单的S…

使用CNN进行验证码识别:深度学习与图像预处理教程

验证码&#xff08;CAPTCHA&#xff09;广泛用于区分人类和自动化程序&#xff08;如机器人&#xff09;&#xff0c;通常由扭曲的字母、数字或符号组成。为了实现验证码的自动识别&#xff0c;深度学习尤其是卷积神经网络&#xff08;CNN&#xff09;非常有效。本文将带你一起…

STM32 51单片机设计半导体制冷片温控设计

目录 前言 一、本设计主要实现哪些很“开门”功能&#xff1f; 二、电路设计原理图 1.电路图采用Altium Designer进行设计&#xff1a; 三、实物设计图 四、程序源代码设计 五、获取资料内容 前言 基于STM32与51单片机的半导体制冷片温控设计 前言 随着现代工业、医疗…

ssm114基于SSM框架的网上拍卖系统的设计与实现+vue(论文+源码)_kaic

摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff0c;商品拍卖当然也不能排除在外&#xff0c;随着商品拍卖管理的不断成熟&#xff0c;它彻底改变了过去传统的经营管理方式&#xff0c;不仅使商品…

算法每日双题精讲——滑动窗口(长度最小的子数组,无重复字符的最长子串)

&#x1f31f;快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 &#x1f31f; 别再犹豫了&#xff01;快来订阅我们的算法每日双题精讲专栏&#xff0c;一起踏上算法学习的精彩之旅吧&#xff01;&#x1f4aa;…

批量从Excel某一列中找到符合要求的值并提取其对应数据

本文介绍在Excel中&#xff0c;从某一列数据中找到与已知数据对应的字段&#xff0c;并提取这个字段对应数值的方法。 首先&#xff0c;来明确一下我们的需求。现在已知一个Excel数据&#xff0c;假设其中W列包含了上海市全部社区的名称&#xff0c;而其后的Y列则是这些社区对应…

MaxKB

docker 安装 MaxKB docker run -d --namemaxkb --restartalways -p 8080:8080 -v ~/.maxkb:/var/lib/postgresql/data -v ~/.python-packages:/opt/maxkb/app/sandbox/python-packages cr2.fit2cloud.com/1panel/maxkbdocker psCONTAINER ID IMAGE …

越南很火的slots游戏投放Google谷歌广告策略

越南很火的slots游戏投放Google谷歌广告策略 越南的slot游戏市场正在借助Google广告代投策略推动增长。随着智能手机的普及和互联网的普及&#xff0c;越南的游戏市场迅速增长&#xff0c;吸引了越来越多的投资者和开发者进入该市场。 在这个竞争激烈的市场中&#xff0c;广告…

现代无线通信接收机架构:超外差、零中频与低中频的比较分析

写在前面&#xff1a;本博客是对三种接收机架构的学习笔记&#xff0c;仅供个人学习记录使用。内容主要是上网查阅的资料&#xff0c;以及个人的一些理解。如有错误的地方请指出&#xff01; 文章目录 一、通信机基本架构1、射频发射级的基本组成及完成功能2、射频接收级的基本…