数码管显示(静态与动态)

文章目录

  • 一、数码管简介
  • 二、数码管连接方式
    • 2.1 共阴极
    • 2.2 共阳极
    • 2.3 数码管真值表
  • 三、数码管驱动方式
    • 3.1 静态显示
    • 3.2 动态显示
    • 四、Cyclone IV数码管原理图
  • 五、模块代码
  • 六、引脚分配
  • 七、动态显示
  • 八、引脚分配


一、数码管简介

数码管分七段数码管和八段数码管。七段和八段的区别在于,是否包括小数点DP(Digital Point)。本实验中使用的是数码管是8段数码管,每段是由led组成。通过控制每段led的亮灭,来控制数码管显示不同的数字和字母。
数码管显示(静态与动态)_第1张图片

二、数码管连接方式

数码管显示(静态与动态)_第2张图片

2.1 共阴极

,a—dp为输入端,全部在二极管的正极,二极管的负极共同接地。只有当a—dp输入为高电平的时候,二极管才导通,然后对应的段发亮。

2.2 共阳极

所示,a—dp为输入端,全部在二极管的负极,二极管的正极极共同接+5v(高电平)。只有当a—dp输入为低电平的时候,二极管才导通,然后对应的段发亮。

2.3 数码管真值表

要显示不同的数字或者字母,就要选择点亮对应的led段。图5中对应的是cyclone IV开发板上数码管的真值表,可以通过查找该表来显示我们想要的数字或者字母。

数码管显示(静态与动态)_第3张图片

三、数码管驱动方式

3.1 静态显示

在静态显示中,只考虑段选信号。在不同的时刻,各个位选信号保持不变,并根据真值表,选择要显示的数字或者字母。

3.2 动态显示

在动态显示中,需要将位选信号考虑进来。在不同的时刻,各个位的位选信号随时改变,并根据真值表,选择显示不同的数字或者字母。

四、Cyclone IV数码管原理图

Cyclone IV开发板中的数码管是共阳极,所以数码管中需要给低电平,对应的led段才会亮。位选信号原理图如图8所示,位选信号也是需要低电平有效。
数码管显示(静态与动态)_第4张图片

五、模块代码

创建time_count文件,并编写 time_count模块代码。

module time_count(
	input	     clk  ,//50MHz时钟信号
	input		 rst_n,//复位信号
	output	reg  flag//一个时钟周期的脉冲信号
);
parameter	 MAX_NUM = 25'd25_000_000;//计数器最大计数值
reg  [24:0]	 cnt                     ; //时钟分频计数器

//计数器对时钟计数,每0.5s,输出一个时钟周期脉冲信号
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin//按复位时
		flag <= 1'b0;//信号为0
		cnt <= 25'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 <= 25'd0;
	end
end
endmodule 

创建seg_led_static文件,并编写 seg_led_static模块代码。

module	seg_led_static(
	input		      clk     ,
	input		      rst_n   ,
	input		      flag    ,
	output	reg [5:0] sel     ,//数码管位选信号
	output	reg [7:0] seg  //数码管段选信号
);
reg [3:0]	num;//数码管显示十六进制数
//控制数码管位选信号(注:低电平有效),选中所有的数码管
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)//如果按复位键0
		sel <= 6'b111111;//则默认为高电平
	else 
		sel <= 6'b000000;//否则为低电平
end
//每次通知信号flag到达时,数码管计数加1
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)
		num <=	4'h0;
	else if(flag)begin
		if(num < 4'hf)
			num <= num + 1'h1;
		else 
			num <= 4'h0;
	end
	else begin
		num <= num;
	end
end
//根据数码管显示的数值,控制段选信号
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)
		seg <= 8'b0;
	else begin
		case(num)//匹配16进制数
			4'h0:    seg <= 8'b1100_0000;//匹配到后参考共阳极真值表
	        4'h1:    seg <= 8'b1111_1001;
	        4'h2:    seg <= 8'b1010_0100;
	        4'h3:    seg <= 8'b1011_0000;
	        4'h4:    seg <= 8'b1001_1001;
	        4'h5:    seg <= 8'b1001_0010;
	        4'h6:    seg <= 8'b1000_0010;
	        4'h7:    seg <= 8'b1111_1000;
	        4'h8:    seg <= 8'b1000_0000;
	        4'h9:    seg <= 8'b1001_0000;
	        4'ha:    seg <= 8'b1000_1000;
	        4'hb:    seg <= 8'b1000_0011;
	        4'hc:    seg <= 8'b1100_0110;
	        4'hd:    seg <= 8'b1010_0001;
	        4'he:    seg <= 8'b1000_0110;
	        4'hf:     seg <= 8'b1000_1110;
	      	default : seg <= 8'b1100_0000;
		endcase
	end
