找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 12573|回复: 36
打印 上一主题 下一主题
收起左侧

51单片机MODBUS程序源码与ModBusPol(上位机测试软件)下载

  [复制链接]
跳转到指定楼层
楼主
ID:404756 发表于 2018-10-1 22:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
MODBUS-51工程版从机,附带ModBusPol上位机测试软件




单片机源程序如下:
  1. #include "modbus.h"
  2. #include "resister.h"
  3. /******************数据举例,移植数据定义修改区,resister.h也需要修改***********************************/
  4. uint ROdat[3]={1,123,456};          //3个只读整型
  5. uint RWdat[3]={1,123,456};          //3个可读可写整型
  6. float temp=23.4;                                                                         //一个浮点型
  7. long   adc=789654;                                                                        //一个long型
  8. bit    ROstatus0=0;                              //只读线圈
  9. bit    ROstatus1=1;                              //只读线圈
  10. bit    RWstatus0=0;                              //可读可写线圈
  11. bit    RWstatus1=1;                              //可读可写线圈

  12. /********************************************************************
  13. modbus RTU 的C51程序
  14. 单片机AT89C51          11.0592MHZ
  15. 通信波特率 9600 8位数据 1位停止位  485通位接口
  16. 单片机控制板地址 localAddr(变量)
  17. 0x01 0x03 0x00 0x00 0x01 0x84 0x0a
  18. **********************************************************************/
  19. uchar LocalAddr = 0x01; //单片机控制板的地址

  20. /***********************************************/
  21. union uf
  22. {
  23. uint x[2];
  24. float y;
  25. }ftemp;

  26. union ul
  27. {
  28. uint x[2];
  29. long y;
  30. }ltemp;

  31. uchar receTimeOut;                //接收超时
  32. uchar sendCount;  //发送字节个数
  33. uchar receCount;    //接收到的字节个数
  34. uchar receBuf[50];
  35. uchar sendBuf[50];
  36. bit   bt1ms;       //定时标志位


  37. /* CRC 高位字节值表 */
  38. uchar code auchCRCHi[] = {
  39. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0/**/,
  40. 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  41. 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
  42. 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
  43. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
  44. 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
  45. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
  46. 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  47. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
  48. 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
  49. 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
  50. 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
  51. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
  52. 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
  53. 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
  54. 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
  55. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
  56. 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  57. 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
  58. 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  59. 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
  60. 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
  61. 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
  62. 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  63. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
  64. 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
  65. } ;
  66. /* CRC低位字节值表*/
  67. uchar code auchCRCLo[] = {
  68. 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06/**/,
  69. 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
  70. 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,                   
  71. 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
  72. 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
  73. 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
  74. 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
  75. 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
  76. 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
  77. 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
  78. 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
  79. 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
  80. 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
  81. 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
  82. 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
  83. 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
  84. 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
  85. 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
  86. 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
  87. 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
  88. 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
  89. 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
  90. 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
  91. 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
  92. 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
  93. 0x43, 0x83, 0x41, 0x81, 0x80, 0x40
  94. } ;


  95. //-------------------------------定时器0 1ms 中断 -------------------------
  96. void timer0_IntProc() interrupt 1
  97. {
  98.         TL0 = 0x66;               
  99.         TH0 = 0xFC;       
  100.     bt1ms = 1;

  101. }

  102. void presetSingleRegister(void);
  103. uint setCoilVal(uint addr,uint tempData);
  104. uint getCoilVal(uint addr,uint *tempData);
  105. uint getRegisterVal(uint addr,uint *tempData);
  106. uint setRegisterVal(uint addr,uint tempData);



  107. //--------------------------------串行中断程序---------------------------
  108. void comm_IntProc() interrupt 4
  109. {
  110.        if(RI)
  111.         {
  112.              RI = 0;  
  113.                 receTimeOut = 10;    //通讯超时值这个地方很重要        10ms
  114.                 receBuf[receCount] = SBUF;
  115.                         receCount++;          //接收地址偏移寄存器加1                                 
  116.         }
  117.                 if(TI)
  118.                 TI=0;       

  119. }   

  120. //------------------------------------定时处理--------------------------------
  121. void timeProc(void)
  122. {
  123.         if(bt1ms)
  124.         {
  125.            bt1ms = 0;
  126.                if(receTimeOut>0)
  127.                       {
  128.                     receTimeOut--;
  129.             if(receTimeOut==0 && receCount>0)   //判断通讯接收是否超时
  130.                     {
  131.                         b485Send = 0;    //将485置为接收状态                                                                                                                                                              
  132.                         receCount = 0;//      //将接收地址偏移寄存器清零
  133.                             }
  134.                       }
  135.         }
  136. }


  137. //-----------------------------初始化中断------------------------------------
  138. void InitUartAndTimer0(void)
  139. {
  140.         TMOD= 0x21;    //T0用于定时,T1用于波特
  141.                 TL0 = 0x66;               
  142.                 TH0 = 0xFC;       
  143.         TR0   = 1;        
  144.         ET0   = 1; //开中断T0
  145.                 //-----------------------------------------------
  146.                 SCON=0x50;
  147.                 TH1=0xfd;
  148.                 TL1=0xfd;
  149.                 TR1=1;
  150.                 EA=1;
  151.                 ES=1;
  152.                 TI=0;   
  153.                 b485Send = 0;      //处于接收


  154. }   
  155. //--------------------------初始化-----------------------------
  156. void initProg(void)
  157. {        
  158.         InitUartAndTimer0();       
  159. }




  160. /***************************CRC校验码生成函数 ********************************/
  161. uint crc16(uchar *puchMsg, uint usDataLen)
  162. {
  163. uchar uchCRCHi = 0xFF ; /* 高CRC字节初始化 */
  164. uchar uchCRCLo = 0xFF ; /* 低CRC 字节初始化 */
  165. uint uIndex ; /* CRC循环中的索引 */
  166. while (usDataLen--) /* 传输消息缓冲区 */
  167. {
  168.   uIndex = uchCRCHi ^ *puchMsg++ ; /* 计算CRC */
  169.   uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;
  170.   uchCRCLo = auchCRCLo[uIndex] ;
  171. }
  172. return (uchCRCLo << 8 | uchCRCHi) ;
  173. }

  174. void uartsends(uchar buff[],uchar len)
  175. {
  176.         uchar i;
  177.         for(i=0;i<len;i++)
  178.         {
  179.                 SBUF=buff[i];
  180.                 while(!TI);
  181.                 TI=0;
  182.         }
  183. }                               
  184. /*******************************串口发送函数 ********************************/
  185. void Begin_send(void)
  186. {
  187.         b485Send = 1;      //处于发送
  188.         uartsends(sendBuf,sendCount);
  189.         b485Send = 0;              //发送完后将485置于接收状态
  190.     receCount = 0;   //清接收地址偏移寄存器
  191. }


  192. //fuction:01 读单个或多个线圈状态
  193. void readCoils(void)
  194. {
  195. uint addr;
  196. uint tempAddr;
  197. uint byteCount;
  198. uint  bitCount;
  199. uint crcData;
  200. uint  position;
  201. uint  i,k;
  202. uint tempData;
  203. uchar  exit = 0;
  204. addr = (receBuf[2]<<8) + receBuf[3];
  205. tempAddr = addr;
  206. bitCount = (receBuf[4]<<8) + receBuf[5]; //读取的位个数
  207. byteCount = bitCount / 8;    //字节个数
  208. if(bitCount%8 != 0)
  209.   byteCount++;      
  210.   for(k=0;k<byteCount;k++)//字节位置
  211.   {
  212.     position = k + 3;
  213.     sendBuf[position] = 0;
  214.     for(i=0;i<8;i++)
  215.     {
  216.       getCoilVal(tempAddr,&tempData);
  217.       sendBuf[position] |= tempData << i;
  218.       tempAddr++;
  219.       if(tempAddr >= addr+bitCount)//读完
  220.       {
  221.         exit = 1;
  222.         break;
  223.       }
  224.     }
  225.     if(exit == 1)
  226.     break;
  227.   }
  228.   sendBuf[0] = LocalAddr;
  229.   sendBuf[1] = 0x01;
  230.   sendBuf[2] = byteCount;
  231.   byteCount += 3;
  232.   crcData = crc16(sendBuf,byteCount);
  233.   sendBuf[byteCount] = crcData & 0xff;
  234.   byteCount++;
  235.   sendBuf[byteCount] = crcData >> 8;
  236.   sendCount = byteCount + 1;
  237.   Begin_send();   
  238. }

  239. //fuction:02 读取线圈输入(只读寄存器)状态
  240. void readInPutCoils(void)
  241. {
  242. uint addr;
  243. uint tempAddr;
  244. uint byteCount;
  245. uint  bitCount;
  246. uint crcData;
  247. uint  position;
  248. uint  i,k;
  249. uint tempData;
  250. uchar  exit = 0;
  251. addr = (receBuf[2]<<8) + receBuf[3];
  252. tempAddr = addr +10000;        //只读线圈寄存器偏移地址10000
  253. bitCount = (receBuf[4]<<8) + receBuf[5]; //读取的位个数
  254. byteCount = bitCount / 8;    //字节个数
  255. if(bitCount%8 != 0)
  256.   byteCount++;      
  257.   for(k=0;k<byteCount;k++)//字节位置
  258.   {
  259.     position = k + 3;
  260.     sendBuf[position] = 0;
  261.     for(i=0;i<8;i++)
  262.     {
  263.       getCoilVal(tempAddr,&tempData);
  264.       sendBuf[position] |= tempData << i;
  265.       tempAddr++;
  266.       if(tempAddr >= addr+bitCount)//读完
  267.       {
  268.         exit = 1;
  269.         break;
  270.       }
  271.     }
  272.     if(exit == 1)
  273.     break;
  274.   }
  275.   sendBuf[0] = LocalAddr;
  276.   sendBuf[1] = 0x02;
  277.   sendBuf[2] = byteCount;
  278.   byteCount += 3;
  279.   crcData = crc16(sendBuf,byteCount);
  280.   sendBuf[byteCount] = crcData & 0xff;
  281.   byteCount++;
  282.     sendBuf[byteCount] = crcData >> 8;
  283.   sendCount = byteCount + 1;
  284.   Begin_send();   
  285. }

  286. /********function code : 03,读取多个寄存器值 ********/

  287. void readRegisters(void)
  288. {
  289.         uint addr;
  290.         uint tempAddr;
  291.         uint crcData;
  292.         uint readCount;
  293.         uint byteCount;
  294.         uint i;
  295.         uint tempData = 0;
  296.         addr = (receBuf[2]<<8) + receBuf[3];
  297.         tempAddr = addr+40000;      //+40000,保持寄存器偏移地址
  298.         readCount = (receBuf[4]<<8) + receBuf[5]; //要读的个数 ,整型
  299.         byteCount = readCount * 2;                  //每个寄存器内容占高,低两个字节
  300.         for(i=0;i<byteCount;i+=2,tempAddr++)
  301.         {
  302.               getRegisterVal(tempAddr,&tempData);   
  303.               sendBuf[i+3] = tempData >> 8;        
  304.               sendBuf[i+4] = tempData & 0xff;  
  305.         }
  306.         sendBuf[0] = LocalAddr;
  307.         sendBuf[1] = 3;  //function code : 03
  308.         sendBuf[2] = byteCount;
  309.         byteCount += 3;             //加上前面的地址,功能码,地址 共3+byteCount个字节
  310.         crcData = crc16(sendBuf,byteCount);
  311.         sendBuf[byteCount] = crcData & 0xff;   // CRC代码低位在前
  312.         byteCount++;
  313.         sendBuf[byteCount] = crcData >> 8 ;           //高位在后
  314.         sendCount = byteCount + 1;                        //例如byteCount=49,则sendBuf[]中实际上有49+1个元素待发
  315.         Begin_send();
  316. }
  317. //fuction 04:读取输入寄存器
  318. void readInPutRegisters(void)
  319. {
  320.         uint addr;
  321.         uint tempAddr;
  322.         uint crcData;
  323.         uint readCount;
  324.         uint byteCount;
  325.         uint i;
  326.         uint tempData = 0;
  327.         addr = (receBuf[2]<<8) + receBuf[3];
  328.         tempAddr = addr+30000;  //+输入寄存器偏移地址:30000
  329.         readCount = (receBuf[4]<<8) + receBuf[5]; //要读的个数 ,整型
  330.         byteCount = readCount * 2;                  //每个寄存器内容占高,低两个字节
  331.         for(i=0;i<byteCount;i+=2,tempAddr++)
  332.         {
  333.               getRegisterVal(tempAddr,&tempData);   
  334.               sendBuf[i+3] = tempData >> 8;        
  335.               sendBuf[i+4] = tempData & 0xff;  
  336.         }
  337.         sendBuf[0] = LocalAddr;
  338.         sendBuf[1] = 4;  //function code : 04
  339.         sendBuf[2] = byteCount;
  340.         byteCount += 3;             //加上前面的地址,功能码,地址 共3+byteCount个字节
  341.         crcData = crc16(sendBuf,byteCount);
  342.         sendBuf[byteCount] = crcData & 0xff;   // CRC代码低位在前
  343.         byteCount++;
  344.         sendBuf[byteCount] = crcData >> 8 ;           //高位在后
  345.         sendCount = byteCount + 1;                        //例如byteCount=49,则sendBuf[]中实际上有49+1个元素待发
  346.         Begin_send();
  347. }
  348.          
  349. //fuction:05 ,强制单个线圈
  350. void forceSingleCoil(void)
  351. {
  352. uint addr;
  353. uint tempAddr;
  354. uint tempData;
  355. uint  onOff;
  356. uchar i;
  357. addr = (receBuf[2]<<8) + receBuf[3];
  358. tempAddr = addr;
  359. onOff = (receBuf[4]<<8) + receBuf[5];
  360. if(onOff == 0xff00)
  361. {
  362.   tempData = 1;//设为ON
  363. }
  364. else if(onOff == 0x0000)//设为OFF
  365. {
  366.   tempData = 0;
  367. }
  368. setCoilVal(tempAddr,tempData);
  369. for(i=0;i<receCount;i++)
  370. {
  371.   sendBuf[i] = receBuf[i];
  372. }
  373. sendCount = receCount;
  374. Begin_send();
  375. }

  376. /****************fuction:06设置单个寄存器ok**********************************************************/

  377. //主机器发送  地址,功能码,寄存器高位,寄存器低位,数据数高位, 数数低位,CRC低位,CRC高位
  378. //例如设置D0 发送,        01      06         00            3F       00                         01                   */
  379. /*********************************************************************************/

  380. void presetSingleRegister(void)
  381. {
  382. uint addr;
  383. uint tempAddr;
  384. uint tempData;
  385. uint crcData;
  386. addr = (receBuf[2]<<8) + receBuf[3];
  387. tempAddr = (addr+40000);
  388. tempData = (receBuf[4]<<8) + receBuf[5];
  389. setRegisterVal(tempAddr,tempData);  
  390. sendBuf[0] = LocalAddr;
  391. sendBuf[1] = 6;    //function code : 16
  392. sendBuf[2] = addr >> 8;  //寄存器地址高位
  393. sendBuf[3] = addr & 0xff;//寄存器地址低位
  394. sendBuf[4] =receBuf[4];
  395. sendBuf[5] =receBuf[5];
  396. crcData = crc16(sendBuf,6);//生成CRC校验码
  397. sendBuf[6] = crcData & 0xff;  //CRC代码低位在前
  398. sendBuf[7] = crcData >> 8;          //高位在后
  399. sendCount = 8;
  400. Begin_send();
  401. }

  402. /********从机响应主机问询函数,function code : 15,强置多线圈值 *********/
  403. //////////////询问数据包格式:
  404. ///////////////////////// receBuf[0] receBuf[1]  receBuf[2]     receBuf[3]   receBuf[4]    receBuf[5]   receBuf[6]  receBuf[7]  receBuf[8] ... receBuf[9]   receBuf[10]
  405. //询问数据格式:receBuf[]={从站地址, 功能码,  起始地址高位,起始地址低位,寄存器数高位,寄存器数低位, 字节计数,  数据高位,  数据低位,... 校验码低位, 校验码高位}
  406. /****************************************************************************/
  407. void forceMultipleCoils(void)
  408. {
  409. uint addr;
  410. uint tempAddr;
  411. uint byteCount;
  412. uint  bitCount;
  413. uint crcData;
  414. uint tempData;
  415. uint  i,k;
  416. uchar  exit = 0;
  417. addr = (receBuf[2]<<8) + receBuf[3];
  418. tempAddr = addr;
  419. bitCount = (receBuf[4]<<8) + receBuf[5];
  420. byteCount = bitCount / 8;    //字节个数
  421. if(bitCount%8 != 0)
  422.   byteCount++;     
  423.   for(k=0;k<byteCount;k++)//字节位置
  424.   {
  425.     for(i=0;i<8;i++)
  426.     {
  427.       tempData = (receBuf[k+3] >>i)&0x01;  
  428.       setCoilVal(tempAddr,tempData);
  429.       tempAddr++;
  430.       if(tempAddr >= addr+bitCount)//读完
  431.       {
  432.         exit = 1;
  433.         break;
  434.       }
  435.     }
  436.   
  437.     if(exit == 1)
  438.     break;
  439.   }
  440. sendBuf[0] = LocalAddr;
  441. sendBuf[1] = 15;    //function code : 16
  442. sendBuf[2] = addr >> 8;  //寄存器地址高位
  443. sendBuf[3] = addr & 0xff;//寄存器地址低位
  444. sendBuf[4] = bitCount >> 8;//待设置寄存器数量高位
  445. sendBuf[5] = bitCount & 0xff;//待设置寄存器数量低位
  446. crcData = crc16(sendBuf,6);//生成CRC校验码
  447. sendBuf[6] = crcData & 0xff;  //CRC代码低位在前
  448. sendBuf[7] = crcData >> 8;          //高位在后
  449. sendCount = 8;
  450. Begin_send();
  451. }

  452. /********从机响应主机问询函数,function code : 16,设置多个寄存器值 *********/
  453. //////////////询问数据包格式:
  454. ///////////////////////// receBuf[0] receBuf[1]  receBuf[2]     receBuf[3]   receBuf[4]    receBuf[5]   receBuf[6]  receBuf[7]  receBuf[8] ... receBuf[9]   receBuf[10]
  455. //询问数据格式:receBuf[]={从站地址, 功能码,  起始地址高位,起始地址低位,寄存器数高位,寄存器数低位, 字节计数,  数据高位,  数据低位,... 校验码低位, 校验码高位}
  456. /****************************************************************************/
  457. void presetMultipleRegisters(void)
  458. {
  459. uint addr;
  460. uint tempAddr;
  461. uint setCount;
  462. uint crcData;
  463. uint tempData;
  464. uchar i;
  465. addr = (receBuf[2]<<8) + receBuf[3];
  466. tempAddr = addr+40000;
  467. setCount = (receBuf[4]<<8) + receBuf[5];
  468. for(i=0;i<setCount;i++,tempAddr++)
  469. {
  470.   tempData = (receBuf[i*2+7]<<8) + receBuf[i*2+8];//待设置寄存器值
  471.   setRegisterVal(tempAddr,tempData);  
  472. }
  473. sendBuf[0] = LocalAddr;
  474. sendBuf[1] = 16;    //function code : 16
  475. sendBuf[2] = addr >> 8;  //寄存器地址高位
  476. sendBuf[3] = addr & 0xff;//寄存器地址低位
  477. sendBuf[4] = setCount >> 8;//待设置寄存器数量高位
  478. sendBuf[5] = setCount & 0xff;//待设置寄存器数量低位
  479. crcData = crc16(sendBuf,6);//生成CRC校验码
  480. sendBuf[6] = crcData & 0xff;  //CRC代码低位在前
  481. sendBuf[7] = crcData >> 8;          //高位在后
  482. sendCount = 8;
  483. Begin_send();
  484. }


  485. /*************************查询uart接收的数据包内容函数 **************************/
  486. ////函数功能:丛机根据串口接收到的数据包receBuf[1]里面的内容,即function code执行相应的命令
  487. /********************************************************************************/
  488. void checkComm0Modbus(void)                   //10ms内必须响应接收数据
  489. {
  490. uint crcData;
  491. uint tempData;
  492. uint temp;
  493. if(receCount > 4)                 //如果接收到数据
  494. {         
  495.   switch(receBuf[1])
  496.   {
  497. case 1:                                                                //读取寄存器(一个或多个)
  498.    {         
  499.       if(receCount >= 8)  //从询问数据包格式可知,receCount应该等于8        ,接收完成一组数据应该关闭接收中断
  500.         {            
  501.           if(receBuf[0]==LocalAddr)   //核对地址
  502.             {         
  503.               crcData = crc16(receBuf,6);                     //核对校验码
  504.               temp=receBuf[7];
  505.               temp=(temp<<8)+receBuf[6];
  506.               if(crcData == temp)
  507.               if(receBuf[1] == 1)
  508.                 {
  509.                 readCoils();                        //读取线圈输出状态(一个或多个)
  510.                 }
  511.                 receCount = 0;                                                                           
  512.              }       
  513.           
  514.         }      
  515.           break;
  516.       }
  517. case 2:                                                                //读取寄存器(一个或多个)
  518.    {         
  519.       if(receCount >= 8)  //从询问数据包格式可知,receCount应该等于8        ,接收完成一组数据应该关闭接收中断
  520.         {            
  521.           if(receBuf[0]==LocalAddr)   //核对地址
  522.             {         
  523.               crcData = crc16(receBuf,6);                     //核对校验码
  524.               temp=receBuf[7];
  525.               temp=(temp<<8)+receBuf[6];
  526.               if(crcData == temp)
  527.               if(receBuf[1] == 2)
  528.                 {
  529.                 readInPutCoils();                        //读取线圈输入状态(一个或多个)
  530.                 }
  531.                 receCount = 0;                                                                           
  532.              }       
  533.           
  534.         }      
  535.           break;
  536.       }   
  537.    case 3:                                                                //读取寄存器(一个或多个)
  538.    {         
  539.       if(receCount >= 8)  //从询问数据包格式可知,receCount应该等于8        ,接收完成一组数据应该关闭接收中断
  540.         {            
  541.           if(receBuf[0]==LocalAddr)   //核对地址
  542.             {         
  543.               crcData = crc16(receBuf,6);                     //核对校验码
  544.               temp=receBuf[7];
  545.               temp=(temp<<8)+receBuf[6];
  546.               if(crcData == temp)
  547.               if(receBuf[1] == 3)
  548.               {
  549.                 readRegisters();                        //读取保持寄存器(一个或多个)
  550.                }
  551.                 receCount = 0;                                                                           
  552.             }                  
  553.         }      
  554.         break;
  555.    }
  556. case 4:                                                                //读取寄存器(一个或多个)
  557.    {         
  558.       if(receCount >= 8)  //从询问数据包格式可知,receCount应该等于8        ,接收完成一组数据应该关闭接收中断
  559.       {            
  560.           if(receBuf[0]==LocalAddr)   //核对地址
  561.           {         
  562.             crcData = crc16(receBuf,6);                     //核对校验码
  563.             temp=receBuf[7];
  564.             temp=(temp<<8)+receBuf[6];
  565.             if(crcData == temp)
  566.             if(receBuf[1] == 4)
  567.               {
  568.               readInPutRegisters();                        //读取输入寄存器(一个或多个)
  569.               }
  570.                 receCount = 0;                                                                           
  571.           }       
  572.           
  573.       }      
  574.           break;
  575.     }
  576.    case 5:                                                                //读取寄存器(一个或多个)
  577.    {         
  578.       if(receCount >= 8)  //从询问数据包格式可知,receCount应该等于8        ,接收完成一组数据应该关闭接收中断
  579.       {            
  580.           if(receBuf[0]==LocalAddr)   //核对地址
  581.           {         
  582.             crcData = crc16(receBuf,6);                     //核对校验码
  583.             temp=receBuf[7];
  584.             temp=(temp<<8)+receBuf[6];
  585.             if(crcData == temp)
  586.             if(receBuf[1] == 5)
  587.               {
  588.               forceSingleCoil();                        //强置单个线圈 状态
  589.               }
  590.                 receCount = 0;                                                                           
  591.           }       
  592.           
  593.       }      
  594.           break;
  595.     }
  596. case 6: if(receCount >= 8)
  597.            {   
  598.              if(receBuf[0]==LocalAddr)
  599.                   {
  600.                     crcData = crc16(receBuf,6);
  601.                     temp=receBuf[7];
  602.                     temp=(temp<<8)+receBuf[6];
  603.                     if(crcData == temp)
  604.                     if(receBuf[1] == 6)
  605.                       {
  606.                           presetSingleRegister();      //预置单个保持寄存器
  607.                         //  SaveSetupDataToFlash();   //保存设置数据  
  608.                       }
  609.                     receCount = 0;                                                                                                                                         
  610.                  }         
  611.           }
  612.                  break;
  613. case 15://设置多个线圈
  614.       tempData = receBuf[6];
  615.       tempData += 9; //数据个数
  616.       if(receCount >= tempData)
  617.       {
  618.           if(receBuf[0]==LocalAddr )
  619.             {
  620.                 crcData = crc16(receBuf,tempData-2);
  621.               if(crcData == (receBuf[tempData-1]<<8)+ receBuf[tempData-2])//更改了??
  622.                 {
  623.                   forceMultipleCoils();  
  624.                  // SaveSetupDataToFlash();   //保存设置数据  
  625.                 }
  626.             }
  627.                   receCount = 0;
  628.         }
  629.       break;        
  630.   case 16:                                                //设置多个寄存器
  631.    {
  632.         tempData = (receBuf[4]<<8) + receBuf[5];                 //设置寄存器个数
  633.         tempData = tempData * 2;                                                 //数据个数=        寄存器*2
  634.         tempData += 9;       //从询问数据包格式可知,receCount应该等于9+byteCount
  635.         if(receCount >= tempData)
  636.           {         
  637.             if(receBuf[0]==LocalAddr )        //核对地址
  638.                 {         
  639.                   crcData = crc16(receBuf,tempData-2);
  640.                      temp=receBuf[tempData-1];
  641.                   temp=(temp<<8)+receBuf[tempData-2];
  642.                   if(crcData == temp)
  643.                     {  
  644.                     presetMultipleRegisters();  
  645.                     //SaveSetupDataToFlash();   //保存设置数据
  646.                     }
  647.                 }
  648.               receCount = 0;
  649.             }
  650.         break;
  651.       }   
  652.   default: break;  
  653.   }
  654. }
  655. }

  656. ……………………

  657. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码

