单片机学习小组
直播中

梅利号

9年用户 1506经验值
擅长:可编程逻辑
私信 关注

如何去实现一种等精度频率计模块的设计呢

什么是数字频率计?
如何去实现一种等精度频率计模块的设计呢?



回帖(2)

关睿

2022-1-17 14:35:34
数字频率计是一种基本的测量仪器,被广泛应用于航天、电子、测控等领域。基于传统测频原理的频率计的测量精度将随被测信号频率的下降而降低,在使用中有较大的局限性,而等精度频率计不但具有较高的测量精度,而且在整个频率区域能保持恒定的测试精度。本章我们通过新起点开发板搭建等精度频率计,学习等精度频率计的设计思想和实现方案。

29.1简介
频率测量在电子设计和测量领域中经常用到,因此对频率测量方法的研究在实际工程应用中具有重要意义。常用的频率测量方法有两种:周期测量法和频率测量法。周期测量法是先测量出被测信号的周期T,然后根据频率求出被测信号的频率。频率测量法是在时间t内对被测信号的脉冲数N进行计数,然后求出单位时间内的脉冲数,即为被测信号的频率。但是上述两种方法都会产生±1个基准时钟误差或被测时钟的误差,在实际应用中有一定的局限性。根据测量原理,很容易发现周期测量法适合于低频信号测量,频率测量法适合于高频信号测量,但二者都不能兼顾高低频率同样精度的测量要求。
等精度测量的一个最大特点是测量的实际门控时间不是一个固定值,而是一个与被测信号有关的值,刚好是被测信号的整数倍。在计数允许时间内,同时对基准时钟和被测信号进行计数,再通过数学公式推导得到被测信号的频率。由于门控信号是被测信号的整数倍,就消除了对被测信号产生的±l周期误差,但是会产生对基准时钟±1周期的误差。等精度测量原理如图 29.1.1所示。

图 29.1.1 等精度测量原理
从以上叙述的等精度的测量原理可以很容易得出如下结论:首先,被测信号频率clk_fx的相对误差与被测信号的频率无关;其次,增大测量时间段“软件闸门”或提高“标频”clk_fs,可以减小相对误差,提高测量精度;最后,由于一般提供基准时钟clk_fs的石英晶振稳定性很高,所以基准时钟的相对误差很小,可忽略。假设基准时钟的频率为100MHz,只要实际闸门时间大于或等于1s,就可使测量的最大相对误差小于或等于10^(-8),即精度达到1/100MHz。等精度测量的核心思想在于如何保证在实际测量门闸内被测信号为整数个周期,这就需要在设计中让实际测量门闸信号与被测信号建立一定的关系。基于这种思想,设计中以被测信号的上升沿作为开启门闸和关闭门闸的驱动信号,只有在被测信号的上升沿才将图 29.1.1中预置的“软件闸门”的状态锁存,因此在“实际闸门”Tx内被测信号的个数就能保证整数个周期,这样就避免普通测量方法中被测信号的±1的误差,但会产生高频的基准时钟信号的±l周期误差,由于基准时钟频率远高于被测信号,因此它产生的±1周期误差对测量精度的影响十分有限,特别是在中低频测量的时候,相较于传统的频率测量和周期测量方法,可以大大提高测量精度。
等精度测频的原理图如图 29.1.2所示。如图中所示,预置软件闸门信号Gate是由新起点开发板的定时模块产生,gate的时间宽度对测频精度的影响较小,故可以在较大的范围内选择,GATE信号经被测时钟clk_fx同步化(图中的D触发器)到被测时钟域下。另外,为了方便处理,这里选择预置闸门信号的长度由参数GATE_TIME设置。图中的fs_cnt和fx_cnt是2个可控的32位高速计数器,fs_cnt_en和fx_cnt_en分别是其计数使能端,由同步化后的gate信号控制,基准时钟信号clk_fs从时钟输入端clk_fs输入,待测信号clk_fx从时钟输入端clk_fx输入。测量时,生成的gate信号,在被测时钟同步化后用来控制启动和关闭2个计数器,2个计数器分别对被测信号和基准时钟计数。若在一次实际闸门时间GATE_TIME中,计数器对被测信号的计数值为fx_cnt,对基准时钟的计数值为fs_cnt,而基准时钟的频率为CLK_FS,则被测信号的频率为clk_fx,则由公式

图 29.1.2 是新起点开发板实现功能的原理图。

