玖叶教程网

前端编程开发入门

关于PID闭环控制中上位机与下位机通讯代码的解析分享(一)

下位机接收数据代码(以STM32单片机为例)与上位机发送数据C#代码分享

1、下位机代码:

/**

* @brief 接收的数据处理

* @param void

* @return -1:没有找到一个正确的命令.

*/

int8_t receiving_process(void)

{

uint8_t frame_data[128]; // 要能放下最长的帧

uint16_t frame_len = 0; // 帧长度

uint8_t cmd_type = CMD_NONE; // 命令类型


while(1)

{

cmd_type = protocol_frame_parse(frame_data, &frame_len);

switch (cmd_type)

{

case CMD_NONE:

{

return -1;

}


case SET_P_I_D_CMD:

{

uint32_t temp0 = COMPOUND_32BIT(&frame_data[13]);

uint32_t temp1 = COMPOUND_32BIT(&frame_data[17]);

uint32_t temp2 = COMPOUND_32BIT(&frame_data[21]);


float p_temp, i_temp, d_temp;


p_temp = *(float *)&temp0;

i_temp = *(float *)&temp1;

d_temp = *(float *)&temp2;


set_p_i_d(p_temp, i_temp, d_temp); // 设置 P I D

}

break;


case SET_TARGET_CMD:

{

int actual_temp = COMPOUND_32BIT(&frame_data[13]); // 得到数据


set_pid_target(actual_temp); // 设置目标值

}

break;


case START_CMD:

{

set_motor_enable(); // 启动电机

}

break;


case STOP_CMD:

{

set_motor_disable(); // 停止电机

}

break;


case RESET_CMD:

{

HAL_NVIC_SystemReset(); // 复位系统

}

break;


case SET_PERIOD_CMD:

{

uint32_t temp = COMPOUND_32BIT(&frame_data[13]); // 周期数

SET_BASIC_TIM_PERIOD(temp); // 设置定时器周期1~1000ms

}

break;


default:

return -1;

}

}

}

这段代码是一个接收数据并进行处理的函数。函数名为receiving_process,返回类型为int8_t,参数为空。函数的作用是接收数据并根据接收到的命令类型进行相应的处理。如果没有找到正确的命令,函数返回-1。

在函数内部,定义了一些变量用于存储接收到的数据和命令类型。frame_data是一个长度为128的uint8_t数组,用于存储接收到的数据帧。frame_len是一个uint16_t类型的变量,用于记录数据帧的长度。cmd_type是一个uint8_t类型的变量,用于存储命令类型。

接下来是一个无限循环,用于不断接收并处理数据。

循环内部首先调用了一个名为protocol_frame_parse的函数,该函数用于解析数据帧并返回命令类型。解析过程将接收到的数据帧存储在frame_data中,并将数据帧的长度保存在frame_len中。解析结果保存在cmd_type中。

接下来通过switch语句对cmd_type进行判断,根据不同的命令类型进行相应的处理。

如果命令类型为CMD_NONE,表示没有找到正确的命令,返回-1。

如果命令类型为SET_P_I_D_CMD,表示接收到了设置PID参数的命令。接下来通过COMPOUND_32BIT宏将frame_data中的字节转换为32位整数,然后再通过强制类型转换将32位整数转换为float类型。将转换后的参数传递给set_p_i_d函数,用于设置PID参数。

如果命令类型为SET_TARGET_CMD,表示接收到了设置目标值的命令。通过COMPOUND_32BIT宏将frame_data中的字节转换为32位整数,然后将转换后的参数传递给set_pid_target函数,用于设置目标值。

如果命令类型为START_CMD,表示接收到了启动电机的命令。调用set_motor_enable函数,用于启动电机。

如果命令类型为STOP_CMD,表示接收到了停止电机的命令。调用set_motor_disable函数,用于停止电机。