所有资料51hei提供下载:
MODBUS-51工程版从机.rar (3.71 MB, 下载次数: 768)



分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏30 分享淘帖 顶1 踩
回复

使用道具 举报

沙发
ID:1 发表于 2018-10-1 23:10 | 只看该作者
补全原理图或者详细说明一下电路连接即可获得100+黑币
回复

使用道具 举报

板凳
ID:199427 发表于 2018-10-2 08:39 | 只看该作者
谢谢楼主提供的源码!请问楼主,该源码在硬件上测试过吗?
回复

使用道具 举报

地板
ID:237723 发表于 2018-10-2 08:50 | 只看该作者
挺不错 学习学习!
回复

使用道具 举报

5#
ID:25103 发表于 2018-10-4 19:38 | 只看该作者

谢谢楼主提供的源码!谢谢!!
回复

使用道具 举报

6#
ID:188720 发表于 2018-10-20 15:25 | 只看该作者
有没有51单片机做主机的例程?
回复

使用道具 举报

7#
ID:3802 发表于 2019-1-8 17:56 | 只看该作者
好资料,51黑有你更精彩!!!
回复

使用道具 举报

8#
ID:514327 发表于 2019-4-17 10:25 | 只看该作者
值得借鉴
回复

使用道具 举报

9#
ID:578008 发表于 2019-7-25 14:32 | 只看该作者
红烧鱼头 发表于 2018-10-20 15:25
有没有51单片机做主机的例程?

