Intel FPGA (3):数码管显示

Intel FPGA (3):数码管显示

前提摘要

  1. 个人说明:

    • 限于时间紧迫以及作者水平有限,本文错误、疏漏之处恐不在少数,恳请读者批评指正。意见请留言或者发送邮件至:“Email:noahpanzzz@gmail.com”
    • 本博客的工程文件均存放在:GitHub:https://github.com/panziping。
    • 本博客的地址:CSDN:https://blog.csdn.net/ZipingPan
  2. 参考:

    • 芯片型号:Intel EP4CE10F17C8(Cyclone IV E)
    • 《数字电子技术基础》-阎石
    • 《FPGA自学笔记—设计与验证》袁玉卓,曾凯锋,梅雪松
    • 《Verilog 数字系统设计教程》夏宇闻
    • 《Verilog HDL 高级数字设计》Michael D.Ciletti
    • 《Intel FPGA/CPLD设计》(基础篇)王欣 王江宏等
    • 《Intel FPGA/CPLD设计》(高级篇)王江宏 蔡海宁等
    • 《综合与时序分析的设计约束 Synopsys设计约束(SDC)实用指南》Sridhar Gangadharan
  3. 日期:

    • 2024-01-01

正文

正文

硬件资源

在这里插入图片描述

图中HEX_A、HEX_B、HEX_C、HEX_D、HEX_E、HEX_F、HEX_G、HEX_DP控制的是数码管的段码;HEX_SEL0、HEX_SEL1、HEX_SEL2、HEX_SEL3、HEX_SEL4、HEX_SEL5、HEX_SEL6、HEX_SEL7控制的是数码管的位码。

数码管分为共阴极数码管和共阳极数码管,本篇中使用的是共阳极数码管

下表为共阳极数码管译码表。

在这里插入图片描述

数码管的显示方式有独立显示和扫描显示。本篇使用的扫描显示

扫描显示的原理是由于人眼的余晖效应,上图8个数码管,每个时刻只有一个数码管显示,依次循环,只要扫描的频率足够高(1KHz),在人眼看到的数码管显示就是连续的。

由于直接驱动需要消耗IO的数量为18,太过于占用IO资源,所以数码管显示使用到的驱动芯片是74HC595,这样只需要消耗3个IO,将串行信号转化为并行信号。

74HC595

这里截取了74HC595的部分数据手册,读者自行阅读。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

程序编写

根据74HC595数据手册编写驱动代码。

由上文74HC595数据手册可以知道SH_CP(SCLK)、ST_CP(RCLK)和DS(DIO)的时序关系。

在这里插入图片描述

74HC595驱动程序:

