Intel FPGA:数码管显示

这篇具有很好参考价值的文章主要介绍了Intel FPGA:数码管显示。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Intel FPGA:数码管显示

前提摘要

  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

正文

正文

硬件资源

Intel FPGA:数码管显示,# FPGA,Intel FPGA

图中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控制的是数码管的位码。

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

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

Intel FPGA:数码管显示,# FPGA,Intel FPGA

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

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

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

74HC595

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

Intel FPGA:数码管显示,# FPGA,Intel FPGA

Intel FPGA:数码管显示,# FPGA,Intel FPGA

Intel FPGA:数码管显示,# FPGA,Intel FPGA

程序编写

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

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

Intel FPGA:数码管显示,# FPGA,Intel FPGA

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) begin
		if(!rst_n)
			r_seg_data <= 'd0;
		else if(seg_data_valid_go == 1'b1)
			r_seg_data <= seg_data;
		else
			r_seg_data <= r_seg_data;
	end
	
	localparam DIV_CNT_MAX = 4;			//fseg_sclk = 6.25MHz
	reg [2:0] r_div_cnt;
	
	always@(posedge clk or negedge rst_n) begin
		if(!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;
	end
	wire w_sclk_pluse;	//SH_CP
	assign w_sclk_pluse = (r_div_cnt == DIV_CNT_MAX -1) ? 1'b1 :1'b0;
	
	
	reg [4:0] r_sclk_edge_cnt;	//SH_CP
	
	
	always@(posedge clk or negedge rst_n) begin
		if(!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;
			else
				r_sclk_edge_cnt <= r_sclk_edge_cnt + 1'd1;
		else
			r_sclk_edge_cnt <= r_sclk_edge_cnt;
	end
	

	
	always@(posedge clk or negedge rst_n) begin
		if(!rst_n) begin
			seg_sclk <= 1'd0;
			seg_rclk <= 1'd0;
			seg_dio <= 1'd0;
		end
		else begin
			case(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;								   						 end
				5'd4 : begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[13]; end //Q2F(HEX_F)
				5'd5 : begin seg_sclk = 1'b1;														    end
				5'd6 : begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[12]; end //Q2E(HEX_E)
				5'd7 : begin seg_sclk = 1'b1;														    end
				5'd8 : begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[11]; end //Q2D(HEX_D)	
				5'd9 : begin seg_sclk = 1'b1;														    end
				5'd10: begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[10]; end //Q2C(HEX_C)	
				5'd11: begin seg_sclk = 1'b1;														    end
				5'd12: begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[9];  end //Q2B(HEX_B)	
				5'd13: begin seg_sclk = 1'b1;					    									 end
				5'd14: begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[8];  end //Q2A(HEX_A)
				5'd15: begin seg_sclk = 1'b1;					    									 end
				5'd16: begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[7];  end //Q1H(HEX_SEL7)		
				5'd17: begin seg_sclk = 1'b1;					    									 end
				5'd18: begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[6];  end //Q1G(HEX_SEL6)
				5'd19: begin seg_sclk = 1'b1;					    									 end
				5'd20: begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[5];  end //Q1F(HEX_SEL5)
				5'd21: begin seg_sclk = 1'b1;					    									 end
				5'd22: begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[4];  end //Q1E(HEX_SEL4)		
				5'd23: begin seg_sclk = 1'b1;					    									 end
				5'd24: begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[3];  end //Q1D(HEX_SEL3)			
				5'd25: begin seg_sclk = 1'b1;					    									 end
				5'd26: begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[2];  end //Q1C(HEX_SEL2)	
				5'd27: begin seg_sclk = 1'b1;					    									 end
				5'd28: begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[1];  end //Q1B(HEX_SEL1)	
				5'd29: begin seg_sclk = 1'b1;					    									 end
				5'd30: begin seg_sclk = 1'b0;				        seg_dio = r_seg_data[0];  end //Q1A(HEX_SEL0)
				5'd31: begin seg_sclk = 1'b1;					    									 end
				default:;
			endcase
		end
	end

endmodule 

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) begin
		if(!rst_n)
			r_disp_data <= 'd0;
		else if(disp_data_valid_go == 1'b1) 
			r_disp_data <= disp_data;
		else
			r_disp_data <= r_disp_data;
	end
    
    
    
	//segment refresh frequency: 1KHz
	localparam REFRESH_CNT_MAX = 50_000_000 / 1000;
	
	reg [$clog2(REFRESH_CNT_MAX)-1:0] r_refresh_cnt;
	always@(posedge clk or negedge rst_n) begin
		if(!rst_n)
			r_refresh_cnt <= 'd0;
		else if(disp_en == 1'b1) 
			if(r_refresh_cnt == REFRESH_CNT_MAX - 1)
				r_refresh_cnt <= 'd0;
			else
				r_refresh_cnt <= r_refresh_cnt + 1'd1;
		else
			r_refresh_cnt <= 'd0;
	end
	wire 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) begin
		if(!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]};
		else
			r_seg_sel <= r_seg_sel;
	end
	
	
	reg [3:0] r_seg_disp;
	always@(*) begin
		case(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;
		endcase
	end
	
	reg [6:0] r_seg_code;
	always@(*) begin
		case(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:;
		endcase
	end
	
	
	
	reg [1:0] r_refresh_pluse_sync;
	always@(posedge clk or negedge rst_n) begin
		if(!rst_n)
			r_refresh_pluse_sync <= 'd0;
		else 
			r_refresh_pluse_sync <= {r_refresh_pluse_sync[0],w_refresh_pluse};
	end
	
	
	always@(posedge clk or negedge rst_n) begin
		if(!rst_n) begin
			seg_data <= 'd0;
			seg_data_valid_go <= 1'd0;
		end
		else if(r_refresh_pluse_sync[1] == 1'b1) begin
			seg_data <= disp_en ? {r_seg_code,r_seg_sel} : 15'd0;
			seg_data_valid_go <= disp_en ? 1'b1 : 1'b0;
		end	
		else begin
			seg_data <= seg_data;
			seg_data_valid_go <= seg_data_valid_go;
		end
	end

	
endmodule

用于测试的顶层文件:

`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/FPGA。百度和各类采集站皆不可信,搜索请谨慎鉴别。技术类文章一般都有时效性,本人习惯不定期对自己的博文进行修正和更新,因此请访问出处以查看本文的最新版本。

非原创博客会在文末标注出处,由于时效原因,可能并不是原创作者地址(已经无法溯源)。文章来源地址https://www.toymoban.com/news/detail-852575.html

到了这里,关于Intel FPGA:数码管显示的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [FPGA 学习记录] 数码管动态显示

    数码管动态显示 在上一小节当中,我们对数码管的静态显示做了一个详细的讲解;但是如果单单只掌握数码管的静态显示这种显示方式是远远不够的,因为数码管的静态显示当中,被选中的数码位它们显示的内容都是相同的,这种显示方式在我们的实际应用当中显然是不合适

    2024年02月04日
    浏览(50)
  • FPGA基础设计之数码管显示

    数码管是一种半导体发光器件,其基本单元是发光二极管。一般分为七段数码管和八段数码管,多的一段是小数点。也有其他如N型、米型数码管以及16段、24段管等。本次设计的是八段数码管 公阴极数码管高电平亮,公阳极数码管低电平亮。AC620上搭载的是公阳极数码管。 数

    2023年04月26日
    浏览(46)
  • [FPGA 学习记录] 数码管静态显示

    数码管静态显示 在我们的许多项目设计当中,我们通常需要一些显示设备来显示我们需要的信息。我们可以选择的显示设备有很多,而我们的数码管就是使用最多、最简单的显示设备之一。数码管它是一种半导体发光器件,它具有响应时间短、体积小、重量轻、寿命长的优点

    2024年02月03日
    浏览(51)
  • 二、19【FPGA】数码管动态显示实验

    学习说明此文档为本人的学习笔记,注重实践,关于理论部分会给出相应的学习链接。 学习视频:是根据野火FPGA视频教程——第二十二讲 https://www.bilibili.com/video/BV1nQ4y1Z7zN?p=3 “天下武功唯快不破”    “看到的不一定为真” 眼睛的视觉暂留:光信号传入大脑需要短暂时间,

    2023年04月08日
    浏览(37)
  • FPGA学习汇总(六)----数码管显示(1)

    目录 概念 单个数码管显示单个数字  操作  代码  现象 分析 四个数码管定时单个显示数字 分析 代码 四个数码管同时显示 分析 代码 现象

    2024年02月01日
    浏览(50)
  • FPGA学习之数码管时间显示模块

    在学习完小梅哥的串口通信以及数码管显示教程后,他留下了一个课后作业,也就是本次的数码管时间显示模块。作为一个FPGA新人,这也算是第一个比较完整的练手小项目了,也推荐和我一样的新人花时间去完成一下。总体功能虽然比较简单,但是我也花了小两天的时间去编

    2024年03月10日
    浏览(60)
  • FPGA基本实验之数码管的静态显示

    此实验基于FPGA征途pro开发板实现, 数码管是一种半导体发光器件,其基本单元是发光二极管。数码管按段数一般分为七 段数码管和八段数码管,八段数码管比七段数码管多一个发光二极管(多一个小数点显 示)。当然也还有一些其他类型的数码管如“N”形管、“米”字管

    2024年02月03日
    浏览(49)
  • FPGA基本实验之数码管的动态显示

            关于数码管的基本知识大家可以参考我上一篇文章数码管的静态显示,         使用 1ms 的刷新时间让六个数码管轮 流显示:第 1ms 点亮第一个数码管,第 2ms 点亮第二个数码管,以此类推依次点亮六个数 码管,6ms 一个轮回,也就是说每个数码管每 6ms 点亮

    2024年02月08日
    浏览(39)
  • FPGA项目(5)--FPGA控制数码管动态显示的原理

            数码管是现在电子产品上常用的显示器件,它有驱动简单、显示清晰、价格低廉等优势。数码管的实物图:          数码管的内部结构图如下所示:          从图中可以看出,它由八个段组成,即A B C D E F G DP(小数点),只要将这八个段按规律组合点亮,就

    2024年02月11日
    浏览(51)
  • FPGA 驱动数码管动态显示(Verilog&Vivado)

    应用实例: (1)使用串口发送实现ACX720开发板时钟显示 本章将实现 FPGA 驱动数码管动态显示并提取出实现的电路结构,从电路结构入手编写代码,仿真对设计进行验证。最终板级调试时使用 Virtual Input/Output(VIO,虚拟输入/输出端口工具),输入需要显示的数据,数码管则显

    2023年04月12日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包