• 基于FPGA的测频系统+上位机


    【1】本设计的要求:

    • 利用FPGA实现频率计,要求2秒内测出外部频率,并且2秒更新一次值;
    • 实现100MHz频率的测量;
    • 测量结果通过串口921600bps发送给PC;
    • 发送格式为:FFCB0176543210,其中FFCB01为帧头,76543210(即0x76543210)为频率值,数据在上位机中转换成十进制并用合适的单位(MHz、KHz、Hz)表示;
    • 完善上位机。

    【2】现在就来说说我是如何实现上述条件的。对于第一个条件“2秒内测出频率并2秒更新一次”,很明显这是连续、实时的测量过程。跟我们经常看过的“一个占空比为50%、周期为4秒的方波,在其高电平时测试频率”完全不同,当然它也可以测出频率,但达不到连续测量的要求。为了实现该要求,我们得采取另一种思路,就是两个间隔2秒的脉冲之间进行频率的测量,如下图所示:

    1

    实现代码(时钟为100MHz,clkin为待测频的信号):

    //---------------------------------------
    localparam      Threshod_Delay = 29'd500000000;    //2s
    reg   [28:0]    cnt1;
    reg             cnt_en;
    
    always @(posedge clk_ref or negedge sys_rst_n)
    begin
        if(!sys_rst_n)
            begin
            cnt1   <= 0;
            cnt_en <= 0;
            end
        else
            begin
            if(cnt1 < Threshod_Delay)
                begin
                cnt1   <= cnt1 + 1'b1;
                cnt_en <= 1'b0;
                end
            else
                begin
                cnt1   <= 0;
                cnt_en <= 1'b1;
                end
            end
    end
    //---------------------------------------
    reg    clkin_buf1;
    reg    clkin_buf2;
    
    always @(posedge clk_ref or negedge sys_rst_n)
    begin
        if(!sys_rst_n)
            begin
            clkin_buf1 <= 1;
            clkin_buf2 <= 1;
            end
        else
            begin
            clkin_buf1 <= clkin;
            clkin_buf2 <= clkin_buf1;
            end
    end
    
    wire  pos_flag = clkin_buf1 && ~clkin_buf2;
    //---------------------------------------
    reg    [31:0]    freqdata;
    reg    [31:0]    freout;
    reg              flag1;
    
    always @(posedge clk_ref or negedge sys_rst_n)
    begin
        if(!sys_rst_n) 
            begin
            freqdata <= 0;
            flag1    <= 0;
            freout   <= 0;
            end
        else
            begin
                if(cnt_en)
                    begin
                    freout   <= freqdata >> 1;
                    flag1    <= cnt_en;
                    freqdata <= 0;
                    end
                else
                    begin
                    if(pos_flag)
                        freqdata <= freqdata + 1'b1;
                    else
                        freqdata <= freqdata;
                    freout <= freout;
                    flag1  <= 0;
                    end
            end
    end

    在上面的设计中涉及到了一种很重要的思想即边沿检测。所谓边沿检测,就是检测外部输入信号或FPGA内部逻辑信号的跳变,即上升沿或下降沿的捕获。通过边沿检测实现使能时钟,避免了时钟满天飞,同时提高了时序电路的稳定性。边沿检测功能实现之前,我们必须对它在时序上的理解。当上一时刻为低电平,当前时刻为高电平时为上升沿;当上一时刻为高电平,当前时刻为低电平时为下降沿。

    (1)上升沿的检测

    reg DataInBuf1;
    reg DataInBuf2;
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            begin
            DataInBuf1 <= 1'b1;
            DataInBuf2 <= 1'b1;
            end
        else
            begin
            DataInBuf1 <= DataIn;
            DataInBuf2 <= DataInBuf1;
            end
    end
    
    wire pos_flag = DataInBuf1 && ~DataInBuf2;

    (2)下降沿的检测

    reg DataInBuf1;
    reg DataInBuf2;
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            begin
            DataInBuf1 <= 1'b0;
            DataInBuf2 <= 1'b0;
            end
        else
            begin
            DataInBuf1 <= DataIn;
            DataInBuf2 <= DataInBuf1;
            end
    end
    
    wire neg_flag = ~DataInBuf1 && DataInBuf2;

    【3】对于第二个条件”实现100MHz频率的测量”,必须满足采样定理即采样率大于等于200MHz,而本设计的采样取250MHz。

    【4】对于第三个条件“测量结果通过串口921600bps发送给PC”,首先要设计一个UART发送端,波特率为921600,然后将32位宽的测量结果并加上帧头FFCB01以字节为单位进行发送,其核心代码如下:

    //---------------------------------------
    reg    [7:0]    Din;
    reg    [2:0]    state;
    reg             flag2;
    reg             flag3;
    
    always @(posedge clk_ref or negedge sys_rst_n)
    begin
        if(!sys_rst_n)
            begin
            Din   <= 0;
            state <= 0;
            flag2 <= 0;
            flag3 <= 0;
            end
        else
            begin
            if(flag1)
                flag2 <= 1;
            else 
                begin
                if(flag && flag2)
                    begin
                    case(state)
                    3'd0 :
                        begin
                        Din   <= 8'hFF;
                        state <= 3'd1;
                        end
                    3'd1 :
                        begin
                        Din   <= 8'hCB;
                        state <= 3'd2;
                        end
                    3'd2 : 
                        begin
                        Din   <= 8'h01;
                        state <= 3'd3;
                        end
                    3'd3 : 
                        begin
                        Din   <= freout[31:24];
                        state <= 4;
                        end
                    3'd4 : 
                        begin
                        Din   <= freout[23:16];
                        state <= 5;
                        end
                    3'd5 : 
                        begin
                        Din   <= freout[15:8];
                        state <= 6;
                        end
                    3'd6 : 
                        begin
                        Din   <= freout[7:0];
                        flag2 <= 0;
                        state <= 0;
                        end
                    default : state <= 3'd0;
                    endcase
                    flag3 <= flag;
                    end
                else
                    begin
                    Din   <= Din;
                    state <= state;
                    flag3 <= 0;
                    end
                end
            end
    end

    【5】第四个条件“数据在上位机中转换成十进制并用合适的单位(MHz、KHz、Hz)表示”,该上位机使用VC++6.0实现,该条件部分实现代码如下:

    // 计算频率值
    switch(index)
    {
        case 0:
            if(bt == 0xff)    index = 1;
            break;
        case 1:
            if(bt == 0xcb)    index = 2;
            else index = 0;
            break;
        case 2:
            if(bt == 0x01)    {index = 3;result = 0;}
            else index = 0;
            break;
        case 3:
            m_RevStr = m_RevStr + _T("FF CB 01 ") + strtemp;
            result += bt*16*16*16*16*16*16;
            index    = 4;
            break;
        case 4:
            m_RevStr = m_RevStr + strtemp;
            result += bt*16*16*16*16;
            index    = 5;
            break;
        case 5:
            m_RevStr = m_RevStr + strtemp;
            result += bt*16*16;
            index    =6;
            break;
        case 6:
            m_RevStr = m_RevStr + strtemp;
            AddToInfOut(m_RevStr,TRUE,TRUE);
            result += bt;
            if(flag == TRUE)
            {
                if((1000000 <= result) && (result <= 2147483647))
                {
                    result /= 1000000;
                    szFre.Format("%0.2lf",result);
                    m_Frequst.SetWindowText(szFre+"MHz");
                }
                else if((1000 <= result) && (result < 999999))
                {
                    result /= 1000;
                    szFre.Format("%0.2lf",result);
                    m_Frequst.SetWindowText(szFre+"KHz");
                }
                else if((0 <= result) && (result<= 999))
                {
                    szFre.Format("%0.2lf",result);
                    m_Frequst.SetWindowText(szFre+"Hz");
                }
            }    
            m_RevStr="";
            index    = 0;
            break;
        default:
            index = 0;
            break;
    }

    【6】最后,完成的上位机“测频系统”效果如下:

    2

    【7】完成了测频电路和上位机的设计后,接下来就是调试了。由于我没有条件提供外部信号进行测频,于是采取了调用IP核PLL来产生待测信号(可通过按键进行选择),其例化代码如下:

    system_ctrl_pll u_system_ctrl_pll
    (
        //global clock
        .clk      (clk      ),
        .rst_n    (rst_n    ),
    
        //synced signal
        .clk_c0   (clk_ref  ),  //clock output,250MHz    
        .clk_c1   (clkin1   ),  //100MHz
        .clk_c2   (clkin2   ),  //83.333333MHz
        .clk_c3   (clkin3   ),  //66.666667MHz
        .clk_c4   (clkin4   ),  //33.333333MHz
        .sys_rst_n(sys_rst_n)   //system reset
    );

    测试结果如下:

    3

    4

    6

    经过调试,该设计是符合条件的。

    【8】虽然没有把该设计很详细的写出来,但是重要的是思路。哈哈,明天去公司报道,今晚就不再折腾了,早点睡觉,晚安*^_^*

     
  • 相关阅读:
    《 基于UML技术的体育场馆管理系统设计与研究 》随笔
    《暗时间》读后感
    HTML 全局属性
    html简介
    Django中使用多线程发送邮件
    ubuntulinux 更改时区设置时间
    git 提交运用vim编辑器
    git配置
    网页显示403. That’s an error的解决方法。
    js 给url添加时间戳 解决浏览器缓存
  • 原文地址:https://www.cnblogs.com/CrazyBirdLin/p/4319623.html
Copyright © 2020-2023  润新知