用FPGA实现闸门法频率计(黑金EP4CE6F17C8N)

10月份学了仅仅20多天的FPGA,后来学长和我说先搁一段时间,以后用到再现学,于是耽搁了整整2个月,中间画板子调电路去了。(所以评论我博客的人问的问题,我真的不会回答)

最近终于要用到FPGA了,要做一个频率计,20多天的经验果然不够,写了两天代码,数码管死活全是0。测频率的原理是懂的,但是怎么都不会输出。咨询了很多搞电设的同学,都在忙期末考试没时间理我。功夫不负有心人,我竟然在CSDN资源上找到了一个能用的代码,哈哈哈,于是我直接把代码理解了就OK。写这篇博文,希望能够手把手教大家怎么样用FPGA做一个简单的频率计且用数码管输出。(以帮助像自己一样的菜鸟初学者顺利飞出林子变得不那么菜)

首先,实现的原理如逻辑门所示,信号通过输入,产生频率的计数,将数值送到数码管,进行6位数据的处理,最后再进行译码显示出来。(我原本自己写的数码管程序太naive了,原来需要这么复杂的驱动,我还是太菜了)

No.1测频率的fre_test.v

module fre_test(
                clk,
                rst_n,
		clk_in,
		fre
);//时钟、复位信号、待测的输入信号、输出的频率值
input          clk,rst_n,clk_in;
output       [19:0] fre;

reg    [19:0] fre;
reg    [30:0] count1,  count2;
reg            clk_1hz,  en;


wire          load,        clr;
//分频
always @ ( posedge clk or negedge rst_n )
begin
if( !rst_n )
 begin
    count1<=0;
	 clk_1hz<=0;
 end
else
 begin
  if ( count1<25000000-1 )      //晶振是50M,因此计数到49999999
		begin
		 count1  <=  count1 + 1 ;
		 clk_1hz <= 1;     //产生频率为1hz的时钟
		end
  else if ( count1 <50000000-1 )
		begin
		 count1 <= count1 + 1;
		 clk_1hz <= 0;
		end
  else
		begin
		 count1 <= 0;
		 clk_1hz <=0;
		end
 end
end
	   
//测量频率值
always @ ( posedge clk_1hz or negedge rst_n  )    //当检测到clk_1hz的上升沿时
begin
		if ( !rst_n)
				   en  <=  0;
		else
					begin
					en  <=  ~en;    //取反,en为高电平的时间为1s					end
end

assign   load =  ~en ;                    //load的信号永远和使能信号en是反的
assign   clr    =  load&&(~clk_1hz) ;     //当load和clk_1hz同时为1时清零信号clr有效
 
always @ ( posedge clk_in or posedge clr )
begin
	  if ( clr)
		      count2 <= 0;         //清零信号时,计数器count2为0
	  else
				begin
				  if ( en )        //使能信号时,开始计数
				  count2 <= count2 + 1;  //当检测到方波信号的上升沿时则计数,计数的值则为信号的频率值
				  else
				  count2 <= count2;
				end
end

always @ ( posedge load or negedge rst_n)            //输出频率load为上升沿时输出
begin
		 if(!rst_n)
		       fre  <=  0;
		 else 
		 begin
		       if(count2  <  900000)     //低于900000输出正常位
				 fre  <=  count2 ;
				 else if(count2  <  10000000) //小于10000000时位数不够,因此需要去掉一位
				 fre  <=  count2 / 10;
				 else
				 fre  <=  count2 / 100;  //去掉两位
       end
end


endmodule

在这里给大家理一下clk_1hz、en、load、clr信号之间的关系。

可以看出,en的频率为1秒,load的目的是为更新和为clr清零信号作准备的。从时序图可以简单看出来就不详细解释了。

其次,之所以取900000之后就换位而不是1000000的目的在于提醒大家位数变大了。

接着是wei_test