现在有了码?
回复

使用道具 举报

10#
ID:57896 发表于 2019-7-25 21:31 | 只看该作者
其实这个资料很不错的
回复

使用道具 举报

11#
ID:111310 发表于 2019-7-26 11:32 | 只看该作者
我想看看学习,不知道能不能下载下来
回复

使用道具 举报

12#
ID:531445 发表于 2019-7-31 17:01 | 只看该作者
这个资料很不错的
回复

使用道具 举报

13#
ID:593904 发表于 2019-8-22 06:12 来自手机 | 只看该作者
学习资料很好
回复

使用道具 举报

14#
ID:384870 发表于 2019-9-5 06:51 | 只看该作者
谢谢分享,我测试一下
回复

使用道具 举报

15#
ID:514317 发表于 2019-9-5 08:17 | 只看该作者
这个有点复杂    还弄不清楚
回复

使用道具 举报

16#
ID:149389 发表于 2019-9-7 09:05 来自手机 | 只看该作者
很好的参考资料
回复

使用道具 举报

17#
ID:608128 发表于 2019-9-7 11:23 | 只看该作者
很完整,很有用,值得参考
回复

使用道具 举报

18#
ID:428400 发表于 2019-9-28 19:46 | 只看该作者
这个资料好!谢谢
回复