如果命令类型为RESET_CMD,表示接收到了复位系统的命令。调用HAL_NVIC_SystemReset函数,用于复位系统。

如果命令类型为SET_PERIOD_CMD,表示接收到了设置定时器周期的命令。通过COMPOUND_32BIT宏将frame_data中的字节转换为32位整数,然后将转换后的参数传递给SET_BASIC_TIM_PERIOD函数,用于设置定时器周期。

最后,如果命令类型不在上述情况中,默认返回-1。

总结起来,这段代码是一个接收数据并进行处理的函数。函数通过解析数据帧获取命令类型,并根据命令类型进行相应的处理操作。

2、上位机代码:

using System;

using System.IO.Ports;

using System.Threading;


public class UpperComputer

{

private SerialPort serialPort;


public UpperComputer()

{

// 初始化串口

serialPort = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);

}


public void Connect()

{

try

{

serialPort.Open(); // 打开串口连接

Console.WriteLine("成功连接下位机。");

}

catch (Exception ex)

{

Console.WriteLine("连接下位机失败:" + ex.Message);

}

}


public void Disconnect()

{

serialPort.Close(); // 关闭串口连接

Console.WriteLine("已断开下位机连接。");

}


public void SendCommand(byte[] command)

{

try

{

serialPort.Write(command, 0, command.Length); // 发送命令

Console.WriteLine("发送命令成功。");

}

catch (Exception ex)

{

Console.WriteLine("发送命令失败:" + ex.Message);

}

}


public static void Main(string[] args)

{

UpperComputer upperComputer = new UpperComputer();

upperComputer.Connect();


// 示例:发送设置PID参数的命令

byte[] setPIDCommand = new byte[25];

setPIDCommand[0] = 1; // 命令类型:设置PID参数

Buffer.BlockCopy(BitConverter.GetBytes(1.23f), 0, setPIDCommand, 1, 4); // 设置P参数

Buffer.BlockCopy(BitConverter.GetBytes(4.56f), 0, setPIDCommand, 5, 4); // 设置I参数

Buffer.BlockCopy(BitConverter.GetBytes(7.89f), 0, setPIDCommand, 9, 4); // 设置D参数


upperComputer.SendCommand(setPIDCommand);


// 示例:发送设置目标值的命令

byte[] setTargetCommand = new byte[9];

setTargetCommand[0] = 2; // 命令类型:设置目标值

Buffer.BlockCopy(BitConverter.GetBytes(100), 0, setTargetCommand, 1, 4); // 设置目标值为100


upperComputer.SendCommand(setTargetCommand);


// 示例:发送启动电机的命令

byte[] startCommand = new byte[1];

startCommand[0] = 3; // 命令类型:启动电机


upperComputer.SendCommand(startCommand);


// 示例:发送停止电机的命令

byte[] stopCommand = new byte[1];

stopCommand[0] = 4; // 命令类型:停止电机


upperComputer.SendCommand(stopCommand);


// 示例:发送复位系统的命令

byte[] resetCommand = new byte[1];

resetCommand[0] = 5; // 命令类型:复位系统


upperComputer.SendCommand(resetCommand);


// 示例:发送设置定时器周期的命令

byte[] setPeriodCommand = new byte[5];

setPeriodCommand[0] = 6; // 命令类型:设置定时器周期

Buffer.BlockCopy(BitConverter.GetBytes(500), 0, setPeriodCommand, 1, 4); // 设置周期为500ms


upperComputer.SendCommand(setPeriodCommand);


upperComputer.Disconnect();

}

}

导入命名空间:

using System;:引入System命名空间,包含了一些常用的系统类型和功能。

using System.IO.Ports;:引入System.IO.Ports命名空间,提供了与串口通信相关的类和方法。

using System.Threading;:引入System.Threading命名空间,提供了多线程编程相关的类和方法。

定义UpperComputer类:

private SerialPort serialPort;:定义一个私有变量serialPort,用于串口通信。