module hc595_driver(clk,rst_n,seg_data,seg_data_valid_go,seg_sclk,seg_rclk,seg_dio
);input clk;input rst_n;input [15:0] seg_data;input seg_data_valid_go;output reg seg_sclk;output reg seg_rclk;output reg seg_dio;reg [15:0] r_seg_data;always@(posedge clk or negedge rst_n) beginif(!rst_n)r_seg_data <= 'd0;else if(seg_data_valid_go == 1'b1)r_seg_data <= seg_data;elser_seg_data <= r_seg_data;endlocalparam DIV_CNT_MAX = 4;			//fseg_sclk = 6.25MHzreg [2:0] r_div_cnt;always@(posedge clk or negedge rst_n) beginif(!rst_n)r_div_cnt <= 'd0;else if(r_div_cnt == DIV_CNT_MAX -1)r_div_cnt <= 'd0;else	r_div_cnt <= r_div_cnt + 1'b1;endwire w_sclk_pluse;	//SH_CPassign w_sclk_pluse = (r_div_cnt == DIV_CNT_MAX -1) ? 1'b1 :1'b0;reg [4:0] r_sclk_edge_cnt;	//SH_CPalways@(posedge clk or negedge rst_n) beginif(!rst_n)r_sclk_edge_cnt <= 'd0;else if(w_sclk_pluse == 1'b1)if(r_sclk_edge_cnt == 5'd31)r_sclk_edge_cnt <= 'd0;elser_sclk_edge_cnt <= r_sclk_edge_cnt + 1'd1;elser_sclk_edge_cnt <= r_sclk_edge_cnt;endalways@(posedge clk or negedge rst_n) beginif(!rst_n) beginseg_sclk <= 1'd0;seg_rclk <= 1'd0;seg_dio <= 1'd0;endelse begincase(r_sclk_edge_cnt)5'd0 : begin seg_sclk = 1'b0; seg_rclk = 1'b1; seg_dio = r_seg_data[15]; end //Q2H(HEX_DP)5'd1 : begin seg_sclk = 1'b1; seg_rclk = 1'b0;  								 end 5'd2 : begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[14]; end //Q2G(HEX_G)5'd3 : begin seg_sclk = 1'b1;								   						 end5'd4 : begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[13]; end //Q2F(HEX_F)5'd5 : begin seg_sclk = 1'b1;														    end5'd6 : begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[12]; end //Q2E(HEX_E)5'd7 : begin seg_sclk = 1'b1;														    end5'd8 : begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[11]; end //Q2D(HEX_D)	5'd9 : begin seg_sclk = 1'b1;														    end5'd10: begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[10]; end //Q2C(HEX_C)	5'd11: begin seg_sclk = 1'b1;														    end5'd12: begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[9];  end //Q2B(HEX_B)	5'd13: begin seg_sclk = 1'b1;					    									 end5'd14: begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[8];  end //Q2A(HEX_A)5'd15: begin seg_sclk = 1'b1;					    									 end5'd16: begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[7];  end //Q1H(HEX_SEL7)		5'd17: begin seg_sclk = 1'b1;					    									 end5'd18: begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[6];  end //Q1G(HEX_SEL6)5'd19: begin seg_sclk = 1'b1;					    									 end5'd20: begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[5];  end //Q1F(HEX_SEL5)5'd21: begin seg_sclk = 1'b1;					    									 end5'd22: begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[4];  end //Q1E(HEX_SEL4)		5'd23: begin seg_sclk = 1'b1;					    									 end5'd24: begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[3];  end //Q1D(HEX_SEL3)			5'd25: begin seg_sclk = 1'b1;					    									 end5'd26: begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[2];  end //Q1C(HEX_SEL2)	5'd27: begin seg_sclk = 1'b1;					    									 end5'd28: begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[1];  end //Q1B(HEX_SEL1)	5'd29: begin seg_sclk = 1'b1;					    									 end5'd30: begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[0];  end //Q1A(HEX_SEL0)5'd31: begin seg_sclk = 1'b1;					    									 enddefault:;endcaseendendendmodule 

8位数码管显示程序:

显示内容(32位数据,每个数码管占4位)转化为数码管显示编码(16位数据,依次是1位dp位,7位段码,8位位码)。

