数码管动态显示

文章目录

  • 前言
  • 一、数码管驱动
  • 二、数码管原理图
  • 三、实验任务
    • 3.1 任务描述
    • 3.2 系统框图
    • 3.3 模块原理图
    • 3.4 模块代码
    • 3.5 测试代码
    • 3.6 功能仿真
  • 四、引脚分配
  • 五、运行效果
  • 总结


前言

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


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

一、数码管驱动

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

数码管动态显示_第1张图片

图1. 数码管静态显示
数码管动态显示_第2张图片

图2. 数码管动态显示

二、数码管原理图

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

数码管动态显示_第3张图片

图3. 数码管原理图

三、实验任务

3.1 任务描述

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

图4. 模块关系示意图

3.2 系统框图

数码管动态显示_第5张图片

图5. 系统框图

3.3 模块原理图

数码管动态显示_第6张图片

图6. 模块原理图

3.4 模块代码

  1. 创建time_count文件,并编写 time_count模块代码。
module time_count(
	input 	clk,//时钟频率,50MHz
	input	rst_n,//复位信号,下降沿有效
	
	output reg	flag//一个时钟周期的脉冲信号 	

);

parameter 	MAX_NUM = 25'd25_000_000;//0.5s时钟
reg [24:0]	cnt							;//时钟计数器

//计时器对时钟计数,每0.5s输出一个时钟周期脉冲信号
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin//按下复位信号时
		cnt <= 25'd0;//计数器设置位0
		flag <= 1'b0;//周期脉冲信号设置位0
	end 
	else if(cnt == MAX_NUM - 1'd1)begin//如果时间到
		cnt <= 25'd0;//计数器清零
		flag <= 1'b1;//周期脉冲信号输出为1,表示记慢一个周期
	end 
	else begin//如果时间没有到
		cnt <= cnt + 1'd1;//计数器不停计数
		flag <= 1'b0;//周期脉冲信号不变
	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张图片

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

四、引脚分配

数码管动态显示_第8张图片

图1. pin planner
元件 管脚
SEL0 A4
SEL1 B4
SEL2 A3
SEL3 B3
SEL4 A2
SEL5 B1
DIG0 B7
DIG1 A8
DIG2 A6
DIG3 B5
DIG4 B6
DIG5 A7
DIG6 B8
DIG7 A5
CLOCK(时钟) E1
KEY1 E15
表1. 引脚信息表

五、运行效果

数码管动态显示


总结

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

你可能感兴趣的:(FPGA学习,单片机,fpga开发,verilog,fpga,硬件工程)