串口接收并解析命令

简介:该篇文章描述了如何分离串口传输的命令和参数数值




一般来讲如果不是使用复杂的自定义协议,那么通常标志位+参数是非常有效的一种从串口控制下位机的方式,这里说明下这种分析传入的命令并分离为所需参数的算法


这里我使用Arduino来实现,其他架构也是照葫芦画瓢:




整体流程:


数据传入----记录-----解析出数据-----用于其他逻辑



实现的功能:


例如我传入/A100 /B200,那么数组0将存储整数100和200两个数值

例如我传入/ST  那么就会执行预先设置好的一个函数



1.初始化


初始化一个是内存空间的开辟(我是使用C/C++语言来编写这些代码),另一个是串口初始化与启用


我可以明确的了解要传入的数据会产生最多四组数值,肯定没有第五组因为逻辑是固定的,如果要动态开辟空间可以使用指针链表与类,但在嵌入式环境下不推荐因为容易崩。

因为是主要是演示所以我就简化了对于内存释放的操作。


初始化阶段的代码:

long numdata[4]={0,0,0,0};  //record value 
String recData = "";  //recording received data from upper machine
int mark = 0;  //process data flag

整数数组numdata,用于传出被记录的数据。

字符串类型recData,用以记录从串口传入的数据,提供给处理函数进行判断。

整数类型mark,这个在c++中也可以使用bool代替,主要是用来标识目前接收的数据是否处理完了。



char dat[64]="";
int curSetData = 0;

dat用于sprintf函数存储数据,主要用于存储反馈消息,之后传输给上位机

curSetData用于记录目前所赋值的整数在数组的位置,由命令标志来决定



2.数据接收


在串口缓存中还有数据的时候,循环读取记录,并且置数据处理标志位为1

while (Serial.available() > 0)
  {
    recData += char(Serial.read());
    delay(2);  
    mark = 1;
  }



3.数据处理


主要几个步骤,分别为判断数据存在与否,判别命令通用前缀,判断命令,记录数值


判断记录的数值是否为空

if (recData.length() > 1) // judge length
    {

      Serial.println(recData);
    }
    else
    {
      mark = 0;
      return;
    }





判别命令通用前缀

没有这个前缀就直接返回不作处理,这里写的比较简单

if (recData[0] == '/')



判断命令(参数为字母+数字)

判断命令之后,置记录位,之后向依照记录的值向数组位置存储数据

if (recData[i] == 'V')
else if (recData[i] == 'A') 
else if (recData[i] == 'B') 




判断命令(参数仅仅为两个字符)

if (recData[0] == '/')
    {
      if (recData[1] == 'S' && recData[2] == 'T')
      {
        Serial.print("Start test");  
        mark = 0;
      }
      if (recData[1] == 'E' && recData[2] == 'S')
      {
        Serial.print("Emmergency stop");  
        mark = 0;
      }
    }




记录数值

主要是将字符类型转换为整数类型

if (recData[i] >= '0' && recData[i] <= '9')
        {
          numdata[curSetData] = numdata[curSetData] * 10 + (recData[i] - '0');
        }

算法是,例如我传入的是字符串12340,那么我如果要记录这第一个数值1,实际上也就是把它(目前还是个ASCII字符的1)减去ASCII码的0。

之后我记录2,3,4,0字符其实也就是重复第一步,然后加上目前已经记录的被转换为数字类型的数值的10倍,也就是最新记录的数字将作为个位数。




反馈数据(调试)

    
      memset(dat,0,64);
      sprintf(dat,"Current set: %d,All Value: %d",curSetData,numdata[curSetData]);
      Serial.println(dat);
      Serial.println(numdata[0]);
      Serial.println(numdata[1]);
      Serial.println(numdata[2]);





接收数据并处理的部分代码

void serial_get()
{
  static int j = 0;
  while (Serial.available() > 0)
  {
    recData += char(Serial.read());
    delay(2);  
    mark = 1;
  }

  if (mark == 1)
  {
    if (recData.length() > 1) // judge length
    {

      Serial.println(recData);
    }
    else
    {
      return;
    }
    if (recData[0] == '/')
    {
      //using this loop to get number and change to 
      for (int i = 1; i < recData.length() ; i++)
      {
        if (recData[i] == 'V') 
        {
          
          curSetData = 0;
          numdata[curSetData] = 0;
        }
        else if (recData[i] == 'A') 
        {
          
          curSetData = 1;
          numdata[curSetData] = 0;
        }
        else if (recData[i] == 'B') 
        {
          
          curSetData  = 2;
          numdata[curSetData] = 0;
        }

         if (recData[i] >= '0' && recData[i] <= '9')
        {
          numdata[curSetData] = numdata[curSetData] * 10 + (recData[i] - '0');
        }
         
      }
      memset(dat,0,64);
      sprintf(dat,"Current set: %d,All Value: %d",curSetData,numdata[curSetData]);
      Serial.println(dat);
      Serial.println(numdata[0]);
      Serial.println(numdata[1]);
      Serial.println(numdata[2]);
      
    }

    if (recData[0] == '/')
    {
      if (recData[1] == 'S' && recData[2] == 'T')
      {
        Serial.print("Start test");  
        mark = 0;
      }
      if (recData[1] == 'E' && recData[2] == 'S')
      {
        Serial.print("Emmergency stop");  
        mark = 0;
      }
    }
    else
    {
      return;
    }
    
    recData = String("");
    mark = 0;

    j = 0;
  }

}





串口接收并解析命令_第1张图片





所有代码:


long numdata[4]={0,0,0,0};  //record value 
String recData = "";  //recording received data from upper machine
int mark = 0;  //

void setup()
{
  Serial.begin(115200);//set serialport baud rate
}

char dat[64]="";
int curSetData = 0;
void serial_get()
{
  static int j = 0;
  while (Serial.available() > 0)
  {
    recData += char(Serial.read());
    delay(2);  
    mark = 1;
  }

  if (mark == 1)
  {
    if (recData.length() > 1) // judge length
    {
      Serial.println(recData);
    }
    if (recData[0] == '/')
    {
      //using this loop to get number and change to 
      for (int i = 1; i < recData.length() ; i++)
      {
        if (recData[i] == 'V') 
        {
          
          curSetData = 0;
          numdata[curSetData] = 0;
        }
        else if (recData[i] == 'A') 
        {
          
          curSetData = 1;
          numdata[curSetData] = 0;
        }
        else if (recData[i] == 'B') 
        {
          
          curSetData  = 2;
          numdata[curSetData] = 0;
        }

         if (recData[i] >= '0' && recData[i] <= '9')
        {
          numdata[curSetData] = numdata[curSetData] * 10 + (recData[i] - '0');
        }
         
      }
      memset(dat,0,64);
      sprintf(dat,"Current set: %d,All Value: %d",curSetData,numdata[curSetData]);
      Serial.println(dat);
      Serial.println(numdata[0]);
      Serial.println(numdata[1]);
      Serial.println(numdata[2]);
      
    }

    if (recData[0] == '/')
    {
      if (recData[1] == 'S' && recData[2] == 'T')
      {
        Serial.print("Start test");  
        mark = 0;
      }
      if (recData[1] == 'E' && recData[2] == 'S')
      {
        Serial.print("Emmergency stop");  
        mark = 0;
      }
    }
    else
    {
      return;
    }
    
    recData = String("");
    mark = 0;

    j = 0;
  }

}
void loop()
{
  serial_get();
}






注:这些代码是和另一位工程师讨论的结果,我们都有应用在一些小制作上,



你可能感兴趣的:(硬件开发)