软件示波器PID调试技巧、无线调参
在整定PID参数时,网上的教程都是说怎么看波形,怎么根据波形来改变参数。也就是说想要更好的调试PID能够看到数据才能够更好的整定参数。
这篇文章介绍了如何使用开源的一个软件示波器,怎么设定通信协议和解析数据,以及如何搭建无线调参环境。
文章目录
1 准备内容
下面提到的内容如果不想自己去找的话,可以下载我打包好的资料包:
https://download.csdn.net/download/xia3976/72159998
1.1 软件示波器
网上也有很多软件示波器,我习惯于使用这一款开源的软件示波器。它有下面的特点
- 可以鼠标框选放大
- 可以自己设定通信协议
- 可以自己设定通道数量,显示长度,缓存区大小
- 可以向设备发送指令
- 可以显示或者隐藏某一条线
- 可以录屏,导出数据
软件开源地址: https://hackaday.io/project/5334-serialplot-realtime-plotting-software
github地址链接: https://github.com/hyOzd/serialplot
下载的话,进入这个链接:https://hackaday.io/project/5334-serialplot-realtime-plotting-software
如果是windows版本,下载下图这个即可
1.2 数据传输方式
- 如果要无线调参则需要一对已经配对好的HC-05蓝牙模块。HC-05蓝牙模块可以淘宝购买,配对教程可以看这篇文章
https://blog.csdn.net/xia3976/article/details/122199162?spm=1001.2014.3001.5501
连接方式如下所示:
-
如果有线调参的话
就不需要蓝牙模块了,直接连接将单片机的串口(TTL电平信号)通过TTL转USB的模块接到电脑上即可
- 只要用到USB-TTL模块或者CH340芯片,就需要安装CH340驱动
2 软件使用介绍
2.1 连接串口设备
首先需要设置串口参数,然后选择到1.2中连接的串口,并且点击open
2.2 设置通信协议
2.3 波形显示设置
2.4 发送指令
2.5 其他功能
还有一些其他没有介绍的功能,自己探索一下吧。
3 STM32示例发送数据程序
完整例程在资料包中
单片机中发送数据的程序,使用的通信协议需要和第2.2节中设置的通信协议一样才行。
-
例程使用的芯片是STM32F103RBT6,串口1
-
例程使用STM32标准库开发
-
STM32的串口初始化过程请自行百度,这里使用的是串口1
-
需要包含头文件
#include<string.h>
1、封装的发送数据的函数(驱动函数)
//addr 要发送的数组的首地址
//size 数据长度
void Usart1_SendNByte(u8* addr,int size)
{
while(size--)
{
while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET);//等待发送完成,STM32标准库函数
USART_SendData(USART1,*addr);//发送数据 ,STM32标准库函数
addr++; //地址偏移
}
}
2、实现发送功能的函数
这里的帧头,数据通道数量,数据类型都需要和软件示波器中设置的相对应。通道数量和类型、帧头都可以自己设定,只需要保证两边一样就行。
void SendWave(void)
{
u8 temp[] = {0x41,0x42,0x43,0x44,0x45}; //帧头
float channel[4]; //数据通道,float型
channel[0] = 10; //通道赋值
channel[1] = 20;
channel[2] = 30;
channel[3] = data1;
Usart1_SendNByte((u8*)temp,sizeof(temp)); //发送帧头
Usart1_SendNByte((u8*)channel,sizeof(channel)); //发送数据
}
3、主函数
int main()
{
delay_init(72);
My_Usart1_Init(); //串口初始化
while(1)
{
SendWave();
}
}
可以看到数据波形如下图
4 STM32示例接受数据程序
-
例程使用的芯片是STM32F103RBT6,串口1
-
例程使用STM32标准库开发
-
STM32的串口初始化过程请自行百度,这里使用的是串口1
-
需要包含头文件
#include<string.h>
和#include<stdio.h>
单片机接受串口数据有很多种方式,个人在开发时修函使用下面这种方式,接受简单,数据也不容易丢失。这种方式需要使用固定的格式进行通信。这里设定的通信协议如下:
下面示例中的通信协议可以根据自己的需要设置,只需要保证以#结尾,协议的格式和下面数据解析函数中的格式一直,就可以快速适配
PID=0,0,0#
//里面的三个0,为数据,可以根据想要设定的数据改变。
//字母,等号,逗号,#为固定格式,不能改变。
1、串口接收中断函数
通过这个函数会把接受到的数据全部存到 Usart_ReadBuff 数组中,并且会将 Usart_ReadOk 置为1
比如发的是 PID=10,20,0.22#
那么 Usart_ReadBuff 数组中的值就是 PID=10,20,0.22#
// 串口接收缓存数组
char Usart_ReadBuff[30] = {0};
u8 Usart_ReadOk = 0;
/**
* @brief 串口1接收中断函数,将接收到的数据读取到Usart_ReadBuff中暂存,等待解析
* @param void
* @retval None
*/
void USART1_IRQHandler(void) //串口1中断服务程序
{
u8 temp;
static u8 count = 0; // 接收数组控制变量
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //判断是否为接收中断
{
temp = USART_ReceiveData(USART1); //读取接收到的数据,并清除中断标志
if(Usart_ReadOk == 0)
{
Usart_ReadBuff[count] = temp; //保存接收到的数据到接收缓存数组
count++; //数组下标切换
if(temp == '#')
{
Usart_ReadOk = 1;//接收完成置位
count = 0; //清零计数,为下一次接收做准备
}
}
if(count > 29)
{ //防止数据溢出
count = 0;
}
}
}
2、数据解析函数
使用 sscanf
反向格式化函数提取数据保存到指针D1,D2,D3指向的地址中。
解析成功返回1,否则返回0
u8 Usart_GetData(float *D1,float *D2,float *D3)
{
u8 flag = 0;
if(Usart_ReadOk == 1)
{
if(sscanf(Usart_ReadBuff,"PID=%f,%f,%f#",
D1,D2,D3)==3) //使用了几个%就等于几,可以看看sscanf函数原型
{
flag = 1;
}
//清除接收完成标志
Usart_ReadOk = 0;
memset(Usart_ReadBuff,0,sizeof(Usart_ReadBuff));
}
return flag;
}
3、功能测试函数
这个测试函数是,将接收到的第一个数据,通过通道4发送出去
float data1 = 0;
void SendWave(void);
int main()
{
delay_init(72);
My_Usart1_Init(); //串口初始化
float d1,d2,d3;
while(1)
{
SendWave();
if(Usart_GetData(&d1,&d2,&d3)) //解析数据
{
data1 = d1; //解析成功,赋值
}
}
}
void SendWave(void)
{
u8 temp[] = {0x41,0x42,0x43,0x44,0x45};
float channel[4];
channel[0] = 10;
channel[1] = 20;
channel[2] = 30;
channel[3] = data1; //发送出去看看对不对
Usart1_SendNByte((u8*)temp,sizeof(temp));
Usart1_SendNByte((u8*)channel,sizeof(channel));
}
刚开始为0
发送92.3
可以看到波形变成了92.3
5 实际应用
通过前面的介绍,就能够实现将单片机的数据以波形的方式展示。并且通过指令改变单片机中变量的值。
在调节PID的时候,就把要看的期望数据和测量数据赋值给通道,然后发送出来就行了。然后通过发送指令改变PID的值,就实现了在线调参。而不需要每改变一次PID的数据就下载一次程序。
如果喜欢请点赞支持,谢谢。