自组网实现

这次只说如何用C语言实现通信协议的,具体SX1278底层驱动代码有机会再说。

LoRaWAN有点麻烦,需要接入网络,或者自建服务器,都太贵了,还不如自己弄个自组网完全免费,完全自己定制。

写之前先要感谢我的导师任老师,没有老师的监督偏爱我现在可能不是这个样子,也不会这些东西。

这篇文章可能有些地方不正确的地方,请各位多多指正。

为了节省时间和精力,我就直接改装现有协议了,自己设计太麻烦了,设计完我也变秃了。

#1.设计改进通信协议

我用的是在公司和工业中用的比较多的Modbus协议,ModBus 是由 Modicon 公司在 1979 年发明的,是全球第一个真正用于工业现场的总线协议。

modbus简介
https://www.ni.com/zh-cn/innovations/white-papers/14/the-modbus-protocol-in-depth.html

在这里插入图片描述
Modbus协议数据帧结构为从机地址+功能码+数据+校验。

我要用的话需要改进一下,在数据帧里再加一个网络地址,这样设备就有两个ID,设备命名更规范。

改进后的数据帧如下:

网关:
在这里插入图片描述
从机:
在这里插入图片描述

其实参数和数据都差不多,就是改了个名字。

#2.具体实施步骤

#2.1 通信过程
通信无非就是网关发送命令,从机接受命令并处理返回处理数据,网关接受数据的过程。

网关发送命令函数:sendMasterAsk(unsigned char slave_addr,unsigned char op_code,unsigned char pram);
网关接受数据函数:receiveSlaveAck(unsigned char slave_addr,unsigned char op_code,unsigned char pram,DeviceBlock * pdevblock);
从机处理网关命令函数:processMasterAsk(DeviceBlock * pdevblock);

#2.2 相关地址定义部分
在写发送接收函数之前先要把准备工作做好,先把各个参数的定义写好,这个可以写成变量可以写成数组也可以写成宏定义,这个看个人爱好。

我是写成宏定义了,到时候改起来好改。

网关地址、从机地址、操作码、数据都是8个字节,unsigned char刚好就是8个字节,所以相关定义都是unsigned char;给的空间比较豪华,因为我再也不想挨个位去看有什么含义了,太难受了,尤其是1553,一把辛酸泪。

/*网络相关宏定义*/
#define NET_ADDR           0xB9    //网络地址
#define SLAVE1_ADDR        0x01    //子设备1地址
#define SLAVE2_ADDR        0x02    //子设备2地址
#define SLAVE3_ADDR        0x03    //子设备3地址

/*操作码相关宏定义*/
#define OP_R_SENSOR        0x01    //读传感器数据

/*参数相关宏定义*/
#define PRAM_R_TEMPERATURE 0x01    //只读取温度
#define PRAM_R_BPM         0x02    //只读取心跳
#define PRAM_R_HUMIDITY    0x03    //只读取湿度
#define PRAM_R_ALL         0x07    //读取所有传感器

设备块---主要是用起来方便
typedef struct 
{
    unsigned char Temperature;  //温度
    unsigned char BPM;     //BPM
    unsigned short int HUMIDITY;     //环境湿度
}DeviceBlock;

#2.3 网关发送部分

代码部分:

 sendMasterAsk(unsigned char slave_addr,unsigned char op_code,unsigned char pram)
{
    
    unsigned char sendbuffer[6] = {NET_ADDR,slave_addr,op_code,pram,0,0};  按照通信协议排列
    unsigned short int CRC16 = getModbusCRC16(sendbuffer,4);             

    sendbuffer[4] = CRC16>>8;                                             
    sendbuffer[5] = CRC16;                                               
    
    transmitPackets(sendbuffer,sizeof(sendbuffer));                     //发送
}

设置一个数组写入网络地址代码,从机地址,操作码,参数(也就是在这个操作码下要干什么事情),剩下两个就是CRC了,这个CRC可以用硬件实现,也可以用软件,这个无所谓。最后用SX1278的API发送就行了。

slave_addr是子机地址,调用时输入定义的地址
op_code是操作码,pram是操作码下相关操作

#2.4 从机处理指令部分
代码部分:

processMasterAsk(DeviceBlock * pdevblock)
{
    unsigned char Askbuffer[6];  网关发给从机的数据
    unsigned char Ackbuffer[9] = {NET_ADDR,SLAVE1_ADDR}; 从机返回给网关的数据,按照通信协议排列
    unsigned char len;
    unsigned short int CRC16;
    unsigned char i;

    if(receivePackets(Askbuffer)==1)   表示收到数据
    {
        if(Askbuffer[0] != NET_ADDR)   检测网络地址对不对
        {
            return FRAME_NETADDR_ERR;  返回网络地址错误代码
        }

        if(Askbuffer[1] != SLAVE3_ADDR)  检测从机地址对不对
        {
            return FRAME_SLAVEADDR_ERR;  返回从机地址错误代码
        }

        len = getFrameLength(Askbuffer,sizeof(Askbuffer));  检测实际长度


		没问题后开始处理数据
      if(Askbuffer[2] == OP_R_SENSOR)   
        {
            Ackbuffer[2] = OP_R_SENSOR;

            for(i=0;i<8;++i) 8个字节每个位都来一遍,从第0位到第7{
                switch(Askbuffer[3] & (0x01<<i)) i从0位开始移位1每次移移位,移8次,对比呢个位是1,相同就走哪一步,具体定义见参数定义数字,然后将对应传感器数据写入设备块数据准备发送
                {
                    case PRAM_R_TEMPERATURE:Ackbuffer[3] = pdevblock->Temperature;break;

                    case PRAM_R_HUMIDITY   :Ackbuffer[4] = pdevblock->HUMIDITY;   break;

                    case PRAM_R_BPM        :
                    {
                                                Ackbuffer[5] = pdevblock->BPM;
                                            }                                     break;
                    default                :                                      break;
                }
            }

            CRC16 = getModbusCRC16(Ackbuffer,7);

            Ackbuffer[7] = CRC16>>8;

            Ackbuffer[8] = CRC16;

        }
}

#2.4 网关接受部分
代码部分:
大部分都和从机部分一样,对着看吧

receiveSlaveAck(unsigned char slave_addr,unsigned char op_code,unsigned char pram,DeviceBlock * pdevblock)
{
    unsigned char receivebuffer[9];收到的从机数据
    unsigned char len;
    unsigned char i;

    if(receivePackets(receivebuffer)==1)
    {
        if(receivebuffer[0] != NET_ADDR) 
        {
            return FRAME_NETADDR_ERR;
        }

        if(receivebuffer[1] != slave_addr)
        {
            return FRAME_SLAVEADDR_ERR;
        }

        len = getFrameLength(receivebuffer,sizeof(receivebuffer));
   
      
     if(op_code==OP_R_SENSOR)    
        {
         
            for(i=0;i<8;++i)
            {

                switch(pram & (0x01<<i))
                {
                    case PRAM_R_TEMPERATURE:(pdevblock+slave_addr)->Temperature = receivebuffer[3];                break;  
                    读出从机传来的数据
                    case PRAM_R_HUMIDITY   :(pdevblock+slave_addr)->HUMIDITY = receivebuffer[4];                   break;
                    case PRAM_R_BPM        :(pdevblock+slave_addr)->BPM = receivebuffer[5];  break;
                    default                :                                                                       break;
                }                             
            }
        }
}

发布了2 篇原创文章 · 获赞 1 · 访问量 1324

猜你喜欢

转载自blog.csdn.net/qq_37870032/article/details/104683127