******************************************************************************************
Author:  荷包蛋
E-mail: shuangfeiyanworld@163.com
Device:  EP2C8Q208C8
Tool:    Quartus 8.1
Function:数字频率计(用8个数码管显示结果,单位为HZ)(理论基础:在单位时间1s内待测信号所产生的脉冲数即为待测信号的频率)
Version: 2011-9-5 v1.0
********************************************************************************************/

module frequence  (
                     input    CLK_50M, // 50MHZ基准频率
                     input      CLK_X,  // 待测信号
                     output reg [7 :0] WEI,DUAN // 数码管位选和段选
                  );
reg [31:0] cnt1,num;  //cnt1用来作延时用,num用来计算1s内待测信号所发出的脉冲数
reg        sec,state;      //sec用来产生周期为2s,占空比为50%的单位脉冲(即一个周期内高电平和低电平持续时间均为1s)
reg [31:0] freq ;     //频率输出


/**** 产生占空比为50%,周期为2s的单位脉冲sec ****/
always @ (posedge CLK_50M)
begin
 if(cnt1==50_000_000) // delay 1s,cnt1=50_000_000是为了延时1s(因为基准时钟为50M),如果基准时钟为20M,则应写为cnt1==20_000_000,以此类推,总之,只要实现1s延时即可
  begin
   cnt1<=0;
   sec<=~sec;
  end
 else
   cnt1<=cnt1+1;
end

/**** 统计待测信号在单位时间1s内产生的脉冲数 ****/
always @ (posedge CLK_X)
begin
 if(sec) // sec为高电平期间(1s),统计待测信号产生的脉冲数
  begin
   num<=num+1;
   state<=0;
  end
 else // sec为低电平期间(1s),读取待测信号产生的脉冲数
  case(state)
  0: begin freq<=num; state<=1;   end // 读取脉冲数(由于freq为reg型,在下一次sec低电平到来之前,会一直保持当前值不变)
  1: num<=0; // 将num清零,为下一个sec高电平期间脉冲数的统计做准备
  endcase
end


/**** 以下为频率测量结果的显示模块 ****/

reg [3 :0] wei1,wei2,wei3,wei4,wei5,wei6,wei7,wei8 ; //待测

always @ ( posedge CLK_50M ) // 得到待测信号频率输出的个位数,十位数,百位数,......(提示:N**M的意思是N的M次方)
begin
 wei1 <= (freq/10**0)%10 ;
 wei2 <= (freq/10**1)%10 ;
 wei3 <= (freq/10**2)%10 ;
 wei4 <= (freq/10**3)%10 ;
 wei5 <= (freq/10**4)%10 ;
 wei6 <= (freq/10**5)%10 ;
 wei7 <= (freq/10**6)%10 ;
 wei8 <= (freq/10**7)%10 ;
end


//display part
reg [15:0]jishu;

always@(posedge CLK_50M) // 为数码管动态扫描的时间间隔作准备
begin
 if (jishu==16'hffff)
   jishu<=0;
 else
  begin
   jishu<=jishu+1;
  end
end


reg [3:0]tab;

always@(posedge CLK_50M)
begin
 case(jishu[15:13]) // 位值读取;每一个时间间隔读取一个位(个位、十位、百位 ...)
 0:tab<=wei1[3:0];
 1:tab<=wei2[3:0];
 2:tab<=wei3[3:0];
 3:tab<=wei4[3:0];
 4:tab<=wei5[3:0];
 5:tab<=wei6[3:0];
 6:tab<=wei7[3:0];
 7:tab<=wei8[3:0];
 default:tab<=4'bz;
 endcase 
 
 case(jishu[15:13]) // 位选;在对应的时间间隔上打开对应的数码管(第一个、第二个、第三个 ...)
 0:WEI<=8'b1111_1110;//显示在第一个数码管上的数
 1:WEI<=8'b1111_1101;//显示在第二个数码管上的数,以下同理
 2:WEI<=8'b1111_1011;
 3:WEI<=8'b1111_0111;
 4:WEI<=8'b1110_1111;
 5:WEI<=8'b1101_1111;
 6:WEI<=8'b1011_1111;
 7:WEI<=8'b0111_1111;
 default:WEI<=4'bz;
 endcase
 
 case(tab)  // 段选;当tab(即wei1/wei2 ...)为0,1,2...时,打开数码管相应的段
 0:DUAN<=8'hc0;
 1:DUAN<=8'hf9;
 2:DUAN<=8'ha4;
 3:DUAN<=8'hb0;
 4:DUAN<=8'h99;
 5:DUAN<=8'h92;
 6:DUAN<=8'h82;
 7:DUAN<=8'hf8;
 8:DUAN<=8'h80;
 9:DUAN<=8'h90;
 default:DUAN<=8'h??;
 endcase   
end

endmodule