module seg_disp(clk,rst_n,disp_en,disp_data,disp_data_valid_go,seg_data,seg_data_valid_go
);input clk;input rst_n;input disp_en;input [31:0] disp_data;input disp_data_valid_go;output reg [14:0] seg_data;output reg seg_data_valid_go;reg [31:0] r_disp_data;always@(posedge clk or negedge rst_n) beginif(!rst_n)r_disp_data <= 'd0;else if(disp_data_valid_go == 1'b1) r_disp_data <= disp_data;elser_disp_data <= r_disp_data;end//segment refresh frequency: 1KHzlocalparam REFRESH_CNT_MAX = 50_000_000 / 1000;reg [$clog2(REFRESH_CNT_MAX)-1:0] r_refresh_cnt;always@(posedge clk or negedge rst_n) beginif(!rst_n)r_refresh_cnt <= 'd0;else if(disp_en == 1'b1) if(r_refresh_cnt == REFRESH_CNT_MAX - 1)r_refresh_cnt <= 'd0;elser_refresh_cnt <= r_refresh_cnt + 1'd1;elser_refresh_cnt <= 'd0;endwire w_refresh_pluse;assign w_refresh_pluse = (r_refresh_cnt == REFRESH_CNT_MAX - 1) ? 1'b1:1'b0;reg [7:0] r_seg_sel;always@(posedge clk or negedge rst_n) beginif(!rst_n)r_seg_sel <= 8'b0000_0001;else if(w_refresh_pluse == 1'b1)r_seg_sel <= {r_seg_sel[6:0],r_seg_sel[7]};elser_seg_sel <= r_seg_sel;endreg [3:0] r_seg_disp;always@(*) begincase(r_seg_sel)8'b0000_0001 : r_seg_disp = r_disp_data[3:0];8'b0000_0010 : r_seg_disp = r_disp_data[7:4];8'b0000_0100 : r_seg_disp = r_disp_data[11:8];8'b0000_1000 : r_seg_disp = r_disp_data[15:12];8'b0001_0000 : r_seg_disp = r_disp_data[19:16];8'b0010_0000 : r_seg_disp = r_disp_data[23:20];8'b0100_0000 : r_seg_disp = r_disp_data[27:24];8'b1000_0000 : r_seg_disp = r_disp_data[31:28];		default:r_seg_disp = 4'b0000;endcaseendreg [6:0] r_seg_code;always@(*) begincase(r_seg_disp)4'h0: r_seg_code = 7'b1000000;4'h1: r_seg_code = 7'b1111001;4'h2: r_seg_code = 7'b0100100;4'h3: r_seg_code = 7'b0110000;4'h4: r_seg_code = 7'b0011001;4'h5: r_seg_code = 7'b0010010;4'h6: r_seg_code = 7'b0000010;4'h7: r_seg_code = 7'b1111000;4'h8: r_seg_code = 7'b0000000;4'h9: r_seg_code = 7'b0010000;4'ha: r_seg_code = 7'b0001000;4'hb: r_seg_code = 7'b0000011;4'hc: r_seg_code = 7'b1000110;4'hd: r_seg_code = 7'b0100001;4'he: r_seg_code = 7'b0000110;4'hf: r_seg_code = 7'b0001110;default:;endcaseendreg [1:0] r_refresh_pluse_sync;always@(posedge clk or negedge rst_n) beginif(!rst_n)r_refresh_pluse_sync <= 'd0;else r_refresh_pluse_sync <= {r_refresh_pluse_sync[0],w_refresh_pluse};endalways@(posedge clk or negedge rst_n) beginif(!rst_n) beginseg_data <= 'd0;seg_data_valid_go <= 1'd0;endelse if(r_refresh_pluse_sync[1] == 1'b1) beginseg_data <= disp_en ? {r_seg_code,r_seg_sel} : 15'd0;seg_data_valid_go <= disp_en ? 1'b1 : 1'b0;end	else beginseg_data <= seg_data;seg_data_valid_go <= seg_data_valid_go;endendendmodule

用于测试的顶层文件:

