搜索
bottom↓
回复: 12

半成品MODBUS RTU协议+组态王上位机+SHT11 Proteus仿真

[复制链接]

出0入0汤圆

发表于 2014-7-3 21:13:55 | 显示全部楼层 |阅读模式
本帖最后由 slzm40 于 2014-7-3 21:17 编辑

  终归是半成品,数据也没做储存,SHT11也没有软件校准,纯读出。只为调MODBUS RTU协议,控制也乱七八糟的。 在这里也学习了有两年之久,发一发顺便有什么错误的地方求指点,以便进步。
   整个东西在Proteus+keil4+组态王6.55+虚拟串口工具仿真出来,程序没做任何数据储存,本机地址上电初始化为0x01,可设置但掉电后重新上电为01,我没有用EEPROM。
  总而言之,完全是做调试用。简单不能再简单了,手上已有SHT11的模块了,打算过些时间做个板子实测下,然后再做软件校准和一些未做完的事(比如数据储存,上位机完善,多机通信,主机板和主机程序)
        功能和协议
         
        界面1
       
        界面2
       
        组态王界面,够简单吧
       
        历史数据曲线
       
        上MODBUS 的协议解码部份。
  1. void ModbusHandle(void)
  2. {
  3.         INT16U crctemp,crctemp1;
  4.         INT8U addr,readCount,temp,crx;
  5.         INT8U RXBUF[MAX_RXLenth];
  6.         if(UARTMod.fRx)//接收完毕
  7.         {
  8.         crx=UARTMod.Crx;
  9.         memset(RXBUF,00,sizeof(RXBUF));//清空缓冲区
  10.         memcpy(RXBUF,&UARTMod.RxBuffer[0],crx+1);//数据拷贝,这样就可以让UART重新接收数据了
  11.         memset(&UARTMod,00,sizeof(UARTMod));//将UARTMod清空,可重新接收数据
  12.         //UARTMod.fRx=FALSE;//让接收器进行接收
  13.        
  14.         if(RXBUF[0]!=LOCAL_ADD)//不是本机地址返回不处理
  15.                 {
  16.                 return;
  17.                 }
  18.         crctemp=UpdateCRC(&RXBUF[0],crx-2);//CRC校验
  19.         crctemp1=RXBUF[crx-2]<<8|RXBUF[crx-1];
  20.         if((crctemp-crctemp1)!=0)//检验检验是否正确
  21.                 {
  22.                 return;
  23.                 }
  24.         switch(RXBUF[1])//功能码
  25.                 {
  26.                 case 0x01:        //读取输出线圈状态
  27.                                         //slaveADD+funID+  ioADD_H+ioADD_L  +  ioNUM_H+ioNUM_L  +  crc_H+crc_L
  28.                                         //slaveADD+funID+  NUM  +  数据(NUM)  +  crc_H+crc_L       
  29.                                          addr=RXBUF[3];          //获取起始地址
  30.                                             readCount =RXBUF[5];//获取读取线圈个数
  31.                                         if(addr>(OXNum*8-1)||readCount>(OXNum*8-addr)) return;       
  32.                                         //应答处理
  33.                                         UARTMod.TxBuffer[0]=LOCAL_ADD;//地址
  34.                                             UARTMod.TxBuffer[1]=0x01;//功能码
  35.                                            
  36.                                             //因为只设计16个输出线圈,所以
  37.                                             if(readCount>8)  UARTMod.TxBuffer[2]=2; //字节计数
  38.                                          else  UARTMod.TxBuffer[2]=1;
  39.                                          
  40.                                         crctemp=(OX[1]<<8)|OX[0];//输出线圈统一
  41.                                            crctemp=crctemp>>addr;
  42.                                             if(readCount>8)
  43.                                                      {
  44.                                                 UARTMod.TxBuffer[3]=crctemp&0xff;//低
  45.                                                 temp=0xff;
  46.                                                 temp=temp<<(readCount-8);
  47.                                                 temp=~temp;
  48.                                                 crctemp=crctemp>>8;
  49.                                                 crctemp=temp&crctemp;
  50.                                                 UARTMod.TxBuffer[4]=crctemp&0xff;//高
  51.                                                 crctemp=UpdateCRC(&UARTMod.TxBuffer[0],5);
  52.                                                 UARTMod.TxBuffer[5]=crctemp>>8;
  53.                                                 UARTMod.TxBuffer[6]=crctemp&0xff;                                                           
  54.                                                 USART_send_string(7);
  55.                                                      }
  56.                                             else
  57.                                                     {
  58.                                                         temp=0xff;
  59.                                                         temp=temp<<readCount;
  60.                                                         temp=~temp;
  61.                                                         crctemp=crctemp&temp;
  62.                                                         UARTMod.TxBuffer[3]=crctemp&0xff;
  63.                                                         crctemp=UpdateCRC(&UARTMod.TxBuffer[0],4);//发送数据CRC校验
  64.                                                         UARTMod.TxBuffer[4]=crctemp>>8;//校验高8位
  65.                                                         UARTMod.TxBuffer[5]=crctemp&0xff;//校验低8位                                                           
  66.                                                               USART_send_string(6);//发送回应
  67.                                                     }
  68.                                 break;
  69.                 case 0x02:                //读取输入线圈状态
  70.                                                 //slaveADD+funID+  ioADD_H+ioADD_L  +  ioNUM_H+ioNUM_L  +  crc_H+crc_L
  71.                                                 //slaveADD+funID+  NUM  +  数据(NUM)  +  crc_H+crc_L       
  72.                                                  addr=RXBUF[3];          //获取起始地址 (不同于寄存器)
  73.                                                     readCount =RXBUF[5];//获取读取线圈个数
  74.                                                 if(addr>(OXNum*8-1)||readCount>(OXNum*8-addr)) return;       
  75.                                                 //应答处理
  76.                                                 UARTMod.TxBuffer[0]=LOCAL_ADD;//地址
  77.                                                     UARTMod.TxBuffer[1]=0x01;//功能码
  78.                                                     //因为只设计16个线圈,所以
  79.                                                     if(readCount>8)  UARTMod.TxBuffer[2]=2; //字节计数
  80.                                                  else  UARTMod.TxBuffer[2]=1;
  81.                                                  
  82.                                                 crctemp=(IX[1]<<8)|IX[0];//输入线圈统一
  83.                                                    crctemp=crctemp>>addr;
  84.                                                     if(readCount>8)
  85.                                                              {
  86.                                                         UARTMod.TxBuffer[3]=crctemp&0xff;//低
  87.                                                         temp=0xff;
  88.                                                         temp=temp<<(readCount-8);
  89.                                                         temp=~temp;
  90.                                                         crctemp=crctemp>>8;
  91.                                                         crctemp=temp&crctemp;
  92.                                                         UARTMod.TxBuffer[4]=crctemp&0xff;//高
  93.                                                         crctemp=UpdateCRC(&UARTMod.TxBuffer[0],5);
  94.                                                         UARTMod.TxBuffer[5]=crctemp>>8;
  95.                                                         UARTMod.TxBuffer[6]=crctemp&0xff;                                                           
  96.                                                         USART_send_string(7);
  97.                                                              }
  98.                                                     else
  99.                                                             {
  100.                                                                 temp=0xff;
  101.                                                                 temp=temp<<readCount;
  102.                                                                 temp=~temp;
  103.                                                                 crctemp=crctemp&temp;
  104.                                                                 UARTMod.TxBuffer[3]=crctemp&0xff;
  105.                                                                 crctemp=UpdateCRC(&UARTMod.TxBuffer[0],4);//发送数据CRC校验
  106.                                                                 UARTMod.TxBuffer[4]=crctemp>>8;//校验高8位
  107.                                                                 UARTMod.TxBuffer[5]=crctemp&0xff;//校验低8位                                                           
  108.                                                                       USART_send_string(6);//发送回应
  109.                                                             }
  110.                                         break;
  111.                 case 0x03:                //读取保持寄存器
  112.                                                 //slaveADD+funID+datADD_H+dataADD_L+regNUM_H+regNUM_L+crc_H+crc_L
  113.                                                 //slaveADD+funID+2*regNUM+数据(2*regNUM个BYTE)+crc_H+crc_L
  114.                                                 //                                                低地址数据->高地址数据(DAT_H+DAT_L)
  115.                                                 //slaveADD+(funID|0x80)+01(02,03,04)+crc_H+crc_L
  116.                                                 addr=RXBUF[3];          //要读的地址 0~16
  117.                                                 readCount =RXBUF[5];  //要读的个数(16位)
  118.                                                 if(addr>(HoldDataNum-1)||readCount>(HoldDataNum-addr)||readCount>125) return;
  119.                                                 //应答处理
  120.                                                 UARTMod.TxBuffer[0]=LOCAL_ADD;     //目标机地址
  121.                                                 UARTMod.TxBuffer[1]=0x03;          //功能码
  122.                                                 UARTMod.TxBuffer[2]=readCount*2;   //返回字节个数(8位)
  123.                                                 for(temp=0;temp<readCount;temp++)  //低地址数据在前
  124.                                                         {
  125.                                                         UARTMod.TxBuffer[temp*2+3]=(HoldDataReg[temp+addr]>>8)&0xff;//数据高字节在前
  126.                                                         UARTMod.TxBuffer[temp*2+4]=HoldDataReg[temp+addr]&0xff;//数据低字节在前
  127.                                                         }//数据
  128.                                                 crctemp=UpdateCRC(&UARTMod.TxBuffer[0],readCount*2+3);  //求CRC
  129.                                                 UARTMod.TxBuffer[readCount*2+3]=crctemp>>8;
  130.                                                 UARTMod.TxBuffer[readCount*2+4]=crctemp&0xff;                                                            
  131.                                                 USART_send_string(readCount*2+5);
  132.                                 break;
  133.                 case 0x04:                //读取输入寄存器
  134.                                                 //slaveADD+funID+  datADD_H+dataADD_L  +  regNUM_H+regNUM_L   +   crc_H+crc_L
  135.                                                 //slaveADD+funID+2*regNUM+数据(2*regNUM个BYTE)   +   crc_H+crc_L
  136.                                                 //                                                低地址数据->高地址数据(DAT_H+DAT_L)
  137.                                                 //slaveADD+(funID|0x80)+01(02,03,04)+crc_H+crc_L
  138.                                                 addr=RXBUF[3];          //要读的地址 0~HoldDataNum-1
  139.                                                 readCount =RXBUF[5];  //要读的个数(16位)<=125
  140.                                                 if(addr>(InDataNum-1)||readCount>(InDataNum-addr)||readCount>125) return;
  141.                                                 //应答处理
  142.                                                 UARTMod.TxBuffer[0]=LOCAL_ADD;     //目标机地址
  143.                                                 UARTMod.TxBuffer[1]=0x04;          //功能码
  144.                                                 UARTMod.TxBuffer[2]=readCount*2;   //返回字节个数(8位)
  145.                                                 for(temp=0;temp<readCount;temp++)  //低地址数据在前
  146.                                                         {
  147.                                                         UARTMod.TxBuffer[temp*2+3]=(InDataReg[temp+addr]>>8)&0xff;//数据高字节在前
  148.                                                         UARTMod.TxBuffer[temp*2+4]=InDataReg[temp+addr]&0xff;//数据低字节在前
  149.                                                         }//数据
  150.                                                 crctemp=UpdateCRC(&UARTMod.TxBuffer[0],readCount*2+3);  //求CRC
  151.                                                 UARTMod.TxBuffer[readCount*2+3]=crctemp>>8;
  152.                                                 UARTMod.TxBuffer[readCount*2+4]=crctemp&0xff;                                                            
  153.                                                 USART_send_string(readCount*2+5);
  154.                                 break;
  155.                 case 0x05:                //设置单个线圈
  156.                                                 //slaveADD+funID+  ioADD_H+ioADD_L  +  SETVAL_H  +        SETVAL_L +  crc_H+crc_L
  157.                                                 //原报文返回
  158.                                                 addr=RXBUF[3];    //获取起始地址 (不同于寄存器)
  159.                                                 temp=RXBUF[4];    //要设置的状态(0xff为ON,0x00为OFF)
  160.                                                 //以下为设置
  161.                                                 if(temp==0xff)        //置1
  162.                                                 {
  163.                                                         if(addr>=8)
  164.                                                                 {
  165.                                                                 temp=1<<(addr-8);
  166.                                                                 OX[1]=OX[1]|temp;
  167.                                                                 }
  168.                                                         else {
  169.                                                                 temp=1<<addr;
  170.                                                                 OX[0]=OX[0]|temp;
  171.                                                                 }
  172.                                                 }
  173.                                                 else                        //置0
  174.                                                 {
  175.                                                         if(addr>=8)
  176.                                                                 {
  177.                                                                 temp=1<<(addr-8);
  178.                                                                 temp=~temp;
  179.                                                                 OX[1]=OX[1]&temp;
  180.                                                                 }
  181.                                                         else
  182.                                                                 {
  183.                                                                 temp=1<<addr;
  184.                                                                 temp=~temp;
  185.                                                                 OX[0]=OX[0]&temp;
  186.                                                                 }
  187.                                                 }
  188.                                                
  189.                                                 //应答处理,原报文回应
  190.                                                 UARTMod.TxBuffer[0]=LOCAL_ADD;
  191.                                                 UARTMod.TxBuffer[1]=0x05;
  192.                                                 UARTMod.TxBuffer[2]=0x00;
  193.                                                 UARTMod.TxBuffer[3]=addr;
  194.                                                 UARTMod.TxBuffer[4]=RXBUF[4];
  195.                                                 UARTMod.TxBuffer[5]=RXBUF[5];
  196.                                                 UARTMod.TxBuffer[6]=RXBUF[6];
  197.                                                 UARTMod.TxBuffer[7]=RXBUF[7];                                                           
  198.                                                 USART_send_string(8);
  199.                                 break;
  200.                 case 0x06:                //设置单个寄存器
  201.                                                 //slaveADD+funID+  datADD_H+dataADD_L  +  datVAL_H+datVAL_L   +   crc_H+crc_L
  202.                                                 //slaveADD+funID+2*regNUM+数据(2*regNUM个BYTE)   +   crc_H+crc_L
  203.                                                 //                                                低地址数据->高地址数据(DAT_H+DAT_L)
  204.                                                 addr=RXBUF[3];          //要读的地址 0~HoldDataNum-1
  205.                                                 crctemp =RXBUF[4]<<8|RXBUF[5];  //要写的数据
  206.                                                 //以下为设置
  207.                                                 HoldDataReg[addr]=crctemp;
  208.                                                
  209.                                                 //应答处理,原报文回应
  210.                                                 UARTMod.TxBuffer[0]=LOCAL_ADD;
  211.                                                 UARTMod.TxBuffer[1]=0x06;
  212.                                                 UARTMod.TxBuffer[2]=0x00;
  213.                                                 UARTMod.TxBuffer[3]=addr;
  214.                                                 UARTMod.TxBuffer[4]=RXBUF[4];
  215.                                                 UARTMod.TxBuffer[5]=RXBUF[5];
  216.                                                 UARTMod.TxBuffer[6]=RXBUF[6];
  217.                                                 UARTMod.TxBuffer[7]=RXBUF[7];                                                           
  218.                                                 USART_send_string(8);               
  219.                                 break;
  220.                 case 0x0f:                //设置多个线圈
  221.                                 break;
  222.                 case 0x10:                //预置多个寄存器
  223.                                 break;
  224.                 default:                        //返回错误码(不支持功能号)
  225.                                 break;
  226.                 }                 
  227.         }

  228. }
