[文章]基于OpenHarmony操作系统的简易示波器开发心得(下)

阅读量0
0
4
三、简易示波器功能的实现
1.峰值检测
通过查找ad采集的数据内的最大值和最小值,然后相减即得峰峰值。
  1. float Get_Vpp(float arr[])
  2. {
  3.         uint16_t i;
  4.         float MAX=0,MIN=3500,Vpp=0;
  5.         for(i=0;i<Ns;i++)                    // 扫描ADC数组,获取最大值和最小值
  6.         {
  7.             if(arr[i]>MAX)         
  8.                 MAX=arr[i];
  9.             if(arr[i]<MIN)
  10.                 MIN=arr[i];
  11.         }
  12.         Vpp=MAX-MIN;
  13.         return Vpp;
  14. }
复制代码

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

(1)FFT变换函数
  1. oid fft(const float real_in[], const float imag_in[], float real_out[], float imag_out[], const int n, int isign) {
  2.     if (isign != 1 && isign != -1) {//isign=1,正变换;isign=-1,逆变换
  3.         return;
  4.     }
  5.     const int Lv = mylog(n, 2);//蝶形级数
  6.     int L;//蝶形运算级数,用于循环
  7.     int N;//蝶形运算数据量,用于循环
  8.     int distance;//蝶形运算两节点间的距离,用于循环(distance=N/2)
  9.     int group;//蝶形运算的组数
  10.     float tmpr1, tmpi1, tmpr2, tmpi2;//临时变量
  11.     int i, j, k;
  12.     for (i = 0; i < n; i++) {//数位倒读
  13.         j = rev(i, Lv);
  14.         real_out[j] = real_in[i];
  15.         imag_out[j] = imag_in[i];
  16.     }
  17.     L = 1;
  18.     distance = 1;
  19.     N = 2;
  20.     group = n >> 1;
  21.     for (; L <= Lv; L++) {//蝶形循环
  22.         for (i = 0; i < group; i++) {//每级蝶形各组循环
  23.             for (k = 0; k < distance; k++) {//每组蝶形运算
  24.                 float theta = -2 * PI * k / N * isign;//旋转因子,逆变换的角度与正变换相反
  25.                 tmpr1 = real_out[N * i + k];
  26.                 tmpi1 = imag_out[N * i + k];//X(k)
  27.                 tmpr2 = mycos(theta) * real_out[N * i + k + distance] - mysin(theta) * imag_out[N * i + k + distance];
  28.                 tmpi2 = mycos(theta) * imag_out[N * i + k + distance] + mysin(theta) * real_out[N * i + k + distance];//WN(k)*X(k+N/2)
  29.                 real_out[N * i + k] = tmpr1 + tmpr2;
  30.                 imag_out[N * i + k] = tmpi1 + tmpi2;//X(k)=X(k)+WN(K)*X(k+N/2)
  31.                 real_out[N * i + k + distance] = tmpr1 - tmpr2;
  32.                 imag_out[N * i + k + distance] = tmpi1 - tmpi2;//X(k+N/2)=X(k)-WN(K)*X(k+N/2)
  33.                 if (isign == -1) {//逆变换结果需除以N,即除以Lv次2
  34.                     real_out[N * i + k] *= 0.5;
  35.                     imag_out[N * i + k] *= 0.5;
  36.                     real_out[N * i + k + distance] *= 0.5;
  37.                     imag_out[N * i + k + distance] *= 0.5;
  38.                 }
  39.             }
  40.         }
  41.         N <<= 1;
  42.         distance <<= 1;
  43.         group >>= 1;
  44.     }
  45. }
