数码管进阶设计验证

news2024/11/14 7:54:53

前言

        随着数字电路和嵌入式系统的广泛应用,数码管作为一种常见的显示设备,在各种电子产品中扮演着重要角色。数码管以其结构简单、显示清晰和成本低廉的特点,广泛应用于计数器、时钟、测量仪器等领域。然而,传统的数码管设计通常仅支持基本的数字显示功能,难以满足现代应用对更复杂显示需求的要求。

        近年来,随着FPGA技术的发展和应用,数码管的驱动设计也迎来了新的机遇。FPGA(现场可编程门阵列)作为一种强大的数字逻辑设计平台,具有高度的灵活性和并行处理能力,使得数码管驱动的设计可以实现更复杂的功能,例如显示正负号、小数点等。此外,FPGA支持的逻辑设计验证工具和方法也为设计的可靠性和稳定性提供了保障。

        本项目旨在基于FPGA平台,设计一种支持正负号和小数点显示的数码管驱动系统。该系统不仅能够满足基本的数字显示需求,还能够处理更复杂的显示要求,适应现代电子设备对显示功能的多样化需求。通过对FPGA平台的深入研究和应用,我们将探讨如何在数码管显示中实现这些进阶功能,并验证设计的正确性和有效性。

正文

一、数码管进阶设计验证

        1.项目需求

本项目旨在基于FPGA平台,设计一种支持正负号和小数点显示的数码管驱动系统。

        2.技术介绍

驱动部分请参考简易数字钟

本章节重在介绍如何使数码管显示正负号于小数点:

对于在之前做的数码管驱动模块有很多不足:输入数据为BCD码,并且只能输入BCD码,输入数据如果是二进制数据,数码管显示是错误的。


module seg_driver(
 
	input clk,
	input rst_n,
	input [23:0] data_in,//接收数字时钟信号
	
	output reg [2:0] sel,//位选信号
	output reg [7:0] seg//段选信号
);

针对不足处,本章节在模块内调用一二进制码转BCD码模块,使得输入数据易产生与传递,在此基础上,增加一小数点位输入用6位独热编码表示当前小数点位置,增加一标志信号输入,表示现在数值是正数还是负数。

module shu_ma_g_MAX(

	input 				clk		,
	input					rst_n		,
	input	[19:0]		data		,//数据2进制
	input [ 5:0]		point		,//小数点位
	input					signe		,//正负号位
	input					seg_en	,//数码管使能
	
	output reg[2:0]	sel		,
	output reg[7:0]	seg 		

);

        3.顶层架构

        4.端口描述

clk时钟
rst_n复位信号
data[19:0]输入数据(2进制数据)
point[5:0]小数点位
signe正负号位
seg_en数码管使能
sel[2:0]位选信号
seg[7:0]段选信号

二、代码验证

数码管驱动模块

module shu_ma_g_MAX(

	input 				clk		,
	input					rst_n		,
	input	[19:0]		data		,//数据2进制
	input [ 5:0]		point		,//小数点位
	input					signe		,//正负号位
	input					seg_en	,//数码管使能
	
	output reg[2:0]	sel		,
	output reg[7:0]	seg 		

);

parameter cnt_1ms_max = 16'd49999;

wire[3:0] data1				;//数码管数据
wire[3:0] data2				;//数码管数据
wire[3:0] data3				;//数码管数据
wire[3:0] data4				;//数码管数据
wire[3:0] data5				;//数码管数据
wire[3:0] data6				;//数码管数据

reg[23:0]data_reg			;//寄存显示数据

reg[15:0]cnt_1ms			;//1ms计数器
reg		cnt_1ms_flag	;
reg[2:0]	cnt_sel			;//扫描周期计数器
reg[3:0] data_zhan		;//数码管显示暂存数据
reg 		point_flag		;//小数点使能信号
reg[2:0] sel_reg			;//暂存输出