`timescale 1ns / 1ps
//
//
module wei_test(clk,rst,hex,Million,HunThousand,TenThousand,Thousand,Hundred,Ten,One);
input              clk;
input              rst;
input       [19:0] hex;
output  reg [3:0]  Million;            //百万位
        reg [19:0] d5; 
output  reg [3:0]  HunThousand;        //十万位
        reg [19:0] d6; 
output  reg [3:0]  TenThousand;        //万位
        reg [19:0] d1;       
output  reg [3:0]  Thousand;           //千位
        reg [16:0] d2;        
output  reg [3:0]  Hundred;            //百位
        reg [16:0] d3;     
output  reg [3:0]  Ten;                //十位
        reg [3:0] d4; 
output  reg [3:0]	 One;	  
        		  
        initial begin      //初始化使各个位都变为0
	         Million=4'h0;
					 
		 d5=20'h00000;
					 
                TenThousand=4'h0;

                d6=20'h00000;					 

                TenThousand=4'h0;

                d1=20'h00000;

                Thousand=4'h0;

                d2=16'h0000;

                Hundred=4'h0;

                d3=16'h0000;

                d4=4'h0;

                

        end 


        //百万位

        always@(posedge clk) begin

                if(!rst) begin                                        //同步复位

                        Million<=4'h0;

                        d5<=20'h00000;

                end else begin

                        if(hex>999999) begin

                                Million<=4'd1;

                                d5<=hex-20'd1000000;                      

                        end else begin

                                Million<=4'd0;

                                d5<=hex;

                        end

                end

        end	


//十万位

        always@(posedge clk) begin

                if(!rst) begin                                        //同步复位

                        HunThousand<=4'h0;

                        d6<=20'h00000;

                end else begin

                        if(d5>899999) begin

                                HunThousand<=4'd9;

                                d6<=d5-20'd900000;

                        end else if(d5>799999) begin

                                HunThousand<=4'd8;

                                d6<=d5-20'd800000;
								end else if(d5>699999) begin

                                HunThousand<=4'd7;

                                d6<=d5-20'd700000;
                        end else if(d5>599999) begin

                                HunThousand<=4'd6;

                                d6<=d5-20'd600000;
                        end else if(d5>499999) begin

                                HunThousand<=4'd5;

                                d6<=d5-20'd500000;										  

                        end else if(d5>399999) begin

                                HunThousand<=4'd4;

                                d6<=d5-20'd400000;

                        end else if(d5>299999) begin

                                HunThousand<=4'd3;

                                d6<=d5-20'd300000;

                        end else if(d5>199999) begin

                                HunThousand<=4'd2;

                                d6<=d5-20'd200000;

                        end else if(d5>99999) begin

                                HunThousand<=4'd1;

                                d6<=d5-20'd100000;

                        end else begin

                                HunThousand<=4'd0;

                                d6<=d5;

                        end

                end

        end		  
        //万位

        always@(posedge clk) begin

                if(!rst) begin                                        //同步复位

                        TenThousand<=4'h0;

                        d1<=20'h00000;

                end else begin

                        if(d6>89999) begin

                                TenThousand<=4'd9;

                                d1<=d6-20'd90000;
								end else if(d6>79999) begin

                                TenThousand<=4'd8;

                                d1<=d6-20'd80000;
							   end else if(d6>69999) begin

                                TenThousand<=4'd7;

                                d1<=d6-20'd70000;
								end else if(d6>59999) begin

                                TenThousand<=4'd6;

                                d1<=d6-20'd60000;

                        end else if(d6>49999) begin

                                TenThousand<=4'd5;

                                d1<=d6-20'd50000;

                        end else if(d6>39999) begin

                                TenThousand<=4'd4;

                                d1<=d6-20'd40000;

                        end else if(d6>29999) begin

                                TenThousand<=4'd3;

                                d1<=d6-20'd30000;

                        end else if(d6>19999) begin

                                TenThousand<=4'd2;

                                d1<=d6-20'd20000;

                        end else if(d6>9999) begin

                                TenThousand<=4'd1;

                                d1<=d6-20'd10000;

                        end else begin

                                TenThousand<=4'd0;

                                d1<=d6;

                        end

                end

        end

        //千位

        always@(posedge clk) begin

                if(!rst) begin

                        Thousand<=4'h0;

                        d2<=16'h0000;

                end else begin

                        if(d1>8999) begin

                                Thousand<={4'd9};

                                d2<=d1-16'd9000;

                        end else if(d1>7999) begin

                                Thousand<={4'd8};

                                d2<=d1-16'd8000;

                        end else if(d1>6999) begin

                                Thousand<={4'd7};

                                d2<=d1-16'd7000;

                        end else if(d1>5999) begin

                                Thousand<={4'd6};

                                d2<=d1-16'd6000;

                        end else if(d1>4999) begin

                                Thousand<={4'd5};

                                d2<=d1-16'd5000;

                        end else if(d1>3999) begin

                                Thousand<={4'd4};

                                d2<=d1-16'd4000;

                        end else if(d1>2999) begin

                                Thousand<={4'd3};

                                d2<=d1-16'd3000;

                        end else if(d1>1999) begin

                                Thousand<={4'd2};

                                d2<=d1-16'd2000;

                        end else if(d1>999) begin

                                Thousand<={4'd1};

                                d2<=d1-16'd1000;

                        end else begin

                                Thousand<={4'd0};

                                d2<=d1;

                        end

                end

        end

        //百位

        always@(posedge clk) begin

                if(!rst) begin

                        Hundred<=4'h0;

                        d3<=16'h0000;

                end else begin

                        if(d2>899) begin

                                Hundred<={4'd9};

                                d3<=d2-16'd900;

                        end else if(d2>799) begin

                                Hundred<={4'd8};

                                d3<=d2-16'd800;

                        end else if(d2>699) begin

                                Hundred<={4'd7};

                                d3<=d2-16'd700;

                        end else if(d2>599) begin

                                Hundred<={4'd6};

                                d3<=d2-16'd600;

                        end else if(d2>499) begin

                                Hundred<={4'd5};

                                d3<=d2-16'd500;

                        end else if(d2>399) begin

                                Hundred<={4'd4};

                                d3<=d2-16'd400;

                        end else if(d2>299) begin

                                Hundred<={4'd3};

                                d3<=d2-16'd300;

                        end else if(d2>199) begin

                                Hundred<={4'd2};

                                d3<=d2-16'd200;

                        end else if(d2>99) begin

                                Hundred<={4'd1};

                                d3<=d2-16'd100;

                        end else begin

                                Hundred<={4'd0};

                                d3<=d2;

                        end

                end

        end

        //十位

        always@(posedge clk) begin

                if(!rst) begin

                        Ten<=4'h0;

                        d4<=4'h0;

                end else begin

                        if(d3>89) begin

                                Ten<={4'd9};

                                d4<=d3-16'd90;

                        end else if(d3>79) begin

                                Ten<={4'd8};

                                d4<=d3-16'd80;

                        end else if(d3>69) begin

                                Ten<={4'd7};

                                d4<=d3-16'd70;

                        end else if(d3>59) begin

                                Ten<={4'd6};

                                d4<=d3-16'd60;

                        end else if(d3>49) begin

                                Ten<={4'd5};

                                d4<=d3-16'd50;

                        end else if(d3>39) begin

                                Ten<={4'd4};

                                d4<=d3-16'd40;

                        end else if(d3>29) begin

                                Ten<={4'd3};

                                d4<=d3-16'd30;

                        end else if(d3>19) begin

                                Ten<={4'd2};

                                d4<=d3-16'd20;

                        end else if(d3>9)        begin

                                Ten<={4'd1};

                                d4<=d3-16'd10;

                        end else begin

                                Ten<={4'd0};

                                d4<=d3;

                        end

                end

        end

        //个位

        always@(posedge clk) begin

                if(!rst) begin

                        One<=4'd0;

                end else begin

                        One<={d4[3:0]};

                end

        end

       

        

endmodule

这段代码是用来显示六位数码管的。先判断hex即频率值有没有超过999999(前面已经处理过,如果超过,则百万就有数值,否则可以正常显示),将值先送给d5寄存器,此时一个一个进行比较。当在899999~999999之间,则为9,一次类推下去,一位一位地赋值,同时减掉最高位赋给下一位。得到十万位、万位、千位、百位、十位和个位。

最后则是对数码管进行编码

module smg(
                          clk,
                          Million,
						  HunThousand,
						  TenThousand,
						  Thousand,
						  Hundred,
						  Ten,
						  One,
						  sel,
						  data
);
input        clk;
input        [3:0]Million,HunThousand,TenThousand,Thousand,Hundred,Ten,One;
output     reg [7:0]  data;
output     reg [7:0]  sel;

reg [3:0]  cnt,data_dis;
reg [20:0] m;
		 
always@(posedge clk) 
begin
m<=m+1;
end
  


always@(m[13]) 
begin
  case(m[15:13])
    0:  begin
				data_dis<=4'b0000;
				sel<=8'b1111_1110;
	    end
	1:  begin
				data_dis<=Million;
				sel<=8'b1111_1101;
		end
	2:  begin
				data_dis<=HunThousand;
				sel<=8'b1111_1011;
	    end
	3:  begin
				data_dis<=TenThousand;
				sel<=8'b1111_0111;
	    end
	4:  begin
				data_dis<=Thousand;
				sel<=8'b1110_1111;
    	end
	5:  begin
				data_dis<=Hundred;
				sel<=8'b1101_1111;		
		end
	6:  begin
				data_dis<=Ten;
				sel<=8'b1011_1111;
	    end
	7:  begin
				data_dis<=One;	
				sel<=8'b0111_1111;		
		end
	    default:begin
	        data<=8'bz;
		    sel<=8'bz;
		end	
  endcase
end

always@(data_dis)
begin
	    case(data_dis)						    //七段译码
				4'h0:data = 8'hc0;				//显示0
				4'h1:data = 8'hf9;				//显示1
				4'h2:data = 8'ha4;				//显示2
				4'h3:data = 8'hb0;				//显示3
				4'h4:data = 8'h99;				//显示4
				4'h5:data = 8'h92;				//显示5
				4'h6:data = 8'h82;				//显示6
				4'h7:data = 8'hf8;				//显示7
				4'h8:data = 8'h80;				//显示8
				4'h9:data = 8'h90;				//显示9
	         default data = 8'hxx;
	    endcase
end

endmodule

这里对数码管进行扫描操作时,定义了一个21位的寄存器,一直在计数,检测第16位和14位中间三位进行0~7之间8个数的判断,由此扫描显示数码管。

数码管的编码我相信每一块板子的教学视频都有讲解,就不过多解释了。

最后感谢这位分享资源的兄dei,提供一下网址:https://download.csdn.net/download/qq_33836552/9881856

这个资源显示的数值是两倍的频率,因为使能信号的频率为2hz,后面修正了一下,代码就是我上面写的。

最后定义一下管脚,下载到FPGA里,用信号发生器检验一下。希望大家成功。

-------------------------------分割线-------------------------------------------

我没有找到关于学FPGA的qq群,所以我自己建了一个群,期待和大家一起交流。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值