FPGA开发(六)数码管显示实验-计数器实现

        本次实验我们主要进行数码管的显示,包括单个数码管的显示和多个数码管刷新显示。

        在很多的实际中我们都会使用到数码管,在学习单片机的时候应该对数码管的基本原理有所了解,一个数码管有8个小LED组成,控制每一个LED的亮灭即可实现数码管显示不同的形状,这就是单个数码管显示数字的原理。多个数码管的显示有所不同,将每一个数码管所有的LED的负极连接在一起,只控制正极即可实现共阴级控制,同理实现共阳极控制。我们将多个共阳极数码管的所有对应的阴级连接到一起,对应的阳极单独控制,就实现了多个数码管的级联,多个数码管控制主要利用了视觉暂留,每一个时刻显示一个数码管,不断刷新就可以显示为多个数码管同时显示。

        本次博主使用的开发板上共有6个共阳极数码管,电路使用PNP管来进行反向驱动,具体的电路如下所示。

一、单个数码管的显示

        本次我们主要是实现单个数码管按秒显示0到9。      

        对于共阳极单个数码管,显示数字和字符编码如下。

         我们来分析一下这个程序,程序输入有时钟信号,复位信号,一个计时器计时一秒,当计数到9的时候归零,按照计数器的数字在数码管上显示不同的数字。因此我们需要两个always结构,一个进行计数,另一个进行数码管的显示。输出为8位驱动信号,因此我们写出以下的程序。