`timescale 1ns/1ns
module segment(i_clk,i_rst_n,o_seg_sclk,o_seg_rclk,o_seg_dio
);input i_clk;input i_rst_n;output o_seg_sclk;output o_seg_rclk;output o_seg_dio;wire  [31:0] disp_data;assign disp_data = 32'habcdef12;wire [15:0] seg_data;wire seg_data_valid_go;seg_disp seg_disp(.clk(i_clk),.rst_n(i_rst_n),.disp_en(1'b1),.disp_data(disp_data),.disp_data_valid_go(1'b1),.seg_data(seg_data[14:0]),.seg_data_valid_go(seg_data_valid_go)
);hc595_driver hc595_driver(.clk(i_clk),.rst_n(i_rst_n), .seg_data({1'b1,seg_data[14:0]}),		//{1bit dp,7bit seg_code, 8bit seg_sel}.seg_data_valid_go(seg_data_valid_go),.seg_sclk(o_seg_sclk),.seg_rclk(o_seg_rclk),.seg_dio(o_seg_dio)
);endmodule

总结

本工程名为segment,如有需要请至github仓库查看!!!


本文均为原创,欢迎转载,请注明文章出处:CSDN:https://blog.csdn.net/ZipingPan。百度和各类采集站皆不可信,搜索请谨慎鉴别。技术类文章一般都有时效性,本人习惯不定期对自己的博文进行修正和更新,因此请访问出处以查看本文的最新版本。

非原创博客会在文末标注出处,由于时效原因,可能并不是原创作者地址(已经无法溯源)。

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

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

相关文章

SSM框架学习——SqlSession以及Spring与MyBatis整合

SqlSession以及Spring与MyBatis整合 准备所需要的JAR包 要实现MyBatis与Spring的整合&#xff0c;很明显需要这两个框架的JAR包&#xff0c;但是只是使用这两个框架中所提供的JAR包是不够的&#xff0c;还需要配合其他包使用&#xff1a; Spring的JAR包MyBatis的JAR包Spring…

【源头活水】顶刊解读!IEEE T-PAMI (CCF-A,IF 23.6)2024年46卷第一期 [3]

“问渠那得清如许&#xff0c;为有源头活水来”&#xff0c;通过前沿领域知识的学习&#xff0c;从其他研究领域得到启发&#xff0c;对研究问题的本质有更清晰的认识和理解&#xff0c;是自我提高的不竭源泉。为此&#xff0c;我们特别精选论文阅读笔记&#xff0c;开辟“源头…

上位机图像处理和嵌入式模块部署(qmacviusal边缘宽度测量)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面有一篇文章&#xff0c;我们了解了测量标定是怎么做的。即&#xff0c;我们需要提前知道测量的方向&#xff0c;灰度的方向&#xff0c;实际的…

如何选择最佳AVR微控制器:综合性能、功耗、封装及生态支持全方位考量

AVR 微控制器的定义 AVR 微控制器是由Atmel公司&#xff08;现已被Microchip Technology收购&#xff09;开发的一种基于 Reduced Instruction Set Computing (RISC) 架构的8位微控制器系列。其名称“AVR”来源于其最初的设计理念——Audio Video Recorder&#xff0c;尽管后来…

springboot实战---7.springboot制作Docker镜像

&#x1f388;个人主页&#xff1a;靓仔很忙i &#x1f4bb;B 站主页&#xff1a;&#x1f449;B站&#x1f448; &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;SpringBoot &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&…

MySQL常见故障案例与优化介绍

前言 MySQL故障排查的意义在于及时识别并解决数据库系统中的问题&#xff0c;确保数据的完整性和可靠性&#xff1b;而性能优化则旨在提高数据库系统的效率和响应速度&#xff0c;从而提升用户体验和系统整体性能。这两方面的工作都对于保证数据库系统稳定运行、提升业务效率和…

数据结构——数组

数组定义&#xff1a; 在计算机科学中&#xff0c;数组是由一组元素&#xff08;值或变量&#xff09;组成的数据结构&#xff0c;每个元素有至少一个索引或键来标识。 因为数组内的元素是连续存储的&#xff0c;所以数组中元素的地址&#xff0c;可以通过其索引计算出来。 性…

latex学习笔记

一 安装latex&#xff08;vscodetexlive&#xff09; 安装latex学习链接&#xff1a; 【超详细】最好用LaTex环境安装配置手把手教学&#xff01;&#xff01;&#xff08;支持双向搜索&#xff0c;附赠所需安装包及竞赛模板&#xff09;_哔哩哔哩_bilibilihttps://www.bilib…

NoSQL之 Redis配置

目录 关系数据库与非关系型数据库 关系型数据库&#xff1a; ●非关系型数据库 关系型数据库和非关系型数据库区别&#xff1a; &#xff08;1&#xff09;数据存储方式不同 &#xff08;2&#xff09;扩展方式不同 对事务性的支持不同 非关系型数据库产生背景 Redis简介…

6000000IOPS!FASS×kunpeng920全新突破

实测数据详见下文 网络环境 前端和后端网均采用100GE网络&#xff0c;管理网采用1Gbps以太网。 前端网和后端网通过不同网段隔离&#xff0c;与管理网物理隔离。 软硬件配置 存储端配置&#xff1a; 客户端配置&#xff1a; 软件配置&#xff1a; 存储集群配置&#xff1a; …

30分钟了解所有引擎组件,132个Unity 游戏引擎组件速通!【收藏 == 学会】

前言 &#x1f3ac;【全网首发】 | 30分钟了解所有组件&#xff0c;132个Unity 游戏引擎组件速通&#xff01;一、Mesh 网格1.Mesh Filter2.Mesh Renderer3.Skinned Mesh Renderer4.Text Mesh5.TextMeshPro-Text 二、Effects 特效组件1.Particle System2.Visual Effect3.Trail …

算法题->有效的三角形个数C语言和JAVA版本双指针解法

有效的三角形个数C语言和JAVA版本双指针解法 力扣链接:https://leetcode.cn/problems/valid-triangle-number/description/ 题目描述: 题意:给你一个数组,通过数组中的三个值进行组成有效三角形,最后返回有效三角形个数 例子: 由例子可知,不同下标的一个值和相同两个值组成…