数码管动态显示


前言

  上期课程中,我们学习了数码管,并通过代码实现了数码管静态显示。本期课程将延续上节课的内容,讲解数码管动态显示。


  提示:上节课已经学习了数码管,所以跳过数码管的讲解,直接从数码管驱动开始讲解。

一、数码管驱动

  由于段选信号共用,如图2所示,所以在同一时刻只能选择一个数码管,具体选择十位还是个位由位选信号决定。
  问:采用此种方式一次只能选择一种数码管,如何能够同时选择多种数码管?
  答:视觉暂留现象:物体快速移动时,在大脑中残留的影响会暂留一段时间。

在这里插入图片描述

图1. 数码管静态显示
在这里插入图片描述

图2. 数码管动态显示

二、数码管原理图

  原理图中除了数码管的段选信号,还有数码管位选信号。数码管位选和段选信号都是低电平有效。

在这里插入图片描述

图3. 数码管原理图

三、实验任务

3.1 任务描述

  通过使用6位数码管动态显示,实现一个计时器,每0.5秒变化一次,显示数字123456。模块设计如图4所示,一个顶层模块调用两个子模块,time_count是计时模块,sel_led_dynamic是数码管动态显示模块,top_sel_led_dynamic是顶层模块。
在这里插入图片描述

图4. 模块关系示意图

3.2 系统框图

在这里插入图片描述

图5. 系统框图

3.3 模块原理图

在这里插入图片描述

图6. 模块原理图

3.4 模块代码

  1. 创建time_count文件,并编写 time_count模块代码。
module time_count(
	input	     clk  ,//50MHz时钟信号
	input		 rst_n,//复位信号
	output	reg  flag//一个时钟周期的脉冲信号
);
parameter	 MAX_NUM = 26'd25_000_000;//计数器最大计数值
reg  [25:0]	 cnt                     ; //时钟分频计数器

//计数器对时钟计数,每0.5s,输出一个时钟周期脉冲信号
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin//按复位时
		flag <= 1'b0;//信号为0
		cnt <= 26'd0;//计数器清零
	end
	else if(cnt < MAX_NUM - 1'b1)begin//如果没到时间
		flag <= 1'b0;//信号为0
		cnt <= cnt + 1'b1;//计数器正常累计+1
	end
	else	begin //否则到时间
		flag <= 1'b1;//信号变为1
		cnt <= 26'd0;
	end
end
endmodule  
  1. 创建sel_led_dynamic文件,并编写 sel_led_dynamic模块代码。
module sel_led_dynamic(
	input 				clk  ,//时钟,50MHz
	input 				rst_n,//复位信号,下降沿有效
	input 				flag ,//周期信号
	
	output reg [5:0]	sel  ,//位选信号,六个数码管
	output reg [7:0]	seg  //段选信号,八段led

);

reg [2:0]	cstat ;//当前状态
reg [2:0]	nstat ;//下一个状态

//状态跳转
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin//下降沿有效
		cstat <= 3'd0;//当前状态置0
	end 
	else begin
		cstat <= nstat;//状态跳转
	end 
end 

//下一个状态判断(组合逻辑)
always@(*)begin

	case(cstat)
		3'd0:	if(flag)begin
					nstat = 3'd1;
				end 
				else begin
					nstat = 3'd0;
				end 
		3'd1: if(flag)begin
					nstat = 3'd2;
				end 
				else begin
					nstat = 3'd1;
				end 
		3'd2: if(flag)begin
					nstat = 3'd3;
				end 
				else begin
					nstat = 3'd2;
				end 
		3'd3: if(flag)begin
					nstat = 3'd4;
				end 
				else begin
					nstat = 3'd3;
				end 
		3'd4: if(flag)begin
					nstat = 3'd5;
				end 
				else begin
					nstat = 3'd4;
				end 
		3'd5: if(flag)begin
					nstat = 3'd0;
				end 
				else begin
					nstat = 3'd5;
				end 
	default:	nstat= 3'd1;
	endcase 
end 

reg [2:0] value;

//各个状态下的动作(可以组合也可以时序)
always@(*)begin
	if(!rst_n)begin
		value = 3'd0;
	end 
	else begin
		case(cstat)
			3'd0:   begin
							 sel = 6'b111_110;//选择最右边数码管。 sel低有效
							 value = 3'd1;
					end
			3'd1:   begin
							 sel = 6'b111_101;
							 value = 3'd2;
					end
			3'd2:   begin
							 sel = 6'b111_011;
							 value = 3'd3;
					end
			3'd3:   begin
							 sel = 6'b110_111;
							 value = 3'd4;
					end
			3'd4:   begin
							 sel = 6'b101_111;
							 value = 3'd5;
					end
			3'd5:   begin
							 sel = 6'b011_111;
							 value = 3'd6;
					end
		   default:		begin//默认就第1种情况
							 sel = 6'b111_110;
							 value = 3'd1;
					  	end
		endcase
	end 
end 

//数码管seg的输出
always@(*)begin
	if(!rst_n)begin
		 seg = 8'b00000000;
	end 
	else begin
		case(value)
			 3'd1:   seg = 8'b11111001;//根据数码管真值表查找
			 3'd2:   seg = 8'b10100100;
			 3'd3:   seg = 8'b10110000;
			 3'd4:   seg = 8'b10011001;
			 3'd5:   seg = 8'b10010010;
			 3'd6:   seg = 8'b10000010;
			 default :   seg = 8'b00000000;
		endcase
	end 
end 

endmodule 
  1. 创建top_sel_led_dynamic文件,并编写 top_sel_led_dynamic模块代码。
module top_sel_led_dynamic(
	input 			clk  ,//时钟信号,50MHz
	input 			rst_n,//复位信号,下降沿有效
	
	output [5:0]	sel  ,//位选信号
	output [7:0]	seg   //段选信号
);
wire flag;//wire连接两个模块
parameter	MAX_NUM = 25'd25_000_000;
time_count #(.MAX_NUM(MAX_NUM))	u_time_count(//实例化计时器模块
.clk		(clk)  ,//时钟频率,50MHz
.rst_n		(rst_n),//复位信号,下降沿有效

.flag		(flag)  //一个时钟周期的脉冲信号 	

);