end
endmodule 

创建top_seg_led_static文件,并编写top_seg_led_static模块代码:

module  top_seg_led_static(
	input	 	         clk  ,//50MHz系统时钟
	input		         rst_n,//系统复位信号(低有效)
	output		[5:0]	 sel  ,//数码管位选
	output	    [7:0]	 seg//数码管段选
);
 
parameter	MAX_NUM = 25'd25_000_000;// 数码管变化的时间间隔0.5s
wire		add_flag				;// 数码管变化的通知信号
//每隔0.5s产生一个时钟周期的脉冲信号
time_count #(.MAX_NUM(MAX_NUM)) u_time_count(
	.clk		(clk)  ,//50MHz时钟信号
	.rst_n		(rst_n),//复位信号
	.flag		(add_flag)//一个时钟周期的脉冲信号
);
//每当脉冲信号到达时,使数码管显示的数值加1
seg_led_static u_seg_led_static(
	.clk		(clk)	  ,
	.rst_n		(rst_n)	  ,
	.flag	    (add_flag),
	.sel		(sel)	  ,
	.seg		(seg)
);
endmodule 

六、引脚分配

数码管显示(静态与动态)_第5张图片

七、动态显示

计数器模块

module counter(
	input wire 		  clk  ,//时钟
	input wire 		  rst_n,//复位信号
	
	output reg [4:0] hour  ,//小时
	output reg [5:0] min   ,//分钟
	output reg [5:0] sec//秒
	
);

parameter MAX_NUM = 26'd49_999_999;//1s
parameter TOTAL_SEC = 17'd86399   ;//24x60x60s
reg [25:0] cnt_sec ;//秒计数器
reg [16:0] cnt_time;//计时器

//计时1s秒钟模块
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		cnt_sec <= 26'd0;
	end 
	else if(cnt_sec == MAX_NUM)begin
		cnt_sec <= 26'd0;
	end 
	else begin
		cnt_sec <= cnt_sec + 1'd1;
	end 
end 

//时间模块
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		cnt_time <= 17'd0;
	end 
	else if(cnt_time == TOTAL_SEC && cnt_sec == MAX_NUM)begin
		cnt_time <= 17'd0;
	end 
	else if(cnt_sec == MAX_NUM)begin
		cnt_time <= cnt_time + 1'd1;
	end 
	else begin
		cnt_time <= cnt_time;
	end 
end 

