数码管进阶设计验证

2024-08-25 02:44
文章标签 进阶 设计 验证 数码管

本文主要是介绍数码管进阶设计验证,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

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

        近年来,随着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)//判断符号位
beginif(rst_n == 0)data_reg <= 24'b0;elseif((data6)||(point[5]))data_reg <= {data6,data5,data4,data3,data2,data1};elseif(((data5)||(point[4]))&&(signe == 1'b1))//最高位为符号位011-111data_reg <= {4'd10,data5,data4,data3,data2,data1};elseif(((data5)||(point[4]))&&(signe == 1'b0))data_reg <= {4'd11,data5,data4,data3,data2,data1};elseif(((data4)||(point[3]))&&(signe == 1'b1))//次高位为符号位001-111data_reg <= {4'd11,4'd10,data4,data3,data2,data1};elseif(((data4)||(point[3]))&&(signe == 1'b0))data_reg <= {4'd11,4'd11,data4,data3,data2,data1};elseif(((data3)||(point[2]))&&(signe == 1'b1))//次次高位为符号位000-111data_reg <= {4'd11,4'd11,4'd10,data3,data2,data1};elseif(((data3)||(point[2]))&&(signe == 1'b0))data_reg <= {4'd11,4'd11,4'd11,data3,data2,data1};elseif(((data2)||(point[1]))&&(signe == 1'b1))//次次次高位为符号位000-011data_reg <= {4'd11,4'd11,4'd11,4'd10,data2,data1};elseif(((data2)||(point[1]))&&(signe == 1'b0))data_reg <= {4'd11,4'd11,4'd11,4'd11,data2,data1};elseif(((data1)||(point[0]))&&(signe == 1'b1))//次次次次高位为符号位000-001data_reg <= {4'd11,4'd11,4'd11,4'd11,4'd10,data1};elsedata_reg <= {4'd11,4'd11,4'd11,4'd11,4'd11,data1};endalways@(posedge clk,negedge rst_n)	//计数器驱动模块
beginif(rst_n == 0)cnt_1ms <= 16'd0;elseif(cnt_1ms == cnt_1ms_max)cnt_1ms <= 16'd0;elsecnt_1ms <= cnt_1ms + 16'd1;endalways@(posedge clk,negedge rst_n)//1ms标志信号
beginif(rst_n == 0)cnt_1ms_flag <= 1'b0;elseif(cnt_1ms == cnt_1ms_max)cnt_1ms_flag <= 1'b1;elsecnt_1ms_flag <= 1'b0;
endalways@(posedge clk,negedge rst_n)//扫描周期计数器使能
beginif(rst_n == 0)cnt_sel <= 3'd0;elseif((cnt_sel == 3'd5)&&(cnt_1ms_flag <= 1'b1))cnt_sel <= 3'd0;elseif(cnt_1ms_flag <= 1'b1)cnt_sel <= cnt_sel + 3'd1;elsecnt_sel <= cnt_sel;
endalways@(posedge clk,negedge rst_n)//暂存输出
beginif(rst_n == 0)sel_reg <= 3'd0;elseif((cnt_sel == 3'd0)&&(cnt_1ms_flag <= 1'b1))sel_reg <= 3'd0;elseif(cnt_1ms_flag <= 1'b1)sel_reg <= sel_reg + 1'd1;elsesel_reg <= sel_reg;
endalways@(posedge clk,negedge rst_n)//段码数据传递
beginif(rst_n == 0)data_zhan <= 4'd0;elseif((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;endcaseelsedata_zhan <= data_zhan;
endalways@(posedge clk,negedge rst_n)//小数点点亮
beginif(rst_n == 0)point_flag <= 1'b0;elseif(cnt_1ms_flag <= 1'b1)point_flag <= ~point[cnt_sel];elsepoint_flag <= point_flag;
endalways@(posedge clk,negedge rst_n)//段码数值判断并输出
beginif(rst_n == 0)		seg <= 8'b1111_1111;//0elsecase(data_zhan)4'd0 : seg <= {point_flag,7'd100_0000};//04'd1 : seg <= {point_flag,7'd100_0000};//14'd2 : seg <= {point_flag,7'd100_0000};//24'd3 : seg <= {point_flag,7'd100_0000};//34'd4 : seg <= {point_flag,7'd100_0000};//44'd5 : seg <= {point_flag,7'd100_0000};//54'd6 : seg <= {point_flag,7'd100_0000};//64'd7 : seg <= {point_flag,7'd100_0000};//74'd8 : seg <= {point_flag,7'd100_0000};//84'd9 : seg <= {point_flag,7'd100_0000};//94'd10: seg <= 8'b1011_1111;//-4'd11: seg <= 8'b1111_1111;//熄灭
/*			4'd10: seg <= {point_flag,7'd100_0000};//A4'd11: seg <= {point_flag,7'd100_0000};//b4'd12 : seg <= {point_flag,7'd100_0000};//C4'd13 : seg <= {point_flag,7'd100_0000};//d4'd14 : seg <= {point_flag,7'd100_0000};//E4'd15 : seg <= {point_flag,7'd100_0000};//F
*/default : seg <= 8'd1100_0000;endcase
endalways@(posedge clk,negedge rst_n)
beginif(rst_n == 0)		sel <= 3'd0;//0			elsesel <= sel_reg;
ender_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进行一次数据转码并输出
beginif(rst_n == 0)cnt_shift <= 5'd0;elseif((cnt_shift == 5'd21)&&(shift_flag == 1'b1))//计数清零cnt_shift <= 5'd0;elseif(shift_flag == 1'b1)cnt_shift <= cnt_shift + 5'd1;elsecnt_shift <= cnt_shift;
endalways@(posedge clk, negedge rst_n)
beginif(rst_n == 0)data_shift <= 43'd0;elseif(cnt_shift == 5'd0)data_shift <= {24'd0,data};elseif((cnt_shift <= 20)&&(shift_flag ==  1'b0))begindata_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]);//大四加三endelseif((cnt_shift <= 20)&&(shift_flag ==  1'b1))data_shift <= data_shift << 1;elsedata_shift <= data_shift;
endalways@(posedge clk, negedge rst_n)//相对于时钟信号,0时数据计算,1时进行数据移位
beginif(rst_n == 0)shift_flag <= 1'b0;elseshift_flag = ~shift_flag;
endalways@(posedge clk, negedge rst_n)
beginif(rst_n == 0)begindata1   <=  4'b0;data2   <=  4'b0;data3   <=  4'b0;data4   <=  4'b0;data5   <=  4'b0;data6   <=  4'b0;endelse	if(cnt_shift == 5'd21)begindata1   <=  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
endendmodule

仿真代码

`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 beginrst_n = 0;#20rst_n = 1;seg_en = 1'b1;#100data = 0;#490data = 20'd98789;point = 6'b001000;signe = 1'b1;	//-98.789#20000data = 20'd1111;point = 6'b000100;#20000$stop;
endendmodule

三、仿真验证

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

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

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

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.chinasem.cn/article/1104322

相关文章

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

[MySQL表的增删改查-进阶]

🌈个人主页:努力学编程’ ⛅个人推荐: c语言从初阶到进阶 JavaEE详解 数据结构 ⚡学好数据结构,刷题刻不容缓:点击一起刷题 🌙心灵鸡汤:总有人要赢,为什么不能是我呢 💻💻💻数据库约束 🔭🔭🔭约束类型 not null: 指示某列不能存储 NULL 值unique: 保证某列的每行必须有唯一的值default: 规定没有给列赋值时的默认值.primary key:

怎么让1台电脑共享给7人同时流畅设计

在当今的创意设计与数字内容生产领域,图形工作站以其强大的计算能力、专业的图形处理能力和稳定的系统性能,成为了众多设计师、动画师、视频编辑师等创意工作者的必备工具。 设计团队面临资源有限,比如只有一台高性能电脑时,如何高效地让七人同时流畅地进行设计工作,便成为了一个亟待解决的问题。 一、硬件升级与配置 1.高性能处理器(CPU):选择多核、高线程的处理器,例如Intel的至强系列或AMD的Ry

【Linux 从基础到进阶】Ansible自动化运维工具使用

Ansible自动化运维工具使用 Ansible 是一款开源的自动化运维工具,采用无代理架构(agentless),基于 SSH 连接进行管理,具有简单易用、灵活强大、可扩展性高等特点。它广泛用于服务器管理、应用部署、配置管理等任务。本文将介绍 Ansible 的安装、基本使用方法及一些实际运维场景中的应用,旨在帮助运维人员快速上手并熟练运用 Ansible。 1. Ansible的核心概念

Flutter 进阶:绘制加载动画

绘制加载动画:由小圆组成的大圆 1. 定义 LoadingScreen 类2. 实现 _LoadingScreenState 类3. 定义 LoadingPainter 类4. 总结 实现加载动画 我们需要定义两个类:LoadingScreen 和 LoadingPainter。LoadingScreen 负责控制动画的状态,而 LoadingPainter 则负责绘制动画。

基于51单片机的自动转向修复系统的设计与实现

文章目录 前言资料获取设计介绍功能介绍设计清单具体实现截图参考文献设计获取 前言 💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们电子相关专业的大学生,希望您们都共创辉煌!✌💗 👇🏻 精彩专栏 推荐订阅👇🏻 单片机

C++ | Leetcode C++题解之第393题UTF-8编码验证

题目: 题解: class Solution {public:static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num &