`timescale 1n/1ps
module seg_test(
	input clk,
	input rst,
	output seg_pi,
	output [7:0] seg_data
);
reg[31:0]time_cnt;
reg[7:0]num_cnt;
always@(posedge clk or negedge rst)
begin 
	if(rst==1'b0)
	begin
		time_cnt<=32'd0;
	end
	else if(time_cnt==32'd49_000_000)
	begin
		time_cnt<=0;
		if(num_cnt==8'd10)
		begin 
			num_cnt<=0;
		end
		else
		begin
			num_cnt<=num_cnt+1;
		end
	end
	else
	begin
		time_cnt<=time_cnt+32'd1;
	end
end
reg[7:0] seg_get_data;
always@(posedge clk)
begin 
	if(num_cnt==8'd0)
	begin
		seg_get_data<=8'b1100_0000;
	end
	else if(num_cnt==8'd1)
	begin
		seg_get_data<=8'b1111_1001;
	end
	else if(num_cnt==8'd2)
	begin
		seg_get_data<=8'b1010_0100;
	end
	else if(num_cnt==8'd3)
	begin
		seg_get_data<=8'b1011_0000;
	end
	else if(num_cnt==8'd4)
	begin
		seg_get_data<=8'b1001_1001;
	end
	else if(num_cnt==8'd5)
	begin
		seg_get_data<=8'b1001_0010;
	end
	else if(num_cnt==8'd6)
	begin
		seg_get_data<=8'b1000_0010;
	end
	else if(num_cnt==8'd7)
	begin
		seg_get_data<=8'b1111_1000;
	end
	else if(num_cnt==8'd8)
	begin
		seg_get_data<=8'b1000_0000;
	end
	else if(num_cnt==8'd9)
	begin
		seg_get_data<=8'b1001_0000;
	end
end
assign seg_data=seg_get_data;

endmodule

         下载程序后发现实现了我们要求的结果,程序运行结果如下。

        上述实验的工程下载地址: 

二、多位数码管显示 

        本次试验主要实现多位数码管实现一个计数器,每秒增加1。

        首先我们分析一下,多位数码管相对于单个数码管而言,多了一个数码管刷新频率,我们只需要新增加一个计数器,然后按照该计数器的计数值来对应控制我们某一位数码管即可。具体来说就是当该计数器为0,我们就接通第一个数码管,关闭其他数码管,同时将之前按秒计数的计数器的个位数值,通过数据总线输出,当该计数器为1时,我们接通第二个数码管,将按秒计数的计数器的十位数值,通过数据总线输出,以此类推完成整个按秒计数器的输出,当计数器到6时,我们不能直接清零,因为如果刷新频率过快,数码管会有重影,此时我们将所有的数码管同时接通,将所有数码管的数据位都输出为空,完成数码管的清零。此时就可以完成按秒计数器的计数值的显示。

        按照这个逻辑,我们写出程序如下所示,运行改程序可以看见,完成了我们需要的功能,实验结果如下图所示。

        

`timescale 1n/1ps
module seg_test(
	input clk,
	input rst,
	output [5:0]seg_pi,//片选
	output [7:0] seg_data//数据位
);
reg[31:0]time_cnt;//时间计数器,用作计数器的计时时钟 
reg[31:0]time_cnt2;//时间计数器2 用作刷新数码管的时钟
reg[31:0] all_num_cnt;//保存当前的计数 
reg[7:0] wei_cnt_clk;//判断输出哪一个数码管
always@(posedge clk or negedge rst)
begin 
	if(rst==1'b0)
	begin
		time_cnt<=32'd0;
	end
	else if(time_cnt==32'd49_000_000)//计时一秒  或者其他数值  49_999_999表示一秒
	begin
		time_cnt<=0;
		if(all_num_cnt==32'd999999)//时钟计数器 加到一定的值清零
		begin 
			all_num_cnt<=0;
		end
		else
		begin
			all_num_cnt<=all_num_cnt+1;
		end
	end
	else//时钟每秒加一
	begin
		time_cnt<=time_cnt+32'd1;
	end
end

//数码管刷新时间 计数
always@(posedge clk or negedge rst)
begin 
	if(rst==1'b0)
	begin
		time_cnt2<=32'd0;
	end
	else if(time_cnt2==32'd1_000)
	begin
		time_cnt2<=32'd0;
		if(wei_cnt_clk==8'd7)
		begin
			wei_cnt_clk<=0;
		end
		else
		begin
			wei_cnt_clk<=wei_cnt_clk+1;
		end
	end
	else
	begin
		time_cnt2<=time_cnt2+32'd1;
	end
end


reg[7:0] seg_get_data;//数码管编码后的显示  端选信号
reg[5:0] seg_pi_data;//片选信号
reg[7:0] seg_num;//数码管需要显示的数字 
//数码管显示
always@(posedge clk)
begin 	
	if(wei_cnt_clk==8'd0)//如果计时为0 刷新第一个数码管
	begin
		seg_pi_data<=6'b01_1111;//0代表点亮 选择第一个数码管
		seg_num<=all_num_cnt%10;//显示个位
		if(seg_num==8'd0)
		begin
			seg_get_data<=8'b1100_0000;//0的数码管编码
		end
		else if(seg_num==8'd1)
		begin
			seg_get_data<=8'b1111_1001;//1的编码
		end
		else if(seg_num==8'd2)
		begin
			seg_get_data<=8'b1010_0100;
		end
		else if(seg_num==8'd3)
		begin
			seg_get_data<=8'b1011_0000;
		end
		else if(seg_num==8'd4)
		begin
			seg_get_data<=8'b1001_1001;
		end
		else if(seg_num==8'd5)
		begin
			seg_get_data<=8'b1001_0010;
		end
		else if(seg_num==8'd6)
		begin
			seg_get_data<=8'b1000_0010;
		end
		else if(seg_num==8'd7)
		begin
			seg_get_data<=8'b1111_1000;
		end
		else if(seg_num==8'd8)
		begin
			seg_get_data<=8'b1000_0000;
		end
		else if(seg_num==8'd9)
		begin
			seg_get_data<=8'b1001_0000;
		end
	end
	else if(wei_cnt_clk==8'd1)
	begin
		seg_pi_data<=6'b10_1111;//0代表点亮
		seg_num<=all_num_cnt/10%10;
		if(seg_num==8'd0)
		begin
			seg_get_data<=8'b1100_0000;
		end
		else if(seg_num==8'd1)
		begin
			seg_get_data<=8'b1111_1001;
		end
		else if(seg_num==8'd2)
		begin
			seg_get_data<=8'b1010_0100;
		end
		else if(seg_num==8'd3)
		begin
			seg_get_data<=8'b1011_0000;
		end
		else if(seg_num==8'd4)
		begin
			seg_get_data<=8'b1001_1001;
		end
		else if(seg_num==8'd5)
		begin
			seg_get_data<=8'b1001_0010;
		end
		else if(seg_num==8'd6)
		begin
			seg_get_data<=8'b1000_0010;
		end
		else if(seg_num==8'd7)
		begin
			seg_get_data<=8'b1111_1000;
		end
		else if(seg_num==8'd8)
		begin
			seg_get_data<=8'b1000_0000;
		end
		else if(seg_num==8'd9)
		begin
			seg_get_data<=8'b1001_0000;
		end
	end
	
	else if(wei_cnt_clk==8'd2)
	begin
		seg_pi_data<=6'b11_0111;//0代表点亮
		seg_num<=all_num_cnt/100%10;
		if(seg_num==8'd0)
		begin
			seg_get_data<=8'b1100_0000;
		end
		else if(seg_num==8'd1)
		begin
			seg_get_data<=8'b1111_1001;
		end
		else if(seg_num==8'd2)
		begin
			seg_get_data<=8'b1010_0100;
		end
		else if(seg_num==8'd3)
		begin
			seg_get_data<=8'b1011_0000;
		end
		else if(seg_num==8'd4)
		begin
			seg_get_data<=8'b1001_1001;
		end
		else if(seg_num==8'd5)
		begin
			seg_get_data<=8'b1001_0010;
		end
		else if(seg_num==8'd6)
		begin
			seg_get_data<=8'b1000_0010;
		end
		else if(seg_num==8'd7)
		begin
			seg_get_data<=8'b1111_1000;
		end
		else if(seg_num==8'd8)
		begin
			seg_get_data<=8'b1000_0000;
		end
		else if(seg_num==8'd9)
		begin
			seg_get_data<=8'b1001_0000;
		end
	end
	else if(wei_cnt_clk==8'd3)
	begin
		seg_pi_data<=6'b11_1011;//0代表点亮
		seg_num<=all_num_cnt/1000%10;
		if(seg_num==8'd0)
		begin
			seg_get_data<=8'b1100_0000;
		end
		else if(seg_num==8'd1)
		begin
			seg_get_data<=8'b1111_1001;
		end
		else if(seg_num==8'd2)
		begin
			seg_get_data<=8'b1010_0100;
		end
		else if(seg_num==8'd3)
		begin
			seg_get_data<=8'b1011_0000;
		end
		else if(seg_num==8'd4)
		begin
			seg_get_data<=8'b1001_1001;
		end
		else if(seg_num==8'd5)
		begin
			seg_get_data<=8'b1001_0010;
		end
		else if(seg_num==8'd6)
		begin
			seg_get_data<=8'b1000_0010;
		end
		else if(seg_num==8'd7)
		begin
			seg_get_data<=8'b1111_1000;
		end
		else if(seg_num==8'd8)
		begin
			seg_get_data<=8'b1000_0000;
		end
		else if(seg_num==8'd9)
		begin
			seg_get_data<=8'b1001_0000;
		end
	end
	else if(wei_cnt_clk==8'd4)
	begin
		seg_pi_data<=6'b11_1101;//0代表点亮
		seg_num<=all_num_cnt/10000%10;
		if(seg_num==8'd0)
		begin
			seg_get_data<=8'b1100_0000;
		end
		else if(seg_num==8'd1)
		begin
			seg_get_data<=8'b1111_1001;
		end
		else if(seg_num==8'd2)
		begin
			seg_get_data<=8'b1010_0100;
		end
		else if(seg_num==8'd3)
		begin
			seg_get_data<=8'b1011_0000;
		end
		else if(seg_num==8'd4)
		begin
			seg_get_data<=8'b1001_1001;
		end
		else if(seg_num==8'd5)
		begin
			seg_get_data<=8'b1001_0010;
		end
		else if(seg_num==8'd6)
		begin
			seg_get_data<=8'b1000_0010;
		end
		else if(seg_num==8'd7)
		begin
			seg_get_data<=8'b1111_1000;
		end
		else if(seg_num==8'd8)
		begin
			seg_get_data<=8'b1000_0000;
		end
		else if(seg_num==8'd9)
		begin
			seg_get_data<=8'b1001_0000;
		end
	end
	else if(wei_cnt_clk==8'd5)
	begin
		seg_pi_data<=6'b11_1110;//0代表点亮
		seg_num<=all_num_cnt/100000%10;
		if(seg_num==8'd0)
		begin
			seg_get_data<=8'b1100_0000;
		end
		else if(seg_num==8'd1)
		begin
			seg_get_data<=8'b1111_1001;
		end
		else if(seg_num==8'd2)
		begin
			seg_get_data<=8'b1010_0100;
		end
		else if(seg_num==8'd3)
		begin
			seg_get_data<=8'b1011_0000;
		end
		else if(seg_num==8'd4)
		begin
			seg_get_data<=8'b1001_1001;
		end
		else if(seg_num==8'd5)
		begin
			seg_get_data<=8'b1001_0010;
		end
		else if(seg_num==8'd6)
		begin
			seg_get_data<=8'b1000_0010;
		end
		else if(seg_num==8'd7)
		begin
			seg_get_data<=8'b1111_1000;
		end
		else if(seg_num==8'd8)
		begin
			seg_get_data<=8'b1000_0000;
		end
		else if(seg_num==8'd9)
		begin
			seg_get_data<=8'b1001_0000;
		end
	end
	else if(wei_cnt_clk==8'd6)
	begin
		seg_pi_data<=6'b00_0000;//0代表点亮
		seg_get_data<=8'b1111_1111;
	end
	
end


assign seg_data=seg_get_data;//将寄存器与输出管教相连
assign seg_pi=seg_pi_data;

endmodule

        我们可以看到上述程序虽然实现了需求的功能,但是最终的程序有点啰嗦,我们可以将后面的重复代码写出一个程序,传相应的参数进去即可。程序博主之后再进行修改。

        多位数码管显示结果如下图所示

        本次多数码管显示的工程文件地址如下: https://download.csdn.net/download/qq_34020487/12258982

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页