目录
周期法频率计
分析:
设计过程:
周期法频率计
对于低频信号,应用周期法进行测频。周期法测频的基本原理是:应用标准频率信号统计被测信号两个相邻脉冲之间的脉冲数,然后通过脉冲数计算出被测信号的周期,再根据频率与周期之间的倒数关系计算出频率值。
分析:
(1)10mHz信号的周期为100秒。若应用50MHz晶振信号统计被测信号的周期,则两个相邻脉冲之间需要统计(50×106×100=)5×109个脉冲,因此需要应用33位二进制计数器(233=8588934592>5×109)进行计数。 (2)被测信号的周期以两个相邻脉冲的边沿为基准进行测量。
信号边沿检测的通用方法是:应用同步寄存器来捕获和存储被测频率信号。若应用三级右移寄存器作为同步器,如图所示,当存储数据Q0Q1Q2=x10 时,表示检测到被测信号的上升沿,存储数据Q0Q1Q2=x01时,表示检测到被测信号的下降沿,其中x表示无关位。
描述信号边沿检测电路的Verilog代码参考如下:
module edge_detector (
input det_clk, // 时钟,50MHz
input rst_n, // 复位信号,低电平有效
input x_signal, // 被测信号
output wire rising_edge, // 上升沿标志,高电平有效
output wire fall_edge // 下降沿标志,高电平有效
);
reg [0:2] sync_reg; // 三级同步寄存器定义
// 同步移存过程
always @( posedge det_clk or negedge rst_n )
if ( !rst_n ) sync_reg <= 3'b000;
else sync_reg <= { x_signal, sync_reg[0:1] };
// 边沿检测逻辑
assign rising_edge = sync_reg[1] & ~sync_reg[2];
assign fall_edge = ~sync_reg[1] & sync_reg[2];
endmodule
设计过程:
对于周期法频率计,状态机内部需要定义4个状态:复位(RESET)、空闲(IDLE)、计数(COUNT)和结束(DONE)。 状态转换的基本思路是: (1)复位信号有效时,强制状态机处于RESET状态; (2)复位信号撤销后,状态机转入IDLE状态,等待被测信号的有效沿。 (3)检测到第一个有效沿时,状态机转入COUNT状态,开始进行计数; (4)检测到第二个有效沿时,状态机转入DONE状态,停止计数并输出周期计数值; (5)状态机处于DONE时,下一个时钟脉冲转入IDLE状态。
根据上述状态转换图,描述周期测量状态机的Verilog代码参考如下:
module period_detector (
input det_clk, // 检测电路时钟,50MHz
input rst_n, // 复位信号,低电平有效
input x_signal, // 被测频率信号
output reg [32:0] period_value // 周期测量值
);
// 状态定义及编码
localparam RESET = 4'b0001;
localparam IDLE = 4'b0010;
localparam COUNT = 4'b0100;
localparam DONE = 4'b1000;
// 内部线网和变量定义
reg [0:2] sync_reg; // 移位寄存变量
(* synthesis,probe_port,keep *) wire fall_edge; // 下降沿标志
reg [3:0] current_state,next_state; // 现态与次态
(* synthesis,probe_port,keep *) wire cnt_en; // 计数允许信号
(* synthesis,probe_port,keep *) reg [32:0] period_cnt; // 周期计数值
// 下降沿检测逻辑
assign fall_edge = ~sync_reg[1] & sync_reg[2];
// 计数允许逻辑
assign cnt_en = ( current_state == COUNT );
// 同步移存过程
always @( posedge det_clk or negedge rst_n )
if ( !rst_n ) sync_reg <= 3'b000;
else sync_reg [0:2] <= { x_signal, sync_reg[0:1] };
// 状态机转换过程
always @( posedge det_clk or negedge rst_n )
if ( !rst_n ) current_state <= RESET;
else current_state <= next_state;
// 次态逻辑描述
always @ ( current_state )
case ( current_state )
RESET: next_state <= IDLE;
IDLE: if ( fall_edge ) next_state <= COUNT;
else next_state <= IDLE;
COUNT: if ( fall_edge ) next_state <= DONE;
else next_state <= COUNT;
DONE: next_state <= IDLE;
default: next_state <= RESET;
endcase
// 周期计数过程
always @( posedge det_clk )
if ( current_state == IDLE )
period_cnt <= {33{1'b0}};
else if ( cnt_en )
period_cnt <= period_cnt + 1'b1;
// 计数锁存过程
always @ ( current_state )
if ( current_state == DONE )
period_value <= period_cnt;
endmodule
上述状态机代码的仿真波形如图所示。从图中可以看出,状态机时序正确。
应用状态机统计到被测信号周期的计数值period_value后,还需要将计数值转换为周期值,然后再换算为频率值。 由于状态机的时钟为50MHz,所以标准信号的周期 Tdet_clk=20ns,因此被测信号的周期值Tx为 Tx = period_value × Tdet_clk = period_value × 20 (ns) 因此,被测信号的频率值为 fx = 1/Tx = 109/ (period_value × 20) = 5×107/ period_value (Hz) 由上式可以看出,需要应用除法器来计算被测信号的频率值。
测量10mHz~10kHz低频信号的频率,定义被测信号的频率大于等于1Hz时,频率值以“4位整数+4位小数”的格式显示,被测信号的频率小于1Hz时,频率值以“8位小数”的格式显示。
设fx=qqq...qqqq.rrrr rrrr...r。为处理方便,先将计算得到的频率值fx扩大108倍,因此,当频率小于1Hz时除法的商即为实际的频率值,以“8位小数”格式显示。当频率大于小于1Hz时,再缩小104倍(相当于将fx只扩大104倍),则以“4位整数+4位小数”加上小数点显示时,即为实际的频率值。 由于被除数5×1015需要用53位二进制数(252<5×1015<253)表示,而除数period_value为33位二进制数,因此需要定制53位二进制数除以33位二进制数的除法器。
在“DIVIDER_for_freqor_inst.v”前打√,表示生成例化模板文件,以便可以应用例化语句调用定制的除法器。
根据上述处理思路,将周期计数值转换为频率的Verilog描述代码参考如下:
module period2freq (
input [32:0] period_value, // 33位周期计数值
output wire [27:0] freq_value, // 频率值,需要应用BIN28toBCD转换为8个BCD码
output wire DP_flag // 小数点标志
);
// 内部线网定义
wire [52:0] div_quotient; // 53位除法商数
wire [32:0] div_remain; // 33位除法余数
wire [52:0] freq_temp; // 商数÷10000
// 除法器IP例化
DIVIDER_for_freqor DIVIDER_for_freqor_inst (
.denom ( period_value ), // 分母,周期计数值
.numer ( 53'd5000000000000000 ), // 分子,常数5×1015
.quotient ( div_quotient ), // 除法商数,53位
.remain ( div_remain ) // 除法余数,33位
);
// 频率显示值和小数点标志输出
assign freq_temp = div_quotient/10000;
assign freq_value = (div_quotient<100000000)? // 小于108?
div_quotient[27:0] : // 小于1Hz,以“8位小数”显示
freq_temp[27:0]; // 大于等于1Hz,以“4位整数+4位小数”显示
assign DP_flag = ( div_quotient<100000000 )? 0 : 1;
endmodule
20路分频式信号源,输出信号频率为:0.01~6103Hz,由4.5节中模块fx32.v简化而来。
module fx20 (
input clk50, // 时钟,50MHz
input [4:0] fsel, // 频率选择
output reg fpout // 信号源输出
);
// 内部变量定义
reg [31:0] q; // 计数变量
// 计数逻辑描述
always @(posedge clk50 )
q <= q + 1'b1;
// 输出选择过程
always @(fsel,q)
case (fsel) // 根据fsel分频输出
5'b01100: fpout = q[12]; // 6103.515625Hz
5'b01101: fpout = q[13]; // 3051.7578125Hz
5'b01110: fpout = q[14]; // 1525.87890625Hz
5'b01111: fpout = q[15]; // 762.939453125Hz
5'b10000: fpout = q[16]; // 381.4697265625Hz
5'b10001: fpout = q[17]; // 190.7348631825Hz
5'b10010: fpout = q[18]; // 95.367431640625Hz
5'b10011: fpout = q[19]; // 47.6837158203125Hz
5'b10100: fpout = q[20]; // 23.84185791015625Hz
5'b10101: fpout = q[21]; // 11.920928955078125Hz
5'b10110: fpout = q[22]; // 5.9604644775390625Hz
5'b10111: fpout = q[23]; // 2.9802322876953125Hz
5'b11000: fpout = q[24]; // 1.490116119384765625Hz
5'b11001: fpout = q[25]; // 0.7450580596923828125Hz
5'b11010: fpout = q[26]; // 0.37252902984619140625Hz
5'b11011: fpout = q[27]; // 0.186264514923095703125Hz
5'b11100: fpout = q[28]; // 0.0931322574615478515625Hz
5'b11101: fpout = q[29]; // 0.04656612873077392578125Hz
5'b11110: fpout = q[30]; // 0.023283064365386962890625Hz
5'b11111: fpout = q[31]; // 0.0116415321826934814453125Hz
default: fpout = q[14]; // 1525.87890625Hz
endcase
endmodule