xilinx FPGA实现数字钟——数码管显示

这两天学习xilinx的板子,做了一个数码管显示的数字时钟,本设计实现了数字时钟的数码管显示,没有实现调时间功能,现将实现过程记录下来。供有类似需要的童鞋做个参考。

 设计主要分为三个模块:时钟分频模块,时钟位数据产生模块,数码管扫描显示模块。

一、时钟显示模块 clk_div

  由于FPGA工作频率很高,我的板子上时钟是50MHz,数码管显示的最佳扫描频率是1KHz,第一个模块是做的一个50K的分频电路,是一个整数分频,这里并不复杂,具体整数分频实现思路可以参考我的博文:http://blog.csdn.net/baijingdong/article/details/20066327

代码:

module clk_div(
     clk,
     rst,
     clk_out
    );
		input clk;
		input rst;
		output clk_out;
		
		parameter N2=50000;
		
		reg clk3=1'b0;
		reg [16:0]count3=17'd0;
	assign clk_out=clk3;	
		
	always @(posedge clk or negedge rst)
	begin
		if (!rst)
		  begin
			count3<=17'd0;
			clk3<=1'b0;
		  end
		else
			if(count3<N2-1)
				begin
					count3<=count3+1'b1;
					if(count3<(N2/2-1))
					  clk3<=1'b0;
					else
					  clk3<=1'b1;
				end 
			else
			begin
				count3<=17'd0;
				clk3<=1'b0;
			end	
	end
endmodule

二、时钟位数据产生模块 clk_dis1_count

 该模块前面也有一个时钟分频模块,因为分频后的时钟为1KHz,这个时钟直接做计数时钟频率还是太高,这里前面要先加一个1K分频的整数分频模块。clk1-in(1khz),clk3-out(1Hz).

 我的板子上只有四个数码管,因此只实现了秒和分的时间显示,与单片机和其他嵌入式开发不同,FPGA是一个纯硬件的电路,因此,设计相对很不灵活,我们知道数码管显示是扫描显示的,每次只能显示分、秒四个数字中的一个数字,若是按照C语言的思路可以定义一个sec作为一个秒变量,sec%10,sec/10分别可以作为秒的个位和十位的数据,但是在FPGA中却不推荐这么做,因为纯硬件电路做除法等运算直接综合会耗费大量资源,有的运算比如开根号等甚至是无法综合的。

因此,用定义一个计数器分别取其十位和个位的方法设计并不好,我最初的思路也是这样,从我的模块名中就可以看出。但是这种方法起码在fpga设计中不推荐。

这里分别定义了四个寄存器变量,分别代表分和秒的十位和个位数据,利用四层判断语句完成判决。思路并不复杂,但还是很容易让人糊涂的。

模块代码如下:

module clk_dis1_count(clk1,rst,op1,op2,op3,op4);
input clk1,rst;       //声明时钟和复位信号,此处时钟为分频后得到的1KHz信号;
output reg [3:0]op1=4'd0;
output reg [3:0]op2=4'd0;
output reg [3:0]op3=4'd0;
output reg [3:0]op4=4'd0; /*op1,op2...为数码管显示时钟,这里分别定义,
 											op1,op3范围为【0-9】,op2,op4范围为【0-5】*/
//**************************************************************//											
//reg [9:0] count_clk1=10'd0;

//parameter N2=500;				//1KHz->2Hz,500分频电路;
parameter  N2=1000;     //更改成为1hz,每一秒输出一次,做电子表使用。	十位数可以达到1024,不会溢出。	
		reg clk3=1'b0;     //输出clk3 ,2Hz
		reg [9:0]count_clk1=10'd0;//计数器,足够用了。
	
		
	always @(posedge clk1 or negedge rst)
	begin
		if (!rst)
		  begin
			count_clk1<=10'd0;
			clk3<=1'b0;
		  end
		else
			if(count_clk1<N2-1)
				begin
					count_clk1<=count_clk1+1'b1;
					if(count_clk1<(N2/2-1))
					  clk3<=1'b0;
					else
					  clk3<=1'b1;
				end 
			else
			begin
				count_clk1<=10'd0;
				clk3<=1'b0;
			end	
	end
