基于OpenHarmony操作系统的简易示波器开发心得(下) -鸿蒙开发者社区-51CTO.COM

基于OpenHarmony操作系统的简易示波器开发心得(下) 原创

福州市凌睿智捷电子有限公司
发布于 2022-5-6 13:36
浏览
0收藏

三、简易示波器功能的实现
1.峰值检测
通过查找ad采集的数据内的最大值和最小值,然后相减即得峰峰值。

{
        uint16_t i;
        float MAX=0,MIN=3500,Vpp=0; 
        for(i=0;i<Ns;i++)                    // 扫描ADC数组,获取最大值和最小值
        {
            if(arr[i]>MAX)          
                MAX=arr[i];
            if(arr[i]<MIN)
                MIN=arr[i];
        }
        Vpp=MAX-MIN;
        return Vpp;
}

2.频率检测
通过FFT变换,FFT变换的数据需要两部分,实部和虚部,由于变换的是数据是AD采集的实数据,所以只需将采集的值存入实部,虚部存入零即可。通过变换将时域信号转换到频域,然后通过取模排序,然后计算即可得到频率。他的基本思想是把原始的 N 点序列,依次分解成一系列的短序列。充分利用 DFT 计算式中指数因子所具有的对称性质和周期性质,进而求出这些短序列相应的 DFT 并进行适当组合,达到删除重复计算,减少乘法运算和简化结构的目的。当N是素数时,可以将 DFT算转化为求循环卷积,从而更进一步减少乘法次数,提高速度。
(1)FFT变换函数

    if (isign != 1 && isign != -1) {//isign=1,正变换;isign=-1,逆变换 
        return;
    }
    const int Lv = mylog(n, 2);//蝶形级数 
    int L;//蝶形运算级数,用于循环
    int N;//蝶形运算数据量,用于循环 
    int distance;//蝶形运算两节点间的距离,用于循环(distance=N/2) 
    int group;//蝶形运算的组数 
    float tmpr1, tmpi1, tmpr2, tmpi2;//临时变量
    int i, j, k;
    for (i = 0; i < n; i++) {//数位倒读 
        j = rev(i, Lv);
        real_out[j] = real_in[i];
        imag_out[j] = imag_in[i];
    }
    L = 1;
    distance = 1;
    N = 2;
    group = n >> 1;
    for (; L <= Lv; L++) {//蝶形循环 
        for (i = 0; i < group; i++) {//每级蝶形各组循环 
            for (k = 0; k < distance; k++) {//每组蝶形运算 
                float theta = -2 * PI * k / N * isign;//旋转因子,逆变换的角度与正变换相反 
                tmpr1 = real_out[N * i + k];
                tmpi1 = imag_out[N * i + k];//X(k)
                tmpr2 = mycos(theta) * real_out[N * i + k + distance] - mysin(theta) * imag_out[N * i + k + distance];
                tmpi2 = mycos(theta) * imag_out[N * i + k + distance] + mysin(theta) * real_out[N * i + k + distance];//WN(k)*X(k+N/2)
                real_out[N * i + k] = tmpr1 + tmpr2;
                imag_out[N * i + k] = tmpi1 + tmpi2;//X(k)=X(k)+WN(K)*X(k+N/2)
                real_out[N * i + k + distance] = tmpr1 - tmpr2;
                imag_out[N * i + k + distance] = tmpi1 - tmpi2;//X(k+N/2)=X(k)-WN(K)*X(k+N/2)
                if (isign == -1) {//逆变换结果需除以N,即除以Lv次2 
                    real_out[N * i + k] *= 0.5;
                    imag_out[N * i + k] *= 0.5;
                    real_out[N * i + k + distance] *= 0.5;
                    imag_out[N * i + k + distance] *= 0.5;
                }
            }
        }
        N <<= 1;
        distance <<= 1;
        group >>= 1;
    }
}

(2)取模运算函数

{
    uint16_t i=0;
    float Y,X,Mag;
  for (i=0; i < Ns/2; i++)
  {
    
       X =((float)y2r[i])/32768* Ns;
       Y = ((float)y2i[i])/32768* Ns;
       Mag = sqrt(X*X+ Y*Y)/Ns;         // 先平方和,再开方
       y2[i] = (uint32_t)(Mag*65536);           
    
  }
  y2[0] = y2[0]/2;      //直流
}

(3)然后将FFT变换的幅值进行排序,同时也对他们的下标进行了排序,以便后续的计算,即除了直流信号的第一个频率点即为改信号的频率。

{
    uint16_t i,j;
    uint32_t temp1;
    
    for(i=0;i<Ns/2;i++)                     //下标赋初值
    {
        xb[i]=i;
    }
    for(j=0;j<(Ns/2-1);j++)                 // 冒泡排序
     { 
        for(i=1;i<(Ns/2-j-1);i++)       //直流项不参与排序  从第二项开始              
        { 
            if(y2[i]<y2[i+1]) 
            {               
                temp1=y2[i];                //交换数据
                y2[i]=y2[i+1]; 
                y2[i+1]=temp1;

                temp1=xb[i];                            //交换下标
                xb[i]=xb[i+1]; 
                xb[i+1]=temp1; 
            }        
        }                                                               
     }
}

(4)通过计算即可得到频率,采样点数将采样频率进行平分,通过排序取得的幅值最大的那个点的下标进行相乘即为频率,1.47为补偿系数,因为ADS1256采集数据后有延时,导致进行FFT变换后所对应的幅值最大点的下标前移,导致计算频率时候会偏小。

3.波形显示
通过将采集的幅值进行计算,使最后的值在屏幕大小的范围内,进行描点画图。

{
    uint16_t x;
    int y;
    y = (int) rawValue/30+30;   //data processing code
    if(y<0 || y > 240)
    y = lastY;
    //这里之所以是120-rawValue/280,与屏幕的扫描方向有关,如果出现上下颠倒的情况,可以改成120 + 
    if(firstPoint)//如果是第一次画点,则无需连线,直接描点即可
    {
        LCD_DrawPoint(0,y,color);
        lastX=0;
        lastY=y;
        firstPoint=0;
    }
    else
    {
        x=lastX+2;
        if(x<320)  //不超过屏幕宽度
        {
            LCD_DrawLine(lastX,lastY,x,y,color);
            lastX=x;
            lastY=y;
        }
        else  //超出屏幕宽度,清屏,从第一个点开始绘制,实现动态更新效果
        {
            //LCD_Fill(0, 0, LCD_W, LCD_H, LCD_WHITE);//清屏//清屏,白色背景
            LCD_DrawPoint(0,y,color);
            lastX=0;
            lastY=y;
        }
  }
}

4.LCD显示
Gitee社区已有这部分源代码和说明文档,感兴趣的读者可以参考:https://gitee.com/Lockzhiner-Electronics/lockzhiner-rk2206-openharmony3.0lts/tree/master/vendor/lockzhiner/rk2206/samples/b4_lcd。
四、心得体会
通过OpenHarmony操作系统 + 小凌派-RK2206开发板进行项目开发,OpenHarmony的实时性好,稳定性高,瑞芯微RK2206芯片接口比较丰富,移植适配稳定性较好,整体开发进度比较顺利,开发的难度都集中在数据处理算法上。通过这一次的应用开发,整体上对OpenHarmony和国产芯片开发还是蛮认可的,是一次不错的学习体验,特此记录!

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2023-2-2 10:23:09修改
收藏
回复
举报
回复
    相关推荐