在简易示波器中计算波形频率不用fft!!!

文章目录


前言

最近在做一个简易示波器项目在计算输入波形的频率时想了很多方案比如傅里叶变换、利用定时器的捕获功能去捕获信号的频率等等,但是看到其他大神做的示波器里面测波形频率的方法是利用触发点去测波形的频率,这种方法非常实用,下面我将为大家介绍一下这种方法。


一、简介

利用stm32单片机的ADC采集外部输入电压信号,并将其采集的数据组成一个数组在数组中找到其最大值和最小值,并求其最大值和最小值的均值将其作为波形的触发值,然后从数组中中间开始寻找与触发值相符的点,然后再从这个点分别向左和向右查找该点的等值点记录其位置,求其差值A,将数组依据时间的顺序分为四等份或者多等份将每一份的真实时间为T利用公式即Freq = 25 000/(T*|A|) Freq = 25 000 000/(T*|A|)(前者T单位为毫秒,后者T的单位为微秒,但是必须是是大于零的整数)可计算出波形的频率

二、代码

1.波长计算部分

代码如下:

/* 获取触发点位置
   Get Trigger Position */
u8 GetTriggerPos(u16 d1, u16 d2, u16 dTrigger, u8 triSlope)  //d1为i值,d2为i+1值
{
    /*  上升沿触发
        Trigger on Rising Edge  */
    if (triSlope)
    {
        if (d1 <= dTrigger && d2 >= dTrigger)
        {
            return 1;
        }
    }

    /*  下降沿触发
        Trigger on Falling Edge */
    else
    {
        if (d1 >= dTrigger && d2 <= dTrigger)
        {
            return 1;
        }
    }

    return 0;
}
/* 计算波长
   Calculate wave length*/
u8 getWaveLength(u16 triLevel, u8 right_or_left)//trilevel为触发值 right_or_left为查找方向
{
    u16 i;
    u8 tri_pre = 255;
    u8 tri_aft = 255;
    u8 triPos_tmp;
    u8 triSlope_tmp;
    u8 triFail = 1;
    /* 查找距离屏幕中心最近的触发点
       Search the trigger poiont closest to the center of chart */
    if (right_or_left) //向右查找临时触发点 / Search right side
    {
        for (i = TriPos ; i < N_simple_interval - 2; i++)   //TriPos为触发点位置  N_simple_interval为采样点数
        {
            if (GetTriggerPos(*(waveBuf + i), *(waveBuf + i + 1), triLevel, 1)) //按上升沿查找 / Search on rising edge
            {
                triPos_tmp = i;
                triSlope_tmp = 1;
                triFail = 0;
                break;
            }
            else if (GetTriggerPos(*(waveBuf + i), *(waveBuf + i + 1), triLevel, 0)) //按下降沿查找 / Search on falling edge
            {
                triPos_tmp = i;
                triSlope_tmp = 0;
                triFail = 0;
                break;
            }
        }
    }
    else //向左查找临时触发点 / Search left side
    {
        for (i = TriPos + TriPosOffset; i > 0; i--)
        {
            if (GetTriggerPos(*(waveBuf + i), *(waveBuf + i + 1), triLevel, 1)) //按上升沿查找 / Search on rising edge
            {
                triPos_tmp = i;
                triSlope_tmp = 1;
                triFail = 0;
                break;
            }
            else if (GetTriggerPos(*(waveBuf + i), *(waveBuf + i + 1), triLevel, 0)) //按下降沿查找 / Search on falling edge
            {
                triPos_tmp = i;
                triSlope_tmp = 0;
                triFail = 0;
                break;
            }
        }
    }

    if (!triFail)
    {
        for (i = triPos_tmp; i >= 0; i--) //查询触发位置左侧的等值点 / Search equal point left side
        {
            if (triSlope_tmp) //上升触发,查找下降点 / Trigger on rising edge, search on falling edge
            {
                if (*(waveBuf + i) >= triLevel && *(waveBuf + i + 1) <= triLevel)
                {
                    tri_pre = i;
                    break;
                }
            }
            else //下降触发,查找上升点 / Trigger on falling edge, search on rising edge
            {
                if (*(waveBuf + i) <= triLevel && *(waveBuf + i + 1) >= triLevel)
                {
                    tri_pre = i;
                    break;
                }
            }
        }

        for (i = triPos_tmp; i < N_simple_interval - 1; i++) //查询触发位置右侧的等值点 / Search equal point right side
        {
            if (triSlope_tmp) //上升触发,查找下降点 / Trigger on rising edge, search on falling edge
            {
                if (*(waveBuf + i) >= triLevel && *(waveBuf + i + 1) <= triLevel)
                {
                    tri_aft = i;
                    break;
                }
            }
            else //下降触发,查找上升点 / Trigger on falling edge, search on rising edge
            {
                if (*(waveBuf + i) <= triLevel && *(waveBuf + i + 1) >= triLevel)
                {
                    tri_aft = i;
                    break;
                }
            }
        }
    }
    if (tri_pre == 255 || tri_aft == 255 || (tri_pre == tri_aft))
    {
        WaveLength = 0;
        return 0;
    }
    else
    {
        WaveLength = tri_aft - tri_pre;
        return 1;
    }
}

2.频率计算部分

switch (Freq_N)
    {
    case 0:                                      //500ms时间区间
        WaveFreq = (float)50 / WaveLength + 0.5; //WaveFreq=25000/(500*WaveLength);
        break;

    case 1:                          //200ms时间区间
        WaveFreq = 125 / WaveLength; //WaveFreq=25000/(200*WaveLength);
        break;

    case 2:                          //100ms时间区间
        WaveFreq = 250 / WaveLength; //WaveFreq=25000/(100*WaveLength);
        break;

    case 3:                          //50ms时间区间
        WaveFreq = 500 / WaveLength; //WaveFreq=25000/(50*WaveLength);
        break;

    case 4:                           //20ms时间区间
        WaveFreq = 1250 / WaveLength; //WaveFreq=25000/(20*WaveLength);
        break;

    case 5:                           //10ms时间区间
        WaveFreq = 2500 / WaveLength; //WaveFreq=25000/(10*WaveLength);
        break;

    case 6:                           //5ms时间区间
        WaveFreq = 5000 / WaveLength; //WaveFreq=25000/(5*WaveLength);
        break;

    case 7:                            //2ms时间区间
        WaveFreq = 12500 / WaveLength; //WaveFreq=25000/(2*WaveLength);
        break;

    case 8:                            //1ms时间区间
        WaveFreq = 25000 / WaveLength; //WaveFreq=25000/(1*WaveLength);
        break;

    case 9:                            //500us时间区间
        WaveFreq = 50000 / WaveLength; //WaveFreq=25000000/(500*WaveLength);
        break;

    case 10:                            //200us
        WaveFreq = 125000 / WaveLength; //WaveFreq=25000000/(200*WaveLength);
        break;

    case 11:                            //100us时间区间
        WaveFreq = 250000 / WaveLength; //WaveFreq=25000000/(100*WaveLength);
        break;

总结

以上就是在简易示波器中利用触发点计算波形频率的方法在采样点足够的情况下,可以对频率进行精确的计算,频率受单位时间区间以及采样点数的影响很大。

上一篇:频谱细化-----Zoom-FFT算法介绍及MATLAB实现


下一篇:P4173-残缺的字符串【FFT】