打印

modbus项目,进行中

[复制链接]
1504|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
manwjh|  楼主 | 2015-10-27 20:45 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
今天看了modbus的协议规范,同时找了一堆网上各种源代码。不满意,还是自己写吧。

如下代码不可能编译,因为我是边看规格书,边开始规划协议程序框架。CRC部分是摘抄自规范文档里面,结构借鉴了一份不完整的代码,我觉得命名符合我的审美。

/**
  ******************************************************************************
  * @file    modbus.c
  * @author  SZQVC
  * @version V1.0.0
  * @date    2015.10.27
  * @brief   modbus协议解析
  ******************************************************************************
  * @Attention                                                                 *
  *                                                                            *
  * <h2><center>&copy; COPYRIGHT 2015 SZQVC</center></h2>                      *
  *                                                                            *
  * 文件版权归“深圳权成安视科技有限公司”(简称SZQVC)所有。                      *
  *                                                                            *
  *        QQ:936318687    http://www.szqvc.com                               *
  *                                                                            *
  ******************************************************************************
**/

/*
MODBUS 长度
RS232 / RS485 ADU = 253字节+服务器地址(1 byte) + CRC (2字节) = 256字节。
TCP MODBUS ADU    = 249字节+ MBAP (7字节) = 256字节。

MODBUS请求PDU,   mb_req_pdu
MODBUS响应PDU,   mb_rsp_pdu
MODBUS异常响应PDU mb_excep_rsp_pdu
*/

/* define */


/* public */


/* extern */
//定义MODBUS服务器的存储单元
#define   MAX_I_COIL    1             //输入线圈数量
#define   MAX_O_COIL    1             //输出线圈数量
#define   MAX_I_REGI    1             //输入寄存器数量
#define   MAX_H_REGI    1             //保持寄存器数量
uint8_t   I_Coil[MAX_I_COIL/8+1];     //输入线圈
uint8_t   O_Coil[MAX_I_COIL/8+1];     //输出线圈
uint16_t  I_Regi[MAX_I_REGI];         //输入寄存器
uint16_t  H_Regi[MAX_H_REGI];         //保持寄存器

/* private */
#define  MAX_PDU_LEN   64
uint16_t PDU_Len;                     //缓冲接收数据
uint8_t  PDU_Buffer[MAX_PDU_BF];      //协议数据单元指针


/* function */
uint16_t CRC16( uint8_t *puchMsg, uint16_t usDataLen );


/*------------------------------------------------------------------------------*/
/*                              Modbus TASK                                     */
/*------------------------------------------------------------------------------*/
void ModbusTask(void)
{
  uint8_t err_code; //错误码
  
  //ADU模块(完成数据接收并传递到PDU缓冲,兼容RS485和TCP模式)
  
  
  //PDU模块(针对PDU缓冲进行解析)
  if( PDU_Len>MAX_PDU_LEN ){
    mb_excep_rsp_pdu(PDU_Buffer[0],SLAVE_DEVICE_BUSY);  //数据长度超出能力范围
  }else if( PDU_Len>0 ){
    switch(PDU_Buffer[0]){
      //公共功能码
      case 1: //读取输出线圈状态
        ReadCoilState('O');
        break;
      case 2: //读取输入线圈状态
        ReadCoilState('I');
        break;
      case 3: //读取保持寄存器
        ReadRegiState('H');
        break;
      case 4: //读取输入积存器
        ReadRegiState('I');
        break;
      case 5: //设置单个线圈状态
        SetSingleCoil();
        break;
      case 6: //设置单个寄存器
        SetSingleRegi();
        break;
      case 15://设置多个线圈
        SetMultCoil();
        break;
      case 16://预置多个寄存器
        SetMultRegVal();
        break;
      default:
        mb_excep_rsp_pdu(PDU_Buffer[0],ILLEGAL_FUNCTION);
        break;
    }
  }
}

void mb_rsp_pdu(uint8_t f_code)
{
  
}

void mb_excep_rsp_pdu(uint8_t f_code, uint8_t err_code)
{
  
}