//取出时分秒模块
always@(*)begin
	hour = cnt_time / 12'd3600          ;//小时
	min  = (cnt_time % 12'd3600) / 6'd60;//分钟
	sec  = (cnt_time % 12'd3600) % 6'd60;//秒
end 
endmodule 

数码管驱动模块

module seg_driver(
	input wire 			clk	 ,//时钟
	input wire 			rst_n,//复位信号
	input wire [4:0] 	hour ,//小时
	input wire [5:0] 	min	 ,//分钟
	input wire [5:0] 	sec	 ,//秒
	
	output reg [5:0]	seg_sel,
	output reg [7:0] 	seg_ment
);

parameter CNT_20US = 10'd999;//20微秒
wire [3:0] 	sec_low  ;//秒的低位
wire [2:0] 	sec_high ;//秒的高位
wire [3:0] 	min_low  ;//分钟的低位
wire [2:0] 	min_high ;//分钟的高位
wire [1:0] 	hour_low ;//小时的低位
wire [1:0] 	hour_high;//小时的高位
reg  [9:0]	cnt		 ;//计数器,计20us时间
reg  [3:0] 	number	 ;//显示时分秒寄存器

//计时模块
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		cnt <= 10'd0; 	
	end 
	else if(cnt == CNT_20US)begin
		cnt <= 10'd0;
	end 
	else begin
		cnt <= cnt + 1'd1;
	end 
end 

//位选信号切换模块
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		seg_sel <= 6'b011111;//初始化第一个数码管亮
	end 
	else if(cnt == CNT_20US)begin
		seg_sel <= {seg_sel[0],seg_sel[5:1]};//每隔20us进行位移操作
	end 
	else begin
		seg_sel <= seg_sel;//其他时间保持不变
	end 
end 

//位选信号译码模块
always@(*)begin
	case(seg_sel)
		6'b011111: number = sec_low  ;//秒的低位给第一个数码管显示
		6'b101111: number = sec_high ;//秒的高位给第二个数码管显示
		6'b110111: number = min_low  ;//分钟的低位给第三个数码管显示
		6'b111011: number = min_high ;//分钟的高位给第四个数码管显示
		6'b111101: number = hour_low ;//小时的低位给第五个数码管显示
		6'b111110: number = hour_high;//小时的高位给第六个数码管显示
		default:   number = sec_low  ;
	endcase 
end 

//段选信号译码模块
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		seg_ment <= 8'b1100_0000;//初始化显示0
	end
	else begin
		case(number)
			4'd0:		seg_ment <= 8'b1100_0000;//数码管显示0
			4'd1:		seg_ment <= 8'b1111_1001;//数码管显示1
			4'd2: 		seg_ment <= 8'b1010_0100;//数码管显示2
			4'd3: 		seg_ment <= 8'b1011_0000;//数码管显示3
			4'd4: 		seg_ment <= 8'b1001_1001;//数码管显示4
			4'd5: 		seg_ment <= 8'b1001_0010;//数码管显示5
			4'd6: 		seg_ment <= 8'b1000_0010;//数码管显示6
			4'd7: 		seg_ment <= 8'b1111_1000;//数码管显示7
			4'd8: 		seg_ment <= 8'b1000_0000;//数码管显示8
			4'd9:    	seg_ment <= 8'b1001_0000;//数码管显示9
			default:	seg_ment <= 8'b1100_0000;//数码管显示0
		endcase 
	end 
end 

assign sec_low   = sec % 4'd10 ;//秒的低位如59秒--->9
assign sec_high  = sec / 4'd10 ;//秒的高位如59秒--->5
assign min_low   = min % 4'd10 ;//分钟的低位如59--->9
assign min_high  = min / 4'd10 ;//分钟的高位如59--->5
assign hour_low  = hour % 4'd10;//小时的低位如23--->3
assign hour_high = hour / 4'd10;//小时的高位如23--->2
endmodule 

顶层模块

module digital_clock(
	input wire 			clk  ,//时钟
	input wire 			rst_n,//复位信号
	
	output wire [5:0] seg_sel,//数码管位选信号
	output wire [7:0] seg_ment//数码管段选信号

);
parameter MAX_NUM = 26'd49_999_999;//1s
parameter TOTAL_SEC = 17'd86399   ;//60x24x24s
parameter CNT_20US = 10'd999     ;//20us
wire [4:0] 	hour;//小时
wire [5:0] 	min ;//分钟
wire [5:0] 	sec ;//秒	

//实例化计数器模块
counter#(.MAX_NUM(MAX_NUM),
		.TOTAL_SEC(TOTAL_SEC)) u_counter(
.clk  	(clk)  ,
.rst_n	(rst_n),
          
.hour 	(hour) ,
.min	(min)  ,
.sec	(sec)
	
);

//实例化数码管驱动模块
seg_driver#(.CNT_20US(CNT_20US)) u_seg_driver(
.clk	 	(clk)    ,
.rst_n		(rst_n)  ,
.hour	 	(hour)   ,
.min	 	(min)    ,
.sec	 	(sec)    ,
          
.seg_sel	(seg_sel),
.seg_ment	(seg_ment)
);

endmodule 

八、引脚分配

数码管显示(静态与动态)_第6张图片

你可能感兴趣的:(fpga,fpga开发)