复制代码
(2)取模运算函数
  1. void PowerMag(void)
  2. {
  3.     uint16_t i=0;
  4.     float Y,X,Mag;
  5.   for (i=0; i < Ns/2; i++)
  6.   {
  7.    
  8.        X =((float)y2r[i])/32768* Ns;
  9.        Y = ((float)y2i[i])/32768* Ns;
  10.        Mag = sqrt(X*X+ Y*Y)/Ns;         // 先平方和,再开方
  11.        y2[i] = (uint32_t)(Mag*65536);           
  12.    
  13.   }
  14.   y2[0] = y2[0]/2;      //直流
  15. }
复制代码
(3)然后将FFT变换的幅值进行排序,同时也对他们的下标进行了排序,以便后续的计算,即除了直流信号的第一个频率点即为改信号的频率。
  1. void sorting (void)
  2. {
  3.     uint16_t i,j;
  4.     uint32_t temp1;
  5.    
  6.     for(i=0;i<Ns/2;i++)                     //下标赋初值
  7.     {
  8.         xb[i]=i;
  9.     }
  10.     for(j=0;j<(Ns/2-1);j++)                 // 冒泡排序
  11.      {
  12.         for(i=1;i<(Ns/2-j-1);i++)       //直流项不参与排序  从第二项开始              
  13.         {
  14.             if(y2[i]<y2[i+1])
  15.             {               
  16.                 temp1=y2[i];                //交换数据
  17.                 y2[i]=y2[i+1];
  18.                 y2[i+1]=temp1;

  19.                 temp1=xb[i];                            //交换下标
  20.                 xb[i]=xb[i+1];
  21.                 xb[i+1]=temp1;
  22.             }        
  23.         }                                                               
  24.      }
  25. }
复制代码
(4)通过计算即可得到频率,采样点数将采样频率进行平分,通过排序取得的幅值最大的那个点的下标进行相乘即为频率,1.47为补偿系数,因为ADS1256采集数据后有延时,导致进行FFT变换后所对应的幅值最大点的下标前移,导致计算频率时候会偏小。
  1. fre=Fs*xb[1]*1.47/Ns;
复制代码

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

  1. void drawCurve( float rawValue,uint16_t color)  
  2. {
  3.     uint16_t x;
  4.     int y;
  5.     y = (int) rawValue/30+30;   //data processing code
  6.     if(y<0 || y > 240)
  7.     y = lastY;
  8.     //这里之所以是120-rawValue/280,与屏幕的扫描方向有关,如果出现上下颠倒的情况,可以改成120 +
  9.     if(firstPoint)//如果是第一次画点,则无需连线,直接描点即可
  10.     {
  11.         LCD_DrawPoint(0,y,color);
  12.         lastX=0;
  13.         lastY=y;
  14.         firstPoint=0;
  15.     }
  16.     else
  17.     {
  18.         x=lastX+2;
  19.         if(x<320)  //不超过屏幕宽度
  20.         {
  21.             LCD_DrawLine(lastX,lastY,x,y,color);
  22.             lastX=x;
  23.             lastY=y;
  24.         }
  25.         else  //超出屏幕宽度,清屏,从第一个点开始绘制,实现动态更新效果
  26.         {
  27.             //LCD_Fill(0, 0, LCD_W, LCD_H, LCD_WHITE);//清屏//清屏,白色背景
  28.             LCD_DrawPoint(0,y,color);
  29.             lastX=0;
  30.             lastY=y;
  31.         }
  32.   }
  33. }
复制代码
4.LCD显示
Gitee社区已有这部分源代码和说明文档,感兴趣的读者可以参考:https://gitee.com/Lockzhiner-Ele ... 2206/samples/b4_lcd

四、心得体会
通过OpenHarmony操作系统 + 小凌派-RK2206开发板进行项目开发,OpenHarmony的实时性好,稳定性高,瑞芯微RK2206芯片接口比较丰富,移植适配稳定性较好,整体开发进度比较顺利,开发的难度都集中在数据处理算法上。通过这一次的应用开发,整体上对OpenHarmony和国产芯片开发还是蛮认可的,是一次不错的学习体验,特此记录!


回帖

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
链接复制成功,分享给好友