后台、网关、节点三方数据通信问题(1)

来源:互联网 发布:人工智能爱理酱本子 编辑:程序博客网 时间:2024/04/26 14:10

最近在学校做某项目,主要负责后台、网关、节点三方数据通信问题,有具体的协议,来实现控制、查询、定时数据上报等功能。针对联调过程中出现的问题,做一下总结。

       1.模块的选取:网关与后台通信采用的是RM-10模块wifi传输数据,STM32单片机用串口与RM-10连接,串口给模块发送数据,模块无线连接路由器,连至后台。网关与各个节 点连接通过的是HC-12无线模块(传输模式有4种,根据需要自行修改),STM32单片机用串口与HC-12连接,串口给模块发送数据,通过无线传输。

       2.数据传输的打包与解包:因为已经制定了详细的数据协议,(在制定协议的时候,要考虑到这个产品的以后的升级、功能扩展等问题)打包与解包也就有了具体的针对方法。后台到网关,网关到节点,数据包大致相同。分为消息头+消息体。具体内容自行定制。打包比较容易,按照固定格式来就行,途中上结构体,共用体啥的,可以减少代码量,操作方便。对于解包,无疑是从接收到数据就开始解包了,单片机用的是串口与模块通信,串口中断接收数据。那么如何判断,单片机接收到了数据呢,何时开始解包?目前用的这种方法是,设置两个数据指针,一个数据指针(P1)用于串口接收到数据的字节数(我们的数据按字节来处理)的计数,另一个数据指针(P2)就是在解包的时候指示解到第几个数据的指向。单片机一上电,两个数值默认的都是0,当接收到数据的时候,P1开始++,数据存入一个数组Data[]中,这时候P1!=P2,开始进行解包程序,解包的时候用P2指示,P2++,从Data[]中将数据一个一个取出进行处理。数据处理可以一个字节一个字节的去处理,虽然代码比较多,但能保证足够的准确。

   代码:

void USART2_IRQHandler(void)   //接收数据中断
{  
if(USART2->SR&(1<<5))
{
Data[P1] = USART2->DR;
if(++P1>=U2bufsize)
 {
    P1=0;
 }
}  
}


while(P2!=P1)    //解包代码

{

      temp = Data[P2];
      P2++;

      if(P2>=U2bufsize)
{
P2=0;
        }

     //对temp的处理;

}


这里针对U2bufsize这个变量解释下,开辟一个缓冲区,起初,每次解包完毕后,我打算把他们重新置零,但是不行,因为可能在你解完一个包的时候,仍然有数据再被接收,如果,你解完一个包就置零,后面的数据会直接丢弃的。这个缓冲区说通俗点,就是因为数据不能及时被处理,来暂时保存数据的。

    3. 数据校验问题:数据校验,可以通过添加帧头、帧尾来判断这一包数据是否正确。本来我们采用的数据校验也是类似这样的校验,可是因为WIFI模块,因为限制了一次性发送字节的长度问题(我们的包>限制字节数),所以就在原来的基础上添加了CRC-32校验,方便数据确认,和后台的数据拼包。因为STM32有硬件CRC-32校验,就简单的多了。

#include "crc.h"

#define CRC32_POLYNOMIAL ((u32)0xEDB88320)

u32 revbit(u32 uData)
{
   u32 uRevData = 0,uIndex = 0;
uRevData |= ((uData >> uIndex) & 0x01);
for(uIndex = 1;uIndex < 32;uIndex++)
{
     uRevData <<= 1;
uRevData |= ((uData >> uIndex) & 0x01);
  }
return uRevData;
}

u32 CRC32_ForBytes(u8 *pData,u32 uLen)
{
  u32 uIndex = 0,uData = 0,i;
uIndex = uLen >> 2;

  RCC->AHBENR |= 0x00000040;
CRC->CR = 0x01; 

    while(uIndex--)  
    {  
#ifdef USED_BIG_ENDIAN    
        uData = __REV((u32*)pData);  
#else  
        memcpy((u8*)&uData,pData,4);  
#endif        
        pData += 4;  
        uData = revbit(uData);  
        CRC->DR = uData;  
    }  
    uData = revbit(CRC->DR);  
    uIndex = uLen & 0x03;  
    while(uIndex--)  
    {  
        uData ^= (u32)*pData++;  
        for(i = 0;i < 8;i++)  
          if (uData & 0x1)  
            uData = (uData >> 1) ^ CRC32_POLYNOMIAL;  
          else  
            uData >>= 1;  
    }  
    return uData^0xFFFFFFFF; 
}


以上为STM32的CRC-32的硬件校验代码,经验证和PC的相同。

    4. 节点激活问题:节点在最初的时候,都是未被激活的状态,后台给网关下发命令,可以激活节点。问题来了,如果网关同时把每个节点的激活命令广播出去,那么节点返回数据的时候,就会造成数据冲突问题(N多节点同时给网关发数据,网关接收必定出现问题)。于是就采用,一个节点一个节点激活的方法,开始只发送一个节点的激活命令,待该节点返回数据之后,在下发另一个节点的激活命令。(暂定该种方法,现在就两个节点,可以激活。)这样虽然能解决激活的时候的数据冲突问题,以后节点数据定时上报的时候,可能还会出现这种问题,待解决。



2 0
原创粉丝点击