51单片机modbus RTU做主站如何编程?

Hhjc12345678 2018-10-28 11:17:53
各位大神,51单片机modbus RTU做主站如何编程?
百度找了几个看了看,不是做主站的,是从站。
...全文
876 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
jobszheng5 2018-10-29
  • 打赏
  • 举报
回复
这个楼上说的基本全部,向从站请求数据需要自己发起(定时轮循或者单次触发),功能码要自己约定(与从站相互约定),寄存器地址表也要按照之前的约定实现。
都是自己编写的。
不过,由于51单片机的资源有限,所以实现自己使用的功能码即可。
笨狗先飞 2018-10-28
  • 打赏
  • 举报
回复
主站就是按Modbus要求的包排好格式发出去,然后转成接收模式,等从站回复结果就好了。 大约是这个样子,不过代码不完整,不能直接运行,只是举个例子 ModbusRead ModbusWrite就是主站向从站发指令,ModbusMaster是处理发送之后回来的数据,这部分代码只是操作了收发缓冲区。

unsigned char ModbusMaster(unsigned char *buf,unsigned char bufsize,unsigned int Address,unsigned int Count,unsigned char *target)
  //主站处理函数,用于处理从站返回来的数据  通讯缓冲区,缓冲区大小,寄存器起始地址,数量,寄存器组(当功能码为读类指令时,需要指定 寄存器起始地址,数量,寄存器组 以便于存放)
  //返回值为0时表示成功,否则有错误
{
  unsigned char result=0xFF;
  unsigned int i;
  switch(buf[1])
  {
    case 0x01:
    case 0x02:
      if(CheckCRC(buf,bufsize,5+buf[2]))//CRC检查
      {
        for(i=0;i<Count;i++) ModbusWritebit(Address+i,ModbusReadbit(i,buf+3),target);
        result=0;
      }
      break;
    case 0x03:
    case 0x04:
    case 0x17:
      if(target && CheckCRC(buf,bufsize,5+buf[2]))//CRC检查
      {
        if(Count<=buf[2]/2)
        {
          FillData(buf+3,target+Address*2,Count);
          result=0;
        }
      }
      break;
    case 0x05:
    case 0x06:
    case 0x0F:
    case 0x10:
    case 0x16:
      if(CheckCRC(buf,bufsize,8)) result=0;//CRC检查
     break;
    case 0x81:
    case 0x82:
    case 0x83:
    case 0x84:
    case 0x85:
    case 0x86:
    case 0x8F:
    case 0x90:
    case 0x96:
    case 0x97:
      if(CheckCRC(buf,bufsize,5)) result=buf[2];//CRC检查
      break;
    default:
      break;
  }
  return result;
}
//---------------------------------------------------------------代码分割线---------------------------------------------------------------//
nsigned char ModbusRead(unsigned char ID,unsigned char FC,unsigned int Address,unsigned int Count,unsigned char *buf,unsigned char bufsize)
  //主站读指令打包  设备地址,功能码,寄存器地址,数量,通讯缓冲区,缓冲区大小
  //返回值为需要发送的字节数
{
  unsigned char result=0;
  if((FC<5)&&(bufsize>=8))
  {
    result=8;
    buf[0]=ID;
    buf[1]=FC;
    ToUINT(buf+2)=Address;
    ToUINT(buf+4)=Count;
  }
  if(result) ToUINT(buf+result-2)=CRC16(buf,result-2);
  return result;
}
//---------------------------------------------------------------代码分割线---------------------------------------------------------------//
unsigned char ModbusWrite(unsigned char ID,unsigned char FC,unsigned int Address,unsigned int Count,unsigned int addr,unsigned char *source,unsigned char *buf,unsigned char bufsize)
  //主站写指令打包  设备地址,功能码,寄存器地址,数量,本地寄存器地址,本地寄存器组,通讯缓冲区,缓冲区大小
  //返回值为需要发送的字节数
{
  unsigned char result=0;
  unsigned int i;
  if(bufsize>=8)
  {
    buf[0]=ID;
    buf[1]=FC;
    ToUINT(buf+2)=Address;
    switch(FC)
    {
      case 0x05:
        ToUINT(buf+4)=(ModbusReadbit(addr,source))?0xFF00:0x0000;
        result=8;
        break;
      case 0x06:
        ToUINT(buf+4)=ModbusReadWORD(addr,source);
        result=8;
        break;
      case 0x0F:
        ToUINT(buf+4)=Count;
        buf[6]=(Count%8)?Count/8+1:Count/8;
        if(bufsize>=buf[6])
        {
          for(i=0;i<Count;i++)
          {
            if(i%8==0) buf[7+i/8]=0; 
            ModbusWritebit(i,ModbusReadbit(addr+i,source),buf+7);
          }
          result=9+buf[6];
        }
        break;
      case 0x10:
        ToUINT(buf+4)=Count;
        buf[6]=Count*2;
        if(bufsize>=9+buf[6])
        {
          FillData(source+addr*2,buf+7,Count);
          result=9+buf[6];
        }
        break;
      default:
        break;
    }
    if(result) ToUINT(buf+result-2)=CRC16(buf,result-2);
  }
  return result;
}

27,373

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 单片机/工控
社区管理员
  • 单片机/工控社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