图 29.1.2 新起点实现的功能的原理图
29.2实验任务
本次的实验任务是板载50MHz的时钟通过内部逻辑进行分频,来产生500KHz频率的信号,作为被测时钟,然后用Verilog HDL编写的等精度测量模块测量被测时钟,并通过数码管显示。
29.3硬件设计
本次实验只需将新起点开发板P6扩展口的两个IO使用跳帽或者杜邦线连接即可。本次实验将新起点开发板的N9引脚做为分频产生的时钟的输出端,P9引脚作为被测时钟的输入端,通过一根导线(杜邦线)或者跳帽进行连接。

图 29.3.1 硬件原理图
由于端口引脚较多,这里仅给出部分管脚列表,如下表所示:
表 29.3.1 等精度频率计实验管脚分配

XDC约束语句如下:
set_location_assignment PIN_M2 -to sys_clk
set_location_assignment PIN_M1 -to sys_rst_n
set_location_assignment PIN_P9 -to clk_fx
set_location_assignment PIN_N9 -to clk_out
29.4程序设计
根据实验任务,我们可以大致规划出系统的控制流程:首先我们设计一个测试时钟模块用于生成被测的时钟,然后用等精度频率计模块测量被测时钟的频率,并将测得的时钟频率值送入数码管显示模块进行显示。由此画出系统的功能框图如下所示:

图 29.4.1 等精度频率计实验系统框图
由系统框图可知,FPGA部分包括四个模块:顶层模块(top_cymometer)、等精度频率计模块(cymometer)、时钟产生模块(test_pll)以及数码管显示模块(seg_led)。各模块功能如下:
顶层模块(top_cymometer):顶层模块完成了对其它三个模块的例化,实现各模块之间的数据交互。时钟产生模块产生被测时钟输出,并从外部接入至等精度频率计模块,以进行频率测量,将测量的结果传输给数码管显示模块进行显示。顶层模块的原理图如下图所示:

图 29.4.2 顶层模块原理图
等精度频率计模块(cymometer):等精度频率计模块测量输入的被测时钟的频率。并将测得的频率结果输出。
时钟产生模块(test_pll):时钟产生模块产生被测的时钟。
数码管显示模块(seg_led):用来驱动数码管将等精度频率计测得的时钟频率值在数码管上显示出来。
顶层模块的代码如下:

module top_cymometer(
    //system clock
    input                  sys_clk  ,    // 时钟信号
    input                  sys_rst_n,    // 复位信号


    //cymometer interface
    input                  clk_fx   ,    // 被测时钟
    output                 clk_out  ,    // 输出时钟
    //user interface
    output          [5:0]  sel      ,    // 数码管位选
    output          [7:0]  seg_led       // 数码管段选
);


//parameter define
parameter    CLK_FS = 26'd50000000;      // 基准时钟频率值


//wire define
wire    [19:0]       data_fx;            // 被测信号测量值


//*****************************************************
//**                    main code
//*****************************************************


//例化等精度频率计模块
cymometer #(.CLK_FS(CLK_FS)              // 基准时钟频率值
) u_cymometer(
    //system clock
    .clk_fs      (sys_clk  ),            // 基准时钟信号
    .rst_n       (sys_rst_n),            // 复位信号
    //cymometer interface
    .clk_fx      (clk_fx   ),            // 被测时钟信号
    .data_fx     (data_fx  )             // 被测时钟频率输出
);
   
//例化测试时钟模块,产生测试时钟
clk_test #(.DIV_N(7'd100)                // 分频系数
) u_clk_test(
    //源时钟
    .clk_in      (sys_clk  ),            // 输入时钟
    .rst_n       (sys_rst_n),            // 复位信号
    //分频后的时钟
    .clk_out     (clk_out  )             // 测试时钟
);