always@(posedge clk,negedge rst_n)//判断符号位
begin
	if(rst_n == 0)
		data_reg <= 24'b0;
	else
		if((data6)||(point[5]))
			data_reg <= {data6,data5,data4,data3,data2,data1};
		else
			if(((data5)||(point[4]))&&(signe == 1'b1))//最高位为符号位011-111
				data_reg <= {4'd10,data5,data4,data3,data2,data1};
			else
				if(((data5)||(point[4]))&&(signe == 1'b0))
					data_reg <= {4'd11,data5,data4,data3,data2,data1};
				else
					
			if(((data4)||(point[3]))&&(signe == 1'b1))//次高位为符号位001-111
				data_reg <= {4'd11,4'd10,data4,data3,data2,data1};
			else
				if(((data4)||(point[3]))&&(signe == 1'b0))
					data_reg <= {4'd11,4'd11,data4,data3,data2,data1};
				else
				
			if(((data3)||(point[2]))&&(signe == 1'b1))//次次高位为符号位000-111
				data_reg <= {4'd11,4'd11,4'd10,data3,data2,data1};
			else
				if(((data3)||(point[2]))&&(signe == 1'b0))
					data_reg <= {4'd11,4'd11,4'd11,data3,data2,data1};
				else
				
			if(((data2)||(point[1]))&&(signe == 1'b1))//次次次高位为符号位000-011
				data_reg <= {4'd11,4'd11,4'd11,4'd10,data2,data1};
			else
				if(((data2)||(point[1]))&&(signe == 1'b0))
					data_reg <= {4'd11,4'd11,4'd11,4'd11,data2,data1};
				else
												
			if(((data1)||(point[0]))&&(signe == 1'b1))//次次次次高位为符号位000-001
				data_reg <= {4'd11,4'd11,4'd11,4'd11,4'd10,data1};
			else
				data_reg <= {4'd11,4'd11,4'd11,4'd11,4'd11,data1};
						
end

always@(posedge clk,negedge rst_n)	//计数器驱动模块
begin
	if(rst_n == 0)
		cnt_1ms <= 16'd0;
	else
		if(cnt_1ms == cnt_1ms_max)
			cnt_1ms <= 16'd0;
		else
			cnt_1ms <= cnt_1ms + 16'd1;
		
end

always@(posedge clk,negedge rst_n)//1ms标志信号
begin
	if(rst_n == 0)
		cnt_1ms_flag <= 1'b0;
	else
		if(cnt_1ms == cnt_1ms_max)
			cnt_1ms_flag <= 1'b1;
		else
			cnt_1ms_flag <= 1'b0;
end

always@(posedge clk,negedge rst_n)//扫描周期计数器使能
begin
	if(rst_n == 0)
		cnt_sel <= 3'd0;
	else
		if((cnt_sel == 3'd5)&&(cnt_1ms_flag <= 1'b1))
			cnt_sel <= 3'd0;
		else
			if(cnt_1ms_flag <= 1'b1)
				cnt_sel <= cnt_sel + 3'd1;
			else
				cnt_sel <= cnt_sel;
end
		
always@(posedge clk,negedge rst_n)//暂存输出
begin
	if(rst_n == 0)
		sel_reg <= 3'd0;
	else
		if((cnt_sel == 3'd0)&&(cnt_1ms_flag <= 1'b1))
			sel_reg <= 3'd0;
		else
			if(cnt_1ms_flag <= 1'b1)
				sel_reg <= sel_reg + 1'd1;
			else
				sel_reg <= sel_reg;
end

always@(posedge clk,negedge rst_n)//段码数据传递
begin
	if(rst_n == 0)
		data_zhan <= 4'd0;
	else
		if((seg_en == 1'b1)&&(cnt_1ms_flag <= 1'b1))
			case(cnt_sel)
				3'd0 : data_zhan <= data_reg[3:0];
				3'd1 : data_zhan <= data_reg[7:4];
				3'd2 : data_zhan <= data_reg[11:8];
				3'd3 : data_zhan <= data_reg[15:12];
				3'd4 : data_zhan <= data_reg[19:16];
				3'd5 : data_zhan <= data_reg[23:20];
			default : data_zhan <= 4'd0;
			endcase
		else
			data_zhan <= data_zhan;
end

always@(posedge clk,negedge rst_n)//小数点点亮
begin
	if(rst_n == 0)
		point_flag <= 1'b0;
	else
		if(cnt_1ms_flag <= 1'b1)
			point_flag <= ~point[cnt_sel];
		else
			point_flag <= point_flag;
end
							
always@(posedge clk,negedge rst_n)//段码数值判断并输出
begin
	if(rst_n == 0)		
		seg <= 8'b1111_1111;//0
	else
		case(data_zhan)
			4'd0 : seg <= {point_flag,7'd100_0000};//0
			4'd1 : seg <= {point_flag,7'd100_0000};//1
			4'd2 : seg <= {point_flag,7'd100_0000};//2
			4'd3 : seg <= {point_flag,7'd100_0000};//3
			4'd4 : seg <= {point_flag,7'd100_0000};//4
			4'd5 : seg <= {point_flag,7'd100_0000};//5
			4'd6 : seg <= {point_flag,7'd100_0000};//6
			4'd7 : seg <= {point_flag,7'd100_0000};//7
			4'd8 : seg <= {point_flag,7'd100_0000};//8
			4'd9 : seg <= {point_flag,7'd100_0000};//9
			
			4'd10: seg <= 8'b1011_1111;//-
			4'd11: seg <= 8'b1111_1111;//熄灭
/*			
			4'd10: seg <= {point_flag,7'd100_0000};//A
			4'd11: seg <= {point_flag,7'd100_0000};//b
			4'd12 : seg <= {point_flag,7'd100_0000};//C
			4'd13 : seg <= {point_flag,7'd100_0000};//d
			4'd14 : seg <= {point_flag,7'd100_0000};//E
			4'd15 : seg <= {point_flag,7'd100_0000};//F
*/
			default : seg <= 8'd1100_0000;
		endcase
end

always@(posedge clk,negedge rst_n)
begin
	if(rst_n == 0)		
		sel <= 3'd0;//0			
	else
		sel <= sel_reg;
end

er_bcd er_bcd_inst(

	.clk	(clk	),
	.rst_n(rst_n),
	.data	(data	),//数据10进制
	
	.data1(data1),
	.data2(data2),
	.data3(data3),
	.data4(data4), 
	.data5(data5),
	.data6(data6) 		 	

);	
		



endmodule

数据解析模块

module er_bcd(

	input 				clk		,
	input					rst_n		,
	input	[19:0]		data		,//数据10进制
	
	output reg[3:0]	data1		,//bcd码
	output reg[3:0]	data2		,//bcd码
	output reg[3:0]	data3		,//bcd码
	output reg[3:0]	data4		,//bcd码 
	output reg[3:0]	data5		,//bcd码
	output reg[3:0]	data6		 //bcd码	

);

reg [4 :0]cnt_shift	;
reg [43:0]data_shift	;//暂存转换后的BCD码
reg 		 shift_flag	;

always@(posedge clk, negedge rst_n)//记时钟21次后清零,大约20ns*20=400ns进行一次数据转码并输出
begin
	if(rst_n == 0)
		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 + 5'd1;
			else
				cnt_shift <= cnt_shift;
end

always@(posedge clk, negedge rst_n)
begin
	if(rst_n == 0)
		data_shift <= 43'd0;
	else
		if(cnt_shift == 5'd0)
			data_shift <= {24'd0,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]);//大四加三
				end
			else
				if((cnt_shift <= 20)&&(shift_flag ==  1'b1))
					data_shift <= data_shift << 1;
				else
					data_shift <= data_shift;
end

always@(posedge clk, negedge rst_n)//相对于时钟信号,0时数据计算,1时进行数据移位
begin
	if(rst_n == 0)
		shift_flag <= 1'b0;
	else
		shift_flag = ~shift_flag;
end

always@(posedge clk, negedge rst_n)
begin
	if(rst_n == 0)
		begin
			data1   <=  4'b0;
		   data2   <=  4'b0;
		   data3   <=  4'b0;
		   data4   <=  4'b0;
		   data5   <=  4'b0;
		   data6   <=  4'b0;
		end
	else	if(cnt_shift == 5'd21)
		begin
			data1   <=  data_shift[23:20];//分段传递
		   data2   <=  data_shift[27:24];//分段传递
		   data3   <=  data_shift[31:28];//分段传递
		   data4   <=  data_shift[35:32];//分段传递
		   data5   <=  data_shift[39:36];//分段传递
		   data6   <=  data_shift[43:40];//分段传递
		end
end

endmodule

仿真代码

`timescale 1ns/1ps
module shu_ma_g_MAX_tb;
	
	reg 			clk	;
	reg 			rst_n	;
	reg[19:0]	data	;//数据10进制
	reg[ 5:0]	point	;//小数点位
	reg			signe	;//正负号位
	reg			seg_en	;//数码管使能
	
	wire [7:0]	seg	;
	wire [2:0]	sel	;

shu_ma_g_MAX shu_ma_g_MAX(

	.clk		(clk		),
	.rst_n	(rst_n	),
	.data		(data		),//数据10进制
	.point	(point	),//小数点位
	.signe	(signe	),//正负号位
	.seg_en	(seg_en	),//数码管使能
   
	.sel		(sel		),
	.seg 		(seg 		)

);

initial clk =1;
always #10 clk = ~clk;

initial begin
	rst_n = 0;
	#20
	rst_n = 1;
	seg_en = 1'b1;
	#100
	data = 0;
	#490
	data = 20'd98789;
	point = 6'b001000;
	signe = 1'b1;	//-98.789
	#20000
	data = 20'd1111;
	point = 6'b000100;
	#20000
	$stop;
end

endmodule

三、仿真验证

运行仿真,直接调出中间数据进行分析

这里可以看出,在数据未完全解析时,数码管每个位的数据为高阻态,在解析完成后同时赋值给数码管对应段。

下面对其数据显示正确性进行检测:截出一段数据进行分析。

10,9,8,7,8,9对应数据-98789,输入数据应为-98.789。789三位输出相同(懒得改)前面三位分别是-,9,8.,8于8.不同在于最高位的1与0,即01000000表示8.,-为b1011_1111,由于数据的位扫描是按照低位到高位:11000000(9)11000000(8)11000000(7)01000000(8.)11000000(9)1011_1111(-),对应输出显示正确。

参考资料

数码管显示进阶

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

小梅哥 xilinx fpga VGA

module VGA_CTRL(Clk,Reset_n,Data,Data_Req,VGA_HS, //行VGA_VS, //场VGA_BLK, //数据有效的那一段VGA_RGB );input Clk;input Reset_n;input [23:0]Data;output reg Data_Req;output reg VGA_HS;output reg VGA_VS; output reg VGA_BLK;output reg [23:0]VGA_RGB;//{R[7:0]、…

Android常见界面控件(三)

目录 前言 列表控件ListView 常用属性 常用适配器 1.BaseAdapter 2.SimpleAdapter 3.ArrayAdapter 购物商城 选择菜品照片 创建布局文件 实现购物商城列表界面的显示效果 前言 在前面&#xff0c;我们已经讲了六个常用的界面控件和五个界面布局&#xff0c;那么本篇…

【HarmonyOS NEXT星河版开发实战】灯泡定时开关

个人主页→VON 收录专栏→鸿蒙综合案例开发​​​​​ 代码及其图片资源会发布于gitee上面&#xff08;已发布&#xff09; 所有与鸿蒙开发有关的知识点都会在gitee上面进行发布 gitee地址https://gitee.com/wang-xin-jie234 目录 前言 界面功能介绍 界面构建思路 头部 中间…

数据结构——二叉树经典OJ题

1.单值二叉树 单值二叉树&#xff1a;就是判断二叉树里的所有值是否都一样 bool isUnivalTree(struct TreeNode* root) {if(rootNULL)return true;//查找有没有左子树并且看左子树当前指向的值是否和根当前指向的值相等if(root -> left && root -> left -> v…

【三维室内数据集】ScanNet v2使用说明

【版权声明】本文为博主原创文章&#xff0c;未经博主允许严禁转载&#xff0c;我们会定期进行侵权检索。 参考书籍&#xff1a;《人工智能点云处理及深度学习算法》 本文为专栏《Python三维点云实战宝典》系列文章&#xff0c;专栏介绍地址“【python三维深度学习】python…

Python自动化:图片批量添加水印

前言 本文将讲述怎样通过Python自动化的方法&#xff0c;来对照片进行批量的加水印&#xff0c;从而能够有效地阻止他人的非法占有&#xff0c;提高工作的效率。 Python自动化&#xff1a;办公效率的革命 自动化解决方案 实现步骤 读取指定文件夹中的图片&#xff1a;打开…

YOLOv9改进策略【卷积层】| 利用MobileNetv4中的UIB、ExtraDW优化RepNCSPELAN4

一、本文介绍 本文记录的是利用ExtraDW优化YOLOv9中的RepNCSPELAN4&#xff0c;详细说明了优化原因&#xff0c;注意事项等。ExtraDW是MobileNetv4模型中提出的新模块&#xff0c;允许以低成本增加网络深度和感受野&#xff0c;具有ConvNext和IB的组合优势。可以在提高模型精度…

redis | 认识非关系型数据库Redis的哈希数据类型

Redis 非关 kv型 哈希通用命令python 操作hash应用场景 数据类型 数据类型丰富&#xff0c;字符串strings,散列hashes,列表lists&#xff0c;集合sets,有序集合sorted sets等等 哈希 定义 1、由field和关联的value组成的键值对 类似于python的键值对 2、field和value.是字符…

『功能项目』新输入系统【07】

我们打开上一篇06新输入系统项目&#xff0c; 本章要做的事情是摄像机跟随主角移动&#xff0c; 给主角增加一个Player标签方便主摄像机查找主角对象 在编辑场景调好角度&#xff0c;选择Main Camera对象按键盘Ctrl Shift F使运行场景与编辑场景相同 新建CameraCtrl脚本代码 …

秋招突击——8/16——字节广告业务——面经整理——二面挂

文章目录 引言一面面试内容基础知识一、Redis为什么进行AOF重写&#xff1f;二、AQS和Conditon的使用三、乐观锁和分布式锁有什么差异&#xff1f;频繁使用乐观锁行不行&#xff1f;四、Java的即时编译技术五、Java中的JVM调优是如何做的&#xff1f;六、Java中创建对象的流程&…

STM32——BKP备份寄存器RTC实时时钟

首先是理论知识Unix时间戳&#xff1a; 时间戳只显示秒&#xff0c;没有进位&#xff0c;永不进位的秒计数器&#xff0c;60秒就是60秒&#xff0c;100秒就是100秒&#xff0c;它可以和年月日/时分秒进行转换 优点&#xff1a;1、简化硬件电路&#xff08;只需要考虑秒的容量…

C语言 猜数字游戏

目录 1. 随机数⽣成 1.1 rand 1.2 srand 1.3 time 1.4 设置随机数的范围 2. 猜数字游戏实现 游戏要求&#xff1a; 1. 电脑⾃动⽣成1~100的随机数 2. 玩家猜数字&#xff0c;猜数字的过程中&#xff0c;根据猜测数据的⼤⼩给出⼤了或⼩了的反馈&#xff0c;直到猜对&a…

运行微信小程序报错:Bad attr data-event-opts with message

问题 使用uniapp 编译&#xff0c;运行微信小程序环境时&#xff0c;报错 Bad attr data-event-opts with message。&#xff08;这个错误报错原因很多&#xff0c;这里只解决一个&#xff09; 原因 原因是&#xff1a;代码中有&#xff1a; :key"swiperList i"…

猫头虎分享:Python库 Pip 的简介、安装、用法详解入门教程

猫头虎分享&#xff1a;Python库 Pip 的简介、安装、用法详解入门教程 &#x1f3af; 大家好&#xff01;今天猫头虎带您一起探索Python世界中的一个基础工具——Pip。作为一名Python开发者&#xff0c;掌握Pip的使用不仅能帮助你更有效地管理项目中的依赖&#xff0c;还能让你…

【Java】Spring Boot使用 Email 传邮件 (上手图解)

Java系列文章目录 补充内容 Windows通过SSH连接Linux 第一章 Linux基本命令的学习与Linux历史 文章目录 Java系列文章目录一、前言二、学习内容&#xff1a;三、问题描述四、解决方案&#xff1a;4.1 认识依赖4.2 发送邮件步骤4.2.1 先获取授权码4.2.1 邮件配置4.2.2 主体内容…

使用 jar-analyzer 和dbeaver 分析java

https://github.com/jar-analyzer/jar-analyzer 可以进行jar分析&#xff0c;包括method调用 分析完可以通过界面进行一些分析&#xff0c;如果复杂还可以用DbWeaver 打开数据库进行分析

Java SpringBoot+Vue实战教程:如何搭建高中素质评价档案系统?

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

【通俗易懂】限流、降级、熔断有什么区别?

目录 一、限流 1.1 简介 1.2 限流算法 二、降级 2.1 简介 2.2 降级的方式 延迟服务 在粒度范围内关闭服务&#xff08;片段降级或服务功能降级&#xff09; 页面异步请求降级 写降级 读降级 2.3 降级的介入方式 自动开关降级 服务超时 失败次数 发生故障 限流…

Markdown 美化 Github 个人主页

注&#xff1a;本文参考这篇博客 http://t.csdnimg.cn/KXhSw 目录 1 效果展示2 创建仓库3 编写 Markdown3.1 动态波浪图3.2 打字机动图3.3 技术栈图标3.4 项目贡献统计3.5 连续贡献统计3.6 贡献统计图3.7 代码时长统计3.8 仓库代码占比 1 效果展示 先来看看效果&#xff1a; 动…

java整合DL645-2007与Dl645-1997

注意事项: 前导字节-一般在传输帧信息前,都要有0~4个FE不等,所以这里要注意,对于主站来说,直接发送4个FE作为前导字节即可。而从站回复,就不一定了,根据厂家不同而不同,有些没有FE的,也有4个FE的,所以对于接受程序,一定要慎重传输次序-所有的数据项都是先传低字节,…