FPGA开发(七)数码管显示实验2-模块实现计数器

        上一篇文章中我们采用普通的方法实现了数码管显示计数器的内容,可以看到虽然逻辑清楚,但是不可避免的出现了代码过多的缺陷。我们可以看到六个数码管显示的方式基本一样。因此本次实验我们采用模块的形式,将每一个部分用一个模块来进行实现,首先我们需要一个计数模块,一个显示模块,一个显示刷新模块。

        计数模块:输入为

                       1.系统时钟和复位信号。

                       2.进位输入。(上一个计数器模块的进位信号)

                        输出为

                       1.当前计数值。(传给显示模块进行显示)

                       2.进位输出。(传送给下一个计数器模块)

                      功能为:按照上一位计数器的进位输出,将本计数器的值加一,如果计数到十,产生进位输出,并重新计数。

            代码如下:

/*
    Author:Alawyssun
	Time:2020/03/25
	实现功能:完成一个计数器模块 
	计数器输入: 1 进位脉冲
					2 时钟信号和复位信号 
	计数器输出:1 当前计数值
				  2 当前是否有进位信号
	
*/

module num_cnt(
	input rst,//复位信号
	input clk,//时钟信号
	input en,//使能信号 每使能一次计数加一
	output reg pulse,//输出进位信号 传给下一个计数器
	output reg[3:0] data//当前保存的数据
);

