基于OpenHarmony + 小凌派RK2206开发板制作的简易示波器,实时采集波形,实时计算并实时显示对应的波形。OpenHarmony实时性较高,稳定性好,瑞芯微RK2206芯片接口丰富,OpenHarmony芯片适配稳定性好,做出来的简易示波器效果还不错。本文先做第一期的技术文档,后续将持续完善功能和技术文档更新。
1
项目简介
本文基于OpenHarmony操作系统 + 小凌派RK2206开发板而做的简易示波器开发。
本开发以瑞芯微RK2206芯片 + OpenHarmony 3.0LTS操作系统 + 小凌派-RK2206开发板为基础,以模数转换芯片ADS1256为采集数据芯片实时采集,然后通过峰值检测和fft变换算法处理采集数据,最后将处理完成的数据输送到LCD液晶屏上实时显示。
项目实验视频如下所示:
2
模块介绍
1.ADS1256模块
ADS1256是一款 24bit ADC转换模块。ADS1256可以通过SPI进行访问 的高精度的转换器。
上图为ADS1256芯片结构和引脚图,从图可以看出ADS1256的通道资源比较丰富,可以配置成8个单端ADC通道,也可以配置成4个差分通道。ADS1256的通信接口为串行接口,同时还有4个通用的IO口,不过这四个IO口不经常用到。
ADS1256内部有许多寄存器需要配置,相较于ADS1232用起来要复杂的多。
下面介绍一下ADS1256的初始化。
通过SPI通信配置ADS1256的参数,增益以及转换速率。
void ADS1256_CfgADC(uint8_t gain,uint8_t drate) // 初始化设置,设置增益以及转换速率
{
uint8_t buf[4];
ADS1256_WriteCmd(CMD_RESET); // 写复位指令
ADS1256_WriteReg(REG_STATUS,0XF4); // 写状态,数据传输默认高位在前,启动矫正,禁止使用缓冲
ADS1256_WriteCmd(CMD_SELFCAL); // 自校准
ToyUdelay(20);
{
buf[0] = (0 << 3) | (1 << 2) | (0 << 1);
buf[1] = 0x08; //通道设置选择
buf[2] = (0 << 5) | (0 << 3) | (gain << 0);
buf[3] = drate; // DRATE_10SPS; /* 选择数据输出速率 */
CS_L;
ADS1256_Send8Bit(CMD_WREG|0); // 写寄存器
ADS1256_Send8Bit(0x03); // 连续写入4个数据
ADS1256_Send8Bit(buf[0]); // 设置状态寄存器
ADS1256_Send8Bit(buf[1]); // 设置输入通道参数
ADS1256_Send8Bit(buf[2]); // 设置ADCON控制寄存器,增益
ADS1256_Send8Bit(buf[3]); // 设置数据速率
CS_H;
}
ToyUdelay(50);
}
(左右移动查看全部内容)
然后选择通道0,等待数据转换完成后获取他采集的AD值
uint32_t ADS1256_GetAdc(uint8_t channel)
{
uint32_t read;
uint16_t val = 0;
read = 0;
// while(DRDY); //当DRDY变为低电平时,数据开始传输
ADS1256_WriteReg(REG_MUX,channel); // 写入读取的通道
ADS1256_WriteCmd(CMD_SYNC); //同步A/D转换命令
// Delay_1us(1);
ADS1256_WriteCmd(CMD_WAKEUP); //完成SYNC并退出待机模式
GpioGetVal(DRDY, &val);
while(val==1) // 等待数据转换完成
{
GpioGetVal(DRDY, &val);
}
CS_L; //片选拉低
ADS1256_Send8Bit(CMD_RDATA); //读取数据命令
//连续接收3个数据,高字节在前
read = ((uint32_t)ADS1256_Recive8Bit() << 16);
read +=( (uint32_t)ADS1256_Recive8Bit() << 8);
read += ADS1256_Recive8Bit() ;
CS_H;
return read;
}
(左右移动查看全部内容)
2.LCD液晶屏模块
本项目使用的是ST7789V, 用于单片驱动262K色图像TFT-LCD, 包含 720(240*3色) x 320 线输出, 可以直接以SPI协议, 或者8位/9位/16位/18位并行连接外部控制器。ST7789V显示数据存储在片内240x320x18 bits内存中, 显示内存的读写不需要外部时钟驱动。
具体接线如下图所示:
其中,LCD液晶屏引脚功能描述,如下表5.3.1所示。
表5.3.1 LCD液晶屏引脚功能表:
其中,LCD液晶屏与小凌派-RK2206开发板连接如下图所示:
3
简易示波器功能的实现
1.峰值检测
通过查找ad采集的数据内的最大值和最小值,然后相减即得峰峰值。
float Get_Vpp(float arr[])
{
uint16_t i;
float MAX=0,MIN=3500,Vpp=0;
for(i=0;i
"" ="" 扫描adc数组,获取最大值和最小值{
if(arr[i]>MAX)
MAX=arr[i];
if(arr[i]
MIN=arr[i];
}
Vpp=MAX-MIN;
return Vpp;
}
(左右移动查看全部内容)
2.频率检测
通过fft变换,FFT变换的数据需要两部分,实部和虚部,由于变换的是数据是AD采集的实数据,所以只需将采集的值存入实部,虚部存入零即可。通过变换将时域信号转换到频域,然后通过取模排序,然后计算即可得到频率。他的基本思想是把原始的 N 点序列,依次分解成一系列的短序列。充分利用 DFT 计算式中指数因子所具有的对称性质和周期性质,进而求出这些短序列相应的 DFT 并进行适当组合,达到删除重复计算,减少乘法运算和简化结构的目的。当N是素数时,可以将 DFT算转化为求循环卷积,从而更进一步减少乘法次数,提高速度。
(1)FFT变换函数
oid fft(const float real_in[], const float imag_in[], float real_out[], float imag_out[], const int n, int isign) {
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)取模运算函数
void PowerMag(void)
{
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变换的幅值进行排序,同时也对他们的下标进行了排序,以便后续的计算,即除了直流信号的第一个频率点即为改信号的频率。
void sorting (void)
{
uint16_t i,j;
uint32_t temp1;
for(i=0;i
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]
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变换后所对应的幅值最大点的下标前移,导致计算频率时候会偏小。
fre=Fs*xb[1]*1.47/Ns;
(左右移动查看全部内容)
3.波形显示
通过将采集的幅值进行计算,使最后的值在屏幕大小的范围内,进行描点画图。
void drawCurve( float rawValue,uint16_t color)
{
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
4
心得体会
通过OpenHarmony操作系统 + 小凌派-RK2206开发板进行项目开发,OpenHarmony的实时性好,稳定性高,瑞芯微RK2206芯片接口比较丰富,移植适配稳定性较好,整体开发进度比较顺利,开发的难度都集中在数据处理算法上。通过这一次的应用开发,整体上对OpenHarmony和国产芯片开发还是蛮认可的,是一次不错的学习体验,特此记录!
原文标题:基于OpenHarmony操作系统的简易示波器开发心得
文章出处:【微信公众号:HarmonyOS官方合作社区】欢迎添加关注!文章转载请注明出处。
全部0条评论
快来发表一下你的评论吧 !