使用道具 举报

19#
ID:500625 发表于 2019-11-15 11:11 | 只看该作者
感谢分享
回复

使用道具 举报

20#
ID:602896 发表于 2019-11-23 16:37 | 只看该作者
很好找了好久啊
回复

使用道具 举报

21#
ID:33452 发表于 2019-12-4 08:29 | 只看该作者
很好找了好久啊
回复

使用道具 举报

22#
ID:748018 发表于 2020-5-14 19:21 来自手机 | 只看该作者
谢谢楼主的分享
回复

使用道具 举报

23#
ID:611470 发表于 2020-5-14 19:40 来自手机 | 只看该作者
资料很好,感谢分享
回复

使用道具 举报

24#
ID:381027 发表于 2020-5-21 16:50 | 只看该作者
这个程序下载到单片机上直接通过485通信就可以和上位机的主站通信了吗?那主站要怎么设置啊。
回复

使用道具 举报

25#
ID:768413 发表于 2020-6-3 14:40 | 只看该作者
很不错的学习资料
回复

使用道具 举报

26#
ID:348695 发表于 2020-6-25 12:06 | 只看该作者
谢谢楼主提供的源码!
回复

使用道具 举报

27#
ID:564550 发表于 2020-11-13 20:33 | 只看该作者
正在搞焊接的通讯板,借楼主资源 多谢!~
回复