/*******************************************************/
always @(posedge clk3 or negedge rst)
begin
	if(!rst)
		begin
			op1<='d0;
			op2<='d0;
			op3<='d0;
			op4<='d0;
		end
	else
	begin
		if(op1<9)
			op1<=op1+1'b1;//如果秒钟最低位小于9,就加一,否则最低位变为0	
		else
			begin
				if(op2<5)
					op2<=op2+1'b1; //秒钟最低位为9时,十位是否为5,若小于5,十位加一,如:09-10,29-30
										//否则即为 59,->00.后两位为00分位置加一。
				else
					begin
						if(op3<9)
							op3<=op3+1'b1;//由于分和秒都是60进制,因此方法同上。
						else
							begin
								if(op4<5)
									op4<=op4+1'b1;
								else 
									op4<='d0;
								op3<='d0;
							end
							op2<='d0;
						end
					op1<='d0;
				end		
			end
end
 endmodule

三、数码管扫描显示模块 顶层模块

我的板子上的数码管是共阴极的,建立一个查询表,设计过程中用case(Num)语句改变输出。

数码管片选电平为高时数码管点亮,这里设计一个状态机,设计一个IDLE状态和四个输出状态在对应数码管点亮时输出对应位置的数据,然后切换到下一个输出状态。

这部分的代码如下:

`timescale 1ns / 1ps
//
// Company: bupt ,mr_bai
// Engineer: 
// 
// Create Date:    14:08:33 03/01/2014 
// Design Name: 
// Module Name:    clk_display 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//
module clk_display(
     clk,
     rst,
     sm_seg,
     sm_bit
    );
	 input clk;
    input rst;
    output reg[7:0] sm_seg;
    output reg [3:0]sm_bit;
	 //**********************
	 //定义线网型连接线;
	 //*******************
	 wire clk1;
	 wire [3:0]op1,op2,op3,op4;
	//*********************	 
	//定义状态机
	parameter  IDLE=5'b0000_1,
					SA =5'b0001_0,
					SB =5'b0010_0,
					SC =5'b0100_0,
					SD =5'b1000_0;
	reg [4:0]state;
	//
	reg [3:0]Num;
	
clk_div M1(
     .clk(clk),
     .rst(rst),
     .clk_out(clk1)
    );
clk_dis1_count M2(
.clk1(clk1),
.rst(rst),
.op1(op1),
.op2(op2),
.op3(op3),
.op4(op4)
);
  /*always @(posedge clk1)
  begin
		sm_bit<={sm_bit[2:0],sm_bit[3]};
  end*/
  
  always @(posedge clk1 or negedge rst)
  begin
		if(!rst)
			state<=IDLE;
		else
		  begin
				case (state)
					IDLE:state<=SA ;
					
					SA:
						begin
							sm_bit<=4'b0001;
							Num	<=op1;
							state <=SB;
							
						end
					SB:
						begin
							sm_bit<=4'b0010;
							Num   <=op2;
							state <=SC;
						end
					SC:
						begin
							sm_bit<=4'b0100;
							Num   <=op3;
							state <=SD;
						end
					SD:
						begin
							sm_bit<=4'b1000;
							Num   <=op4;
							state <=SA;
						end
					default state<=IDLE;
				endcase	
		  end
  end
     always @ (Num)//
	begin
		case (Num)  
			4'h0 : sm_seg = 8'h3f;   // "0"
			4'h1 : sm_seg = 8'h06;   // "1"
			4'h2 : sm_seg = 8'h5b;   // "2"
			4'h3 : sm_seg = 8'h4f;   // "3"
			4'h4 : sm_seg = 8'h66;   // "4"
			4'h5 : sm_seg = 8'h6d;   // "5"//共阴极数码管表
			4'h6 : sm_seg = 8'h7d;   // "6"
			4'h7 : sm_seg = 8'h07;   // "7"
			4'h8 : sm_seg = 8'h7f;   // "8"
			4'h9 : sm_seg = 8'h6f;   // "9"
			4'ha : sm_seg = 8'h77;   // "a"
			4'hb : sm_seg = 8'h7c;   // "b"
			4'hc : sm_seg = 8'h39;   // "c"
			4'hd : sm_seg = 8'h5e;   // "d"
			4'he : sm_seg = 8'h79;   // "e"
			4'hf : sm_seg = 8'h71;   // "f"
		endcase 
    end
  
endmodule

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值