sel_led_dynamic	u_sel_led_dynamic(//实例化数码管动态显示模块
.clk  	(clk)  ,//时钟信号
.rst_n	(rst_n),//复位信号,下降沿有效
.flag 	(flag) ,//周期信号

.sel  	(sel)  ,//位选信号,六个数码管
.seg  	(seg)   //段选信号,八段led

);
	
endmodule

3.5 测试代码

  创建top_sel_led_dynamic_tb测试文件,并编写 top_sel_led_dynamic_tb测试模块代码。

`timescale 1ns/1ns//单位1ns/精度1ns
module top_sel_led_dynamic_tb();

reg 			clk  ;
reg 			rst_n;
wire [5:0]		sel  ;
wire [7:0]		seg  ;

parameter CYCLE = 5'd20   ;//20ns
parameter MAX_NUM = 7'd100;//计时100x20ns

always #(CYCLE/2) clk = ~clk;//10ns翻转时钟

initial begin
	clk = 1'b0			  ;//时钟置0
	rst_n = 1'b0		  ;//复位信号置0
	#(CYCLE)			  ;//延迟20ns
	rst_n = 1'b1		  ;//复位信号置1
	#(MAX_NUM * CYCLE * 6);//观看六个数码管的情况
	$stop				  ;//停止
end 
top_sel_led_dynamic	#(.MAX_NUM(MAX_NUM)) u_top_sel_led_dynamic(
.clk  	(clk)  ,//时钟信号,50MHz
.rst_n	(rst_n),//复位信号,下降沿有效

.sel  	(sel)  ,//位选信号
.seg   	(seg)//段选信号
);
endmodule 

3.6 功能仿真

  在功能仿真中,与数码管静态显示不同的地方就是sel位选信号不停改变。seg是段选信号,不同的段选信号对应1—6个数字。
在这里插入图片描述

图7. 数码管动态显示仿真

四、引脚分配

在这里插入图片描述

图1. pin planner
元件管脚
SEL0A4
SEL1B4
SEL2A3
SEL3B3
SEL4A2
SEL5B1
DIG0B7
DIG1A8
DIG2A6
DIG3B5
DIG4B6
DIG5A7
DIG6B8
DIG7A5
CLOCK(时钟)E1
KEY1E15
表1. 引脚信息表

五、运行效果

数码管动态显示


总结

  本期课程中,我们讲解了数码管动态显示的原理是改变数码管的位选信号。下期课程中将基于数码管动态显示,制作一个数字时钟。敬请期待!谢谢你的观看!

  • 6
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值