public UpperComputer():构造方法,用于初始化串口。

Connect()方法:

serialPort.Open();:打开串口连接。

Console.WriteLine("成功连接下位机。");:在控制台输出连接成功的提示信息。

Disconnect()方法:

serialPort.Close();:关闭串口连接。

Console.WriteLine("已断开下位机连接。");:在控制台输出断开连接的提示信息。

SendCommand()方法:

serialPort.Write(command, 0, command.Length);:发送命令给下位机。

Console.WriteLine("发送命令成功。");:在控制台输出发送命令成功的提示信息。

Main()方法:

UpperComputer upperComputer = new UpperComputer();:创建一个UpperComputer对象。

upperComputer.Connect();:调用Connect()方法连接下位机。

示例代码:

发送设置PID参数的命令:

byte[] setPIDCommand = new byte[25];:定义一个长度为25的byte数组,用于存储设置PID参数的命令。

setPIDCommand[0] = 1;:设置命令类型为设置PID参数。

Buffer.BlockCopy(BitConverter.GetBytes(1.23f), 0, setPIDCommand, 1, 4);:将浮点数1.23转换为字节数组,并复制到setPIDCommand数组的指定位置,用于设置P参数。

Buffer.BlockCopy(BitConverter.GetBytes(4.56f), 0, setPIDCommand, 5, 4);:将浮点数4.56转换为字节数组,并复制到setPIDCommand数组的指定位置,用于设置I参数。

Buffer.BlockCopy(BitConverter.GetBytes(7.89f), 0, setPIDCommand, 9, 4);:将浮点数7.89转换为字节数组,并复制到setPIDCommand数组的指定位置,用于设置D参数。

upperComputer.SendCommand(setPIDCommand);:调用SendCommand()方法发送设置PID参数的命令。

发送设置目标值的命令:

byte[] setTargetCommand = new byte[9];:定义一个长度为9的byte数组,用于存储设置目标值的命令。

setTargetCommand[0] = 2;:设置命令类型为设置目标值。

Buffer.BlockCopy(BitConverter.GetBytes(100), 0, setTargetCommand, 1, 4);:将整数100转换为字节数组,并复制到setTargetCommand数组的指定位置,用于设置目标值。

upperComputer.SendCommand(setTargetCommand);:调用SendCommand()方法发送设置目标值的命令。

发送启动电机的命令:

byte[] startCommand = new byte[1];:定义一个长度为1的byte数组,用于存储启动电机的命令。

startCommand[0] = 3;:设置命令类型为启动电机。

upperComputer.SendCommand(startCommand);:调用SendCommand()方法发送启动电机的命令。

发送停止电机的命令:

byte[] stopCommand = new byte[1];:定义一个长度为1的byte数组,用于存储停止电机的命令。

stopCommand[0] = 4;:设置命令类型为停止电机。

upperComputer.SendCommand(stopCommand);:调用SendCommand()方法发送停止电机的命令。

发送复位系统的命令:

byte[] resetCommand = new byte[1];:定义一个长度为1的byte数组,用于存储复位系统的命令。

resetCommand[0] = 5;:设置命令类型为复位系统。

upperComputer.SendCommand(resetCommand);:调用SendCommand()方法发送复位系统的命令。

发送设置定时器周期的命令:

byte[] setPeriodCommand = new byte[5];:定义一个长度为5的byte数组,用于存储设置定时器周期的命令。

setPeriodCommand[0] = 6;:设置命令类型为设置定时器周期。

Buffer.BlockCopy(BitConverter.GetBytes(500), 0, setPeriodCommand, 1, 4);:将整数500转换为字节数组,并复制到setPeriodCommand数组的指定位置,用于设置周期。

upperComputer.SendCommand(setPeriodCommand);:调用SendCommand()方法发送设置定时器周期的命令。

upperComputer.Disconnect();:调用Disconnect()方法断开下位机连接。

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言