void ReadCoilState(char type)
{
  uint16_t coil_addr = PDU_Buffer[1]<<8|PDU_Buffer[2];
  uint16_t coil_num  = PDU_Buffer[3]<<8|PDU_Buffer[4];
   
  switch(type)
  {
    case 'I':
      if( addr>MAX_I_COIL ){
        mb_excep_rsp_pdu(PDU_Buffer[0],ILLEGAL_DATA_ADDRESS);   //地址超过界限
      }else if( (addr+coil_num)>MAX_I_COIL ){
        mb_excep_rsp_pdu(PDU_Buffer[0],ILLEGAL_DATA_VALUE);     //读取数量超过界限
      }else{
      }
      break;
    case 'O':
      if( addr>MAX_O_COIL ){
        mb_excep_rsp_pdu(PDU_Buffer[0],ILLEGAL_DATA_ADDRESS);
      }else if( (addr+coil_num)>MAX_O_COIL ){
        mb_excep_rsp_pdu(PDU_Buffer[0],ILLEGAL_DATA_VALUE);
      }else{
      }
      break;
  }
}

void ReadRegiState(char type)
{
  switch(type)
  {
    case 'I':
      break;
    case 'H':
      break;
  }
}

void SetSingleCoil(void)
{
}

void SetSingleRegi(char type)
{
}

void SetMultCoil(void)
{
}

void SetMultRegVal(char type)
{
}

/*------------------------------------------------------------------------------*/
/*                                CRC                                           */
/*------------------------------------------------------------------------------*/
//High-Order Byte Table  
/* Table of CRC values for high–order byte */
const uint8_t auchCRCHi[] = {  
  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};

//Low-Order Byte Table  
/* Table of CRC values for low–order byte */
const uint8_t auchCRCLo[] = {  
  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};

/* The function returns the CRC as a unsigned short type */
uint16_t CRC16( uint8_t *puchMsg, uint16_t usDataLen )
{  
  uint8_t uchCRCHi = 0xFF  /* high byte of CRC initialized  */
  uint8_t uchCRCLo = 0xFF  /* low byte of CRC initialized  */
  uint16_t uIndex   /* will index into CRC lookup table   */   

  while (usDataLen--) /* pass through message buffer  */
  {  
    uIndex = uchCRCLo ^ *puchMsg++    /* calculate the CRC   */  
    uchCRCLo = uchCRCHi ^ auchCRCHi[uIndex]  uchCRCHi = auchCRCLo[uIndex]   
  }  
  return (uchCRCHi << 8 | uchCRCLo);
}


相关帖子

沙发
ngyg12| | 2015-10-27 21:10 | 只看该作者
libmodbus    freemodbus  现成的很多哦

使用特权

评论回复
板凳
manwjh|  楼主 | 2015-10-29 10:53 | 只看该作者
ngyg12 发表于 2015-10-27 21:10
libmodbus    freemodbus  现成的很多哦

能给个链接吗?

我搜索到的代码,许多都糟糕透了。

使用特权

评论回复
地板
ngyg12| | 2015-10-29 14:10 | 只看该作者
manwjh 发表于 2015-10-29 10:53
能给个链接吗?

我搜索到的代码,许多都糟糕透了。

http://libmodbus.org/

使用特权

评论回复
评分
参与人数 1威望 +3 收起 理由
manwjh + 3
5
cqwangsf| | 2016-5-29 10:24 | 只看该作者
自己写一个吧。又不难!

使用特权

评论回复
6
shizaigaole| | 2016-5-30 15:32 | 只看该作者
modbus协议比较简单,难度不大。
但是要写一个比较完全的版本,各种错误状态都有返回码的程序,
还是要花点力气的。

使用特权

评论回复
7
qianrushistm32| | 2016-6-2 09:19 | 只看该作者
freemodbus已经搞好给你了,现在还有人把slave 和master都做到了一块,master也是参照slave的框架编写的,阅读起来很顺畅

使用特权

评论回复
8
ziiiro| | 2017-7-13 23:07 | 只看该作者
标记下

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

16

主题

70

帖子

2

粉丝