always@(posedge clk) 
begin  
	if(rst==0)//按下复位键 
	begin
		data<=4'd0;//计数器和输出全为0
		pulse<=1'd0;
	end
	if(en)//如果有进位输入
	begin 
		if(data==4'd9)//如果此时计数值已经达到9,那么将进位标志位设置为1 同时数据清零
		begin
			pulse<=1'b1;
			data<=4'd0;
		end		
		else //如果计数值不是9 那么计数值自己加一 同时进位标志位为0 
		begin
			pulse<=1'b0;
			data<=data+4'd1;
		end
	end
	else
	begin
		pulse<=1'b0;
	end 
end

endmodule

       显示模块:输入为

                       1.计数模块的计数值

                        输出为

                        1.输出到数码管的解码值 

                         功能为:将计数值(0到9)进行解码得到每一个数字的显示值。

                     代码如下:

/*
    Author:Alawyssun
	Time:2020/03/25
	实现功能:输入一个数字转换成对应的数码管编码
	输入:data 输入的参数
	输出:seg_data输出对应的数码管的编码
*/

module num_show(
	input[3:0]data,
	output reg[7:0]seg_data
	
);
/*
		4'ha:seg_data <= 8'b1000_1000;
		4'hb:seg_data <= 8'b1000_0011;
		4'hc:seg_data <= 8'b1100_0110;
		4'hd:seg_data <= 8'b1010_0001;
		4'he:seg_data <= 8'b1000_0110;
		4'hf:seg_data <= 8'b1000_1110;
*/
always@(*)
begin
	case(data)
		4'd0:seg_data <= 8'b1100_0000;
		4'd1:seg_data <= 8'b1111_1001;
		4'd2:seg_data <= 8'b1010_0100;
		4'd3:seg_data <= 8'b1011_0000;
		4'd4:seg_data <= 8'b1001_1001;
		4'd5:seg_data <= 8'b1001_0010;
		4'd6:seg_data <= 8'b1000_0010;
		4'd7:seg_data <= 8'b1111_1000;
		4'd8:seg_data <= 8'b1000_0000;
		4'd9:seg_data <= 8'b1001_0000;
		default:seg_data <= 8'b1111_1111;
	endcase
end

endmodule

       显示刷新模块:输入为

                         1.六个数码管的解码值

                         输出为:

                          1.当前数码管的片选

                          2.当前数码管的段选

                         功能为:按照刷新频率,将每一位数码管的值依次输出,利用视觉暂留,达到同时输出的结果。

                   代码如下

 

/*
	Author:Alawyssun
	Time:2020/03/25
	程序功能:实现数码管的扫描显示
	输入:六个数码管的输出编码数据
	输出:扫描之后的数码管段选和片选信号
*/
module num_scan(
	input clk,
	input rst,
	input[7:0] seg_data_scan_0,
	input[7:0] seg_data_scan_1,
	input[7:0] seg_data_scan_2,
	input[7:0] seg_data_scan_3,
	input[7:0] seg_data_scan_4,
	input[7:0] seg_data_scan_5,
	output reg[7:0] seg_data_scan,
	output reg[5:0] seg_sel
);
parameter SCAN_FREQ = 200;     //扫描的频率
parameter CLK_FREQ = 50000000; //时钟频率
parameter SCAN_COUNT = CLK_FREQ /(SCAN_FREQ*7) - 1;//扫描一次 需要时钟计数的个数

reg[31:0]time_cnt2;//时间计数器2 用作刷新数码管的时钟
reg[7:0] wei_cnt_clk;//判断输出哪一个数码管

//数码管刷新时间 计数
always@(posedge clk or negedge rst)
begin 
	if(rst==1'b0)
	begin
		time_cnt2<=32'd0;
	end
	else if(time_cnt2==SCAN_COUNT)
	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

//数码管显示
always@(posedge clk or negedge rst)
begin 	
	if(rst == 1'b0)
	begin
		seg_sel <= 6'b000000;
		seg_data_scan <= 8'hff;
	end
	else
	begin
		case(wei_cnt_clk)//如果计时为0 刷新第一个数码管
		8'd0:
		begin
			seg_data_scan<=seg_data_scan_0;
			seg_sel=6'b01_1111;
		end
		8'd1:
		begin
			seg_data_scan<=seg_data_scan_1;
			seg_sel=6'b10_1111;
		end
		8'd2:
		begin
			seg_data_scan<=seg_data_scan_2;
			seg_sel=6'b11_0111;
		end
		8'd3:
		begin
			seg_data_scan<=seg_data_scan_3;
			seg_sel=6'b11_1011;
		end
		8'd4:
		begin
			seg_data_scan<=seg_data_scan_4;
			seg_sel=6'b11_1101;
		end
		8'd5:
		begin
			seg_sel <= 6'b11_1110;
			seg_data_scan <= seg_data_scan_5;
		end
		8'd6://消影
		begin
			seg_sel <= 6'b00_0000;
			seg_data_scan <= 8'hff;
		end
		endcase
	end
end


endmodule

 

         在主模块中,我们只需要对应实例化各个模块即可,首先将每一个数码管的计数模块和显示模块相连,之后将所有模块的解码数输入到显示刷新模块,之后与FPGA的引脚相连接即可。

         主模块代码如下

/*
	Author:Alawyssun
	Time:2020/03/25
	实现功能:利用模块化的方法,实现六个数码管显示一个数字的功能
	该数字在时钟的作用下,按一定的频率自动加一
*/
`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 one_hz;

parameter CLK_FREQ = 50_000_000; //时钟频率
parameter CNT_SECOND = 1;     //计数器加一需要的时间 比如1秒 就写10  0.5秒就写5
parameter CNT_NUMBER = CNT_SECOND*CLK_FREQ;     //计数器加一需要的时间

always@(posedge clk or negedge rst)
begin
	if(rst==1'b0)
	begin
		time_cnt<=32'd0;
	end
	else 
	begin
		if(time_cnt==32'd49_999_999)
		begin
			time_cnt<=32'd0;
			one_hz<=1'b1;
		end
		else
		begin
			time_cnt<=time_cnt+32'd1;	
			one_hz<=1'b0;
		end
	end
end

wire[3:0] count0;
wire t0;
wire[7:0] seg_data_0;
num_cnt num_cnt0_my(
	 .rst  (rst),
    .clk    (clk),
    .en     (one_hz),
	 .pulse      (t0),
    .data   (count0)    
 );
num_show num_show0_my(
	.data (count0),
	.seg_data (seg_data_0)
);
 
wire[3:0] count1;
wire t1;
wire[7:0] seg_data_1;
num_cnt num_cnt1_my(
	 .rst  (rst),
    .clk    (clk),
    .en     (t0),
	 .pulse      (t1),
    .data   (count1)    
 );
num_show num_show1_my(
	.data (count1),
	.seg_data (seg_data_1)
);
 
wire[3:0] count2;
wire[7:0] seg_data_2;
wire t2;
num_cnt num_cnt2_my(
	 .rst  (rst),
    .clk    (clk),
    .en     (t1),
	 .pulse      (t2),
    .data   (count2)    
 );
num_show num_show2_my(
	.data (count2),
	.seg_data (seg_data_2)
);
 
wire[3:0] count3;
wire[7:0] seg_data_3;
wire t3;
num_cnt num_cnt3_my(
	 .rst  (rst),
    .clk    (clk),
    .en     (t2),
	 .pulse      (t3),
    .data   (count3)    
 );
num_show num_show3_my(
	.data (count3),
	.seg_data (seg_data_3)
);
 
wire[7:0] seg_data_4;
wire[3:0] count4;
wire t4;
num_cnt num_cnt4_my(
	 .rst  (rst),
    .clk    (clk),
    .en     (t3),
	 .pulse      (t4),
    .data   (count4)    
 );
num_show num_show4_my(
	.data (count4),
	.seg_data (seg_data_4)
);
 
wire[7:0] seg_data_5;
wire[3:0] count5;
wire t5;
num_cnt num_cnt5_my(
	 .rst  (rst),
    .clk    (clk),
    .en     (t4),
	 .pulse      (t5),
    .data   (count5)    
 );
num_show num_show5_my(
	.data (count5),
	.seg_data (seg_data_5)
);

num_scan num_scan_my(
	.clk (clk),
	.rst (rst),
	.seg_data_scan_0 (seg_data_0),
	.seg_data_scan_1 (seg_data_1),
	.seg_data_scan_2 (seg_data_2),
	.seg_data_scan_3 (seg_data_3),
	.seg_data_scan_4 (seg_data_4),
	.seg_data_scan_5 (seg_data_5),
	.seg_data_scan (seg_data),
	.seg_sel (seg_pi)
);
endmodule

        需要注意的是本程序中加入了消影模块,在显示刷新模块中,用了一次让数码管全部清除显示的方法,防止刷新过快出现重影。

       本次实验的RTL图如下,可以看到六个计数器组成一个进位加法器,之后每一个计数器连接一个显示模块后,通过选择模块输出:

       

       本次实验的效果如下:

         本实验的工程下载地址为: https://download.csdn.net/download/qq_34020487/12270265

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