基于Verilog的频率计

写了个频率计,感觉精度还可以,贴一下.

功能

用DE2实现,用8位七段数码管显示测的的频率,生成若干待测频率,用开关进行频率切换.具体实现如下

##三-八译码器
数码管现实离不开三-八译码器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
module decoder(
input [3:0]i,
output [6:0]led
);
parameter _0 = 8'b1100_0000,
_1 = 8'b1111_1001,
_2 = 8'b1010_0100,
_3 = 8'b1011_0000,
_4 = 8'b1001_1001,
_5 = 8'b1001_0010,
_6 = 8'b1000_0010,
_7 = 8'b1111_1000,
_8 = 8'b1000_0000,
_9 = 8'b1001_0000,
_A = 8'b1000_1000,
_B = 8'b1000_0011,
_C = 8'b1100_0110,
_D = 8'b1010_0001,
_E = 8'b1000_0110,
_F = 8'b1000_1110;

reg [7:0]led_temp;
always @(i)
begin
case(i)
4'd0: led_temp = _0;
4'd1: led_temp = _1;
4'd2: led_temp = _2;
4'd3: led_temp = _3;
4'd4: led_temp = _4;
4'd5: led_temp = _5;
4'd6: led_temp = _6;
4'd7: led_temp = _7;
4'd8: led_temp = _8;
4'd9: led_temp = _9;
4'hA: led_temp = _A;
4'hB: led_temp = _B;
4'hC: led_temp = _C;
4'hD: led_temp = _D;
4'hE: led_temp = _E;
4'hF: led_temp = _F;
default: led_temp = _0;
endcase
end

assign led = led_temp[6:0];

endmodule

待测频率

测模块产生 10hz,100hz,1khz,1Mhz的待测频率.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
module Fin(
input CLK_50M,
input [1:0] SW,
output reg Fout
);

reg [31:0]num;

always @(posedge CLK_50M)
begin
case (SW)
2'b00: //10Hz
if(num<2500000-1)
num <= num+1'b1;
else
begin
num <= 0;
Fout <= ~Fout;
end
2'b01: //100Hz
if(num<250000-1)
num <= num+1'b1;
else
begin
num <= 0;
Fout <= ~Fout;
end
2'b10: //1KHz
if(num<25000-1)
num <= num+1'b1;
else
begin
num <= 0;
Fout <= ~Fout;
end
2'b11: //1MHz
if(num<25-1)
num <= num+1'b1;
else
begin
num <= 0;
Fout <= ~Fout;
end
endcase
end

endmodule

频率检测模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
module control (
input CLK_50M,
input CLK_X_c,
output [31:0]freq_c
);

reg [31:0] cnt1,num; //cnt1用来作延时用
reg sec;
reg flag;

reg [31:0] freq; //频率输出

/****周期为2s的单位脉冲sec ****/
always @ (posedge CLK_50M)
begin
if(cnt1==50_000_000-1) // delay 1s
begin
cnt1<=0;
sec<=~sec;
end
else
cnt1<=cnt1+1;
end

/**** 1s内产生的脉冲数 ****/
always @ (posedge CLK_X_c)
begin
if(sec) // 统计待测信号产生的脉冲数
begin
num<=num+1;
flag<=0;
end
else
begin
if (!flag)
begin
freq<=num; // 读取脉冲数
flag<=1;
end
else num<=0; // 清零
end
end

assign freq_c = freq;

endmodule

顶层模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
module zh(
input CLK_50M, // 50MHZ基准频率
input [1:0]sw,
output [7:0]LED0,
output [7:0]LED1,
output [7:0]LED2,
output [7:0]LED3,
output [7:0]LED4,
output [7:0]LED5,
output [7:0]LED6,
output [7:0]LED7
);

wire [31:0]freq;
wire CLK_X;
//PLL U8(CLK_50M,CLK_X);
Fin U10 (
.CLK_50M(CLK_50M),
.SW(sw),
.Fout(CLK_X)
);

control U9(
.CLK_50M(CLK_50M),
.CLK_X_c(CLK_X),
.freq_c(freq)
);

/****分离各个显示位****/

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

always @ ( posedge CLK_50M ) // 得到待测信号频率输出的个位, 十位等。
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


decoder U0(.i(wei1),.led(LED0));
decoder U1(.i(wei2),.led(LED1));
decoder U2(.i(wei3),.led(LED2));
decoder U3(.i(wei4),.led(LED3));
decoder U4(.i(wei5),.led(LED4));
decoder U5(.i(wei6),.led(LED5));
decoder U6(.i(wei7),.led(LED6));
decoder U7(.i(wei8),.led(LED7));

endmodule

Summary

经过检测在1Mhz以内没有丢失时钟,还不错!