基于OpenHarmony操作系统的简易示波器开发心得(下) 原创
三、简易示波器功能的实现
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和国产芯片开发还是蛮认可的,是一次不错的学习体验,特此记录!