使用道具 举报

28#
ID:81560 发表于 2020-12-7 03:37 | 只看该作者
正需要这个资料,非常感谢!
回复

使用道具 举报

29#
ID:220936 发表于 2021-1-20 19:41 | 只看该作者
好资料,感谢楼主分享,不知在工程上能否使用
回复

使用道具 举报

30#
ID:898951 发表于 2021-3-31 15:13 | 只看该作者
不知道 能不能验证
回复

使用道具 举报

31#
ID:307784 发表于 2022-3-15 07:16 来自手机 | 只看该作者
好资料,可以测试下
回复

使用道具 举报

32#
ID:77589 发表于 2023-6-26 17:36 | 只看该作者
好资料,51黑有你更精彩!!!
回复

使用道具 举报

33#
ID:166646 发表于 2023-7-12 11:51 | 只看该作者
很好的资料,谢谢
回复

使用道具 举报

34#
ID:216265 发表于 2023-8-11 15:05 | 只看该作者
不错,谢谢楼主提供的从机代码
回复

使用道具 举报

35#
ID:143914 发表于 2023-9-6 21:31 来自手机 | 只看该作者
感谢大佬,刚接触modbus,受益匪浅
回复

使用道具 举报

36#
ID:933601 发表于 2023-11-9 20:26 | 只看该作者
感谢楼主无私开源
回复

使用道具 举报

37#
ID:636442 发表于 2024-1-3 15:25 | 只看该作者
感谢技术资料分享。很有参考用处。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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