//例化数码管显示模块
seg_led u_seg_led(
    //module clock
    .clk         (sys_clk  ),            // 数码管驱动模块的驱动时钟
    .rst_n       (sys_rst_n),            // 复位信号
    //seg_led interface
    .sel         (sel      ),            // 数码管位选
    .seg_led     (seg_led  ),            // 数码管段选
    //user interface
    .data        (data_fx  ),            // 被测频率值
    .point       (6'd0     ),            // 数码管显示的点控制
    .en          (1'b1     ),            // 数码管驱动使能信号
    .sign        (1'b0     )             // 控制符号位显示
);


endmodule


2、时钟产生模块的代码如下:
module clk_test #(parameter DIV_N = 7'd100)    //分频系数
    (
     //源时钟
     input        clk_in     ,                 // 输入时钟
     input        rst_n      ,                 // 复位信号
     //分频后的时钟
     output  reg  clk_out                      // 输出时钟
);


//reg define
reg [9:0] cnt;                                 // 时钟分频计数


//*****************************************************
//**                    main code
//*****************************************************


//时钟分频
always @(posedge clk_in or negedge rst_n) begin
    if(rst_n == 1'b0) begin
        cnt     <= 0;
        clk_out <= 0;
    end
    else begin
        if(cnt == DIV_N/2 - 1'b1) begin
            cnt     <= 10'd0;
            clk_out <= ~clk_out;
        end
        else
            cnt <= cnt + 1'b1;
    end
end


endmodule


时钟产生模块通过分频产生被测时钟,这里是用偶数分频方法产生,修改代码第一行的DIV_N分频参数,可得到不同频率的时钟信号,时钟频率为clk_in/DIV_N 。由于该模块在顶层例化时clk_in为系统时钟50MHz,分频参数为100,产生的时钟频率为50000000/100 = 500000Hz。
举报

尹姗姗

2022-1-17 14:35:38
3、等精度频率计模块的代码如下:
module cymometer
   #(parameter    CLK_FS = 26'd50_000_000) // 基准时钟频率值
    (   //system clock
        input                 clk_fs ,     // 基准时钟信号
        input                 rst_n  ,     // 复位信号


        //cymometer interface
        input                 clk_fx ,     // 被测时钟信号
        output   reg [19:0]   data_fx      // 被测时钟频率输出
);


//parameter define
localparam   MAX       =  6'd32;           // 定义fs_cnt、fx_cnt的最大位宽
localparam   GATE_TIME = 16'd5_000;        // 门控时间设置


//reg define
reg                gate        ;           // 门控信号
reg                gate_fs     ;           // 同步到基准时钟的门控信号
reg                gate_fs_r   ;           // 用于同步gate信号的寄存器
reg                gate_fs_d0  ;           // 用于采集基准时钟下gate下降沿
reg                gate_fs_d1  ;           //
reg                gate_fx_d0  ;           // 用于采集被测时钟下gate下降沿
reg                gate_fx_d1  ;           //
reg    [   15:0]   gate_cnt    ;           // 门控计数
reg    [MAX-1:0]   fs_cnt      ;           // 门控时间内基准时钟的计数值
reg    [MAX-1:0]   fs_cnt_temp ;           // fs_cnt 临时值
reg    [MAX-1:0]   fx_cnt      ;           // 门控时间内被测时钟的计数值
reg    [MAX-1:0]   fx_cnt_temp ;           // fx_cnt 临时值


//wire define
wire               neg_gate_fs;            // 基准时钟下门控信号下降沿
wire               neg_gate_fx;            // 被测时钟下门控信号下降沿


//*****************************************************
//**                    main code
//*****************************************************


//边沿检测,捕获信号下降沿
assign neg_gate_fs = gate_fs_d1 & (~gate_fs_d0);
assign neg_gate_fx = gate_fx_d1 & (~gate_fx_d0);


//门控信号计数器,使用被测时钟计数
always @(posedge clk_fx or negedge rst_n) begin
    if(!rst_n)
        gate_cnt <= 16'd0;
    else if(gate_cnt == GATE_TIME + 5'd20)
        gate_cnt <= 16'd0;
    else
        gate_cnt <= gate_cnt + 1'b1;
end


//门控信号,拉高时间为GATE_TIME个实测时钟周期
always @(posedge clk_fx or negedge rst_n) begin
    if(!rst_n)
        gate <= 1'b0;
    else if(gate_cnt < 4'd10)
        gate <= 1'b0;     
    else if(gate_cnt < GATE_TIME + 4'd10)
        gate <= 1'b1;
    else if(gate_cnt <= GATE_TIME + 5'd20)
        gate <= 1'b0;
    else
        gate <= 1'b0;
end


//将门控信号同步到基准时钟下
always @(posedge clk_fs or negedge rst_n) begin
    if(!rst_n) begin
        gate_fs_r <= 1'b0;
        gate_fs   <= 1'b0;
    end
    else begin
        gate_fs_r <= gate;
        gate_fs   <= gate_fs_r;
    end
end


//打拍采门控信号的下降沿(被测时钟下)
always @(posedge clk_fx or negedge rst_n) begin
    if(!rst_n) begin
        gate_fx_d0 <= 1'b0;
        gate_fx_d1 <= 1'b0;
    end
    else begin
        gate_fx_d0 <= gate;
        gate_fx_d1 <= gate_fx_d0;
    end
end


//打拍采门控信号的下降沿(基准时钟下)
always @(posedge clk_fs or negedge rst_n) begin
    if(!rst_n) begin
        gate_fs_d0 <= 1'b0;
        gate_fs_d1 <= 1'b0;
    end
    else begin
        gate_fs_d0 <= gate_fs;
        gate_fs_d1 <= gate_fs_d0;
    end
end


//门控时间内对被测时钟计数
always @(posedge clk_fx or negedge rst_n) begin
    if(!rst_n) begin
        fx_cnt_temp <= 32'd0;
        fx_cnt <= 32'd0;
    end
    else if(gate)
        fx_cnt_temp <= fx_cnt_temp + 1'b1;
    else if(neg_gate_fx) begin
        fx_cnt_temp <= 32'd0;
        fx_cnt   <= fx_cnt_temp;
    end
end


//门控时间内对基准时钟计数
always @(posedge clk_fs or negedge rst_n) begin
    if(!rst_n) begin
        fs_cnt_temp <= 32'd0;
        fs_cnt <= 32'd0;
    end
    else if(gate_fs)
        fs_cnt_temp <= fs_cnt_temp + 1'b1;
    else if(neg_gate_fs) begin
        fs_cnt_temp <= 32'd0;
        fs_cnt <= fs_cnt_temp;
    end
end


//计算被测信号频率
always @(posedge clk_fs or negedge rst_n) begin
    if(!rst_n) begin
        data_fx <= 20'd0;
    end
    else if(gate_fs == 1'b0)
        data_fx <= (CLK_FS / fs_cnt) * fx_cnt ;
end


endmodule


在前面的等精度频率计简介中,我们知道在等精度测量中需要一个闸门信号(门控信号),并且该闸门信号需要同步化到被测时钟域下。这里我们为了方便处理,用被测时钟控制闸门信号的产生,这样就避免了同步化处理,当然了,完全可以用基准时钟控制闸门信号的产生,不过这时产生的闸门信号我们需要同步化到被测时钟域下,这样做的目的是为了不让被测时钟计数产生周期的误差。门控时间由参数GATE_TIME设置,此处设为5000,需要说明的是该值越大测得的被测时钟频率值越精确,但测量时间也会相应的变慢一些。另外因为闸门信号是由被测时钟产生的,当测量频率较高的信号或者说信号频率大于10KHz(此值跟门控时间有关)时是不会有什么问题的,但当测量低频信号像Hz级这种,如果门控时间设置的大的话,测量时间就会非常长,此时可修改门控时间的值,为被测时钟频率的5~10倍即可,对于几十KHz及以上的时钟信号,门控时间的大小对测量速度的影响较小,频率越高影响越小,但对测量精度影响较大,因而在测量频率较高的信号时,建议增大门控时间。
代码中为了防止复位对测量造成的干扰,门控信号在复位后延迟了10个被测信号的周期(第55~58行)。另外计算被测信号频率是在基准时钟下的门控信号为低电平时进行。
建立了门控信号之后,我们需要通过门控信号分别使能基准时钟和被测时钟的计数。因为门控信号对基准时钟而言是异步信号,所以这里我们对门控信号进行了两次打拍处理得到基准频率下的门控信号gate_fs(代码第68行的always语句块)。在门控信号的下降沿将计数值寄存并清零计数寄存器。
在取得数值后,我们需要计算被测信号的频率值,由于在计算周期内数值已不再发生变化(计数值已寄存),而且保留了足够的计算时间,所以可以不用FIFO进行异步处理。计算完之后,把所得的结果赋给寄存器变量data_fx,其数值的单位为Hz。
到这里频率计实验的代码就讲解完了,关于数码管显示部分内容大家可以参考前面数码管显示的例程,这里不再作重复讲解。
至此,我们的设计部分已基本完成,现在我们来做一下误差分析。
(1-3)
其中clk_fxe为被测频率信号的准确值。
在测量中,由于clk_fx计数的起停时间都是由该信号的上升沿触发的,在闸门时间GATE_TIME内对clk_fx的计数fx_cnt无误差();对clk_fs的计数fs_cnt最多相差一个时钟的误差,即|Δfs_cnt|≤1,其测量频率如式(1-4):
(1-4)
将式(1-2)和(1-4)代入式(1-3),并整理如式
(1-5)
由上式可以看出,测量频率的相对误差与被测信号频率的大小无关,仅与闸门时间和基准时钟频率有关,即实现了整个测试频段的等精度测量。闸门时间越长,基准时钟频率越高,测频的相对误差就越小。基准时钟频率可由稳定度好、精度高的高频率晶体振荡器产生,在保证测量精度不变的前提下,提高基准时钟频率,可使闸门时间缩短,即提高测试速度。
29.5下载验证
编译工程并生成sof文件。将新起点开发板的N9引脚和P9引脚,用一根杜邦线或者跳帽连接起来,将下载器一端连电脑,另一端与开发板上的JTAG端口连接,连接电源线并打开电源开关。
下载完成后数码管上面显示“500000”,如下图所示,与时钟产生模块产生的时钟频率一致,等精度频率计实验下载验证成功。

图 29.5.2 实验结果
举报

更多回帖

发帖
×
20
完善资料,
赚取积分