复制代码


最后还是上附件吧。顺便问下,我有CC1101的两个无线模块,无线通信协议目前用哪种。或有没相关资料学习下






本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

 楼主| 发表于 2014-7-3 21:20:25 | 显示全部楼层
        另外感谢hmd420304805 的贴子,他的在这里http://www.amobbs.com/forum.php? ... 4%E6%80%81%E7%8E%8B
也是MODBUS RTU协议,很早以前在这贴子学习了MODBUS

出0入0汤圆

发表于 2014-7-3 23:40:07 来自手机 | 显示全部楼层
不懂帮顶  看着真的很厉害

出0入0汤圆

发表于 2014-7-4 08:23:25 | 显示全部楼层

出0入0汤圆

 楼主| 发表于 2014-7-4 23:38:02 | 显示全部楼层
自己准备研读freemodbus的源码,必竟自己写的代码没有1.5个位判断和3.5个位的判断,也不够完善。 在用modbus poll,测试了1000次。发现有100次读数据超时。。。

出0入0汤圆

发表于 2014-7-5 08:17:30 | 显示全部楼层
组态王用的破解版吗?能共享一下不?

出0入0汤圆

 楼主| 发表于 2014-7-5 13:56:57 | 显示全部楼层
本帖最后由 slzm40 于 2014-7-5 13:58 编辑
cqfeiyu 发表于 2014-7-5 08:17
组态王用的破解版吗?能共享一下不?


  我在网上找的。好像只有破解65000个点。版本6.55,做了个小监控软件,监控温湿度已经有一个多星期了,应该没有问题。网址http://zhidao.baidu.com/link?url ... UvfTZjngMTCuB7Y8dsK

出0入0汤圆

发表于 2014-7-5 15:30:37 | 显示全部楼层
看起来好高端的组态王 mark

出0入0汤圆

发表于 2014-7-5 16:23:38 | 显示全部楼层
slzm40 发表于 2014-7-5 13:56
我在网上找的。好像只有破解65000个点。版本6.55,做了个小监控软件,监控温湿度已经有一个多星期了, ...

谢了,做试验用还是可以的

出0入0汤圆

发表于 2014-7-5 16:25:11 | 显示全部楼层
Modbus 还是建议用FreeModbus稳定

出0入0汤圆

发表于 2018-4-14 21:15:56 | 显示全部楼层

出0入0汤圆

发表于 2018-6-12 17:21:42 | 显示全部楼层
感谢分享,用一个modbus上位机试了试,目前测试了读取那个仪表里面的数据,有时候读取出来的值会有差异,
不知道是不是modbus 按字或字节读取的方式不正确呢还是其他的原因,还没有好好研究

出0入0汤圆

发表于 2018-6-12 17:23:51 | 显示全部楼层
楼主继续完善弄成成品吧
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-27 03:17

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表