这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 高校专区 » 坤创E-Geek/天科大新电社 » 【2021全国电赛】坤创4队记录:04 modbus学习

共1条 1/1 1 跳转至

【2021全国电赛】坤创4队记录:04 modbus学习

菜鸟
2021-07-29 21:07:32     打赏

Modbus是一种串行通信协议,是Modicon公司(现在的施耐德电气 Schneider Electric)于1979年为使用可编程逻辑控制器(PLC)通信而发表。Modbus已经成为工业领域通信协议的业界标准(De facto),并且现在是工业电子设备之间常用的连接方式。

Modbus比其他通信协议使用的更广泛的主要原因有: 

1. 公开发表并且无版权要求

2. 易于部署和维护

3. 对供应商来说,修改移动本地的比特或字节没有很多限制

1627563705633936.png1627563706523312.png1627563705914337.png

Modbus允许多个 (大约240个) 设备连接在同一个网络上进行通信,举个例子,一个由测量温度和湿度的装置,并且将结果发送给计算机。在数据采集与监视控制系统(SCADA)中,Modbus通常用来连接监控计算机和远程终端控制系统(RTU)

extern uint8_t uart_buff[16];
extern uint8_t usart_flag;
// regGroup[]对应地址0x0000-0x0005的数据
uint8_t regGroup[] = {0x11,0x22,0x33,0x44,0x55,0x66};void modbus_ok(void)
{
 if(usart_flag) {
  uint8_t i;
  uint8_t space = ' ';
  printf("主机发送:");
  for(i = 0; i < 8; i++) {
   printf("%02X%c", uart_buff[i], space);
  }
  printf("\n");
  modbus_handle(uart_buff, 8);
 }
}void modbus_handle(unsigned char *buf, unsigned char len)
{
    unsigned char i;
    unsigned char cnt;
    unsigned int  crc;
    unsigned char crch, crcl;
  //本例中的从机地址设定为0x01,
    if (buf[0] != 0x01) {              
      printf("error:从机地址不为0x01\n");
   usart_flag = 0; // 清楚串口动作标志位
   return;           //直接退出,即丢弃本帧数据不做任何处理
    }
    //地址相符时,再对本帧数据进行校验
    crc = modbus_CRC16(buf, len-2);  //计算CRC校验值
    crch = crc >> 8;  // 取高八位
    crcl = crc & 0xFF; // 取低八位
    if ((buf[len-2]!=crch) || (buf[len-1]!=crcl))
    {
   printf("error:CRC校验失败\n");
   usart_flag = 0;
      return;   //如CRC校验不符时直接退出
    }
    //地址和校验字均相符后,解析功能码,执行相关操作
    switch (buf[1]) {
   case 0x03:  //读取一个或连续的寄存器
    //只支持0x0000~0x0005
    if ((buf[2]==0x00) && (buf[3]<=0x05)) {
     i = buf[3];      //提取寄存器地址
     cnt = buf[5];    //提取待读取的寄存器数量
     buf[2] = cnt*2;  //读取数据的字节数,为寄存器数*2
     len = 3;          //帧前部已有地址、功能码、字节数共3个字节
     while (cnt--)
     {
       buf[len++] = 0x00;            //寄存器高字节补0
       buf[len++] = regGroup[i++]; //寄存器低字节
     }
     //重新计算CRC校验值 赋值给后两位
     crc = modbus_CRC16(buf, len);  
     crch = crc >> 8;
     crcl = crc & 0xFF;
     buf[len++] = crch;
     buf[len++] = crcl;
          break;
       }
    //寄存器地址不被支持时,返回错误码
        else {
     buf[1] = 0x83;  //功能码最高位置1
     buf[2] = 0x02;  //设置异常码为02-无效地址
     len = 3;
     break;
        }
       case 0x06:  //写入单个寄存器
    if ((buf[2]==0x00) && (buf[3]<=0x05)) {
     i = buf[3];               //提取寄存器地址
     //往指定地址写入数据
     switch(i) {
      case 0x00: regGroup[0] = buf[5];   
       break;
      case 0x01: regGroup[1] = buf[5];
       break;
      case 0x02: regGroup[2] = buf[5];
       break;
      case 0x03: regGroup[3] = buf[5];
       break;
      case 0x04: regGroup[4] = buf[5];
       break;
      case 0x05: regGroup[5] = buf[5];
       break;
     }
     //重新计算CRC校验值 赋值给后两位
     crc = modbus_CRC16(buf, len-2);  
     crch = crc >> 8;
     crcl = crc & 0xFF;
     buf[len-2] = crch;
     buf[len-1] = crcl;
    }
  }
  char x = 0;
  uint8_t space = ' ';
  printf("从机返回:");
  for(x = 0; x < len; x++) {
   printf("%02X%c", buf[x], space);
  }
  printf("\n");
  usart_flag = 0;
}uint32_t modbus_CRC16(uint8_t *ptr, uint8_t len)
{
    unsigned int index;
    unsigned char crch = 0xFF;  //高CRC字节
    unsigned char crcl = 0xFF;  //低CRC字节
    unsigned char TabH[] = {
    //CRC高位字节值表
            0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
            0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
            0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
            0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
            0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
            0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
            0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
            0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
            0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
            0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
            0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
            0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
            0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
            0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
            0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
            0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
            0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
            0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
            0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
            0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
            0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
            0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
            0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
            0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
            0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
            0x80, 0x41, 0x00, 0xC1, 0x81, 0x40     } ;
        unsigned char TabL[] = {  
        //CRC低位字节值表
            0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
            0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
            0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
            0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
            0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
            0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
            0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
            0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
            0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
            0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
            0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
            0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
            0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
            0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 
            0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
            0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
            0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
            0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
            0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
            0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
            0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 
            0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
            0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
            0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
            0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
            0x43, 0x83, 0x41, 0x81, 0x80, 0x40     } ;
        while (len--)  //计算指定长度的CRC{
            index = crch^*ptr++;
            crch = crcl^TabH[index];
            crcl = TabL[index];
        }
    return ((crch<<8)|crcl);  
}



关键词: 2021全国电赛     modbus    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]