当前使用的是STM32+ucos_ii编写的,能够移植到安卓以及VC .NET等方便移植使用,採用modebus poll測试过.

仅仅须要改动响应的通信接口就可以,方便多串口使用

//modebus_rtu.c

  1. /*************************************************************************************************************
  2. * 文件名称: MODEBUS_RTU.c
  3. * 功能: MODEBUS_RTU通信协议层
  4. * 作者: cp1300@139.com
  5. * 创建时间: 2014-03-24
  6. * 最后改动时间:2014-11-17
  7. * 具体: MODEBUS RTU通信协议层
  8. *************************************************************************************************************/
  9. #include "system.h"
  10. #include "usart.h"
  11. #include "delay.h"
  12. #include "MODEBUS_RTU.h"
  13.  
  14. //调试开关
  15. #define MODEBUS_RTU_DBUG 1
  16. #if MODEBUS_RTU_DBUG
  17. #include "system.h"
  18. #define modebus_debug(format,...) uart_printf(format,##__VA_ARGS__)
  19. #else
  20. #define modebus_debug(format,...) /\
  21. /
  22. #endif //MODEBUS_RTU_DBUG
  23.  
  24. /*************************************************************************************************************************
  25. * 函数 : bool MODEBUS_Init(MODEBUS_HANDLE *pHandle, u8 UartCh, u32 BaudRate, u8 *pRxBuff,u8 *pTxBuff, u32 RxBuffSize, u32 TimeOut)
  26. * 功能 : MODEBUS 初始化
  27. * 參数 : pHandle:当前初始化的modebus句柄,UartCh:使用的串口通道;BaudRate:使用的波特率;pRxBuff:接收缓冲区指针;
  28. RxBuffSize:接收缓冲区大小;pTxBuff:发送缓冲区指针;TimeOut:接收超时,单位ms
  29. * 返回 : FALSE:初始化失败;TRUE:初始化成功
  30. * 依赖 : 串口
  31. * 作者 : cp1300@139.com
  32. * 时间 : 2014-09-25
  33. * 最后改动时间 : 2014-11-10
  34. * 说明 : 收发缓冲区能够与发送缓冲区使用同一缓冲区
  35. 发送缓冲区必须大于最大数据包大小,否则会出现内存溢出
  36. *************************************************************************************************************************/
  37. bool MODEBUS_Init(MODEBUS_HANDLE *pHandle, u8 UartCh, u32 BaudRate, u8 *pRxBuff,u8 *pTxBuff, u32 RxBuffSize, u32 TimeOut)
  38. {
  39. if(pHandle == NULL) return FALSE;
  40. pHandle->TxPacketNum = 0; //发送数据包计数
  41. pHandle->RxPacketNum = 0; //接收数据包计数
  42. pHandle->ErrorNum = 0; //通信错误计数
  43. pHandle->ReturnTime = 0; //数据返回时间
  44. //设置串口
  45. if(MODEBUS_UartInit(UartCh, BaudRate) == FALSE) //初始化串口
  46. {
  47. pHandle->UartCh = 0xff; //通道无效
  48. pHandle->pRxBuff = pHandle->pTxBuff = NULL; //缓冲区无效
  49. pHandle->RxBuffSize = 0; //缓冲区大小为0
  50. }
  51. MODEBUS_SetRxBuff(UartCh, pRxBuff, RxBuffSize);
  52. MODEBUS_DisableRx(UartCh); //关闭串口接收
  53. pHandle->UartCh = UartCh; //通道
  54. pHandle->pRxBuff = pRxBuff;
  55. pHandle->pTxBuff = pTxBuff; //缓冲区
  56. pHandle->RxBuffSize = RxBuffSize; //缓冲区大小
  57. if(TimeOut == 0) TimeOut = 1;
  58. pHandle->TimeOut = TimeOut;
  59. pHandle->BaudRate = BaudRate;
  60.  
  61. return TRUE;
  62. }
  63.  
  64. #if(MODEBUS_RTU_HOST) //开启主机模式
  65. /*************************************************************************************************************************
  66. * 函数 : MRTU_ERROR MODEBUS_HOST_ReadReg(MODEBUS_HANDLE *pHandle, READ_REG_TYPE RegType, u8 SlaveAddr, u16 RegAddr, u16 *pRegData)
  67. * 功能 : 主机读取从机一个指定寄存器
  68. * 參数 : pHandle:modebus句柄;RegType:读取的寄存器类型;SlaveAddr:从机地址;RegAddr:需读取的寄存器地址;pRegData:寄存器的值
  69. * 返回 : MRTU_ERROR:通信状态
  70. * 依赖 : 底层通信驱动
  71. * 作者 : cp1300@139.com
  72. * 时间 : 2014-03-24
  73. * 最后改动时间 : 2014-11-16
  74. * 说明 : MOUEBUS RTU读取数据,读取一个寄存器
  75. 输入输出的数据都为小端模式
  76. *************************************************************************************************************************/
  77. MRTU_ERROR MODEBUS_HOST_ReadReg(MODEBUS_HANDLE *pHandle, READ_REG_TYPE RegType, u8 SlaveAddr, u16 RegAddr, u16 *pRegData)
  78. {
  79. MRTU_READ_FRAME *pFrame; //发送数据帧格式
  80. MRTU_RETURN_FRAME *pReFrame; //返回数据帧格式
  81. MRTU_UNU_FRAME *pUnuFrame; //返回的异常数据帧格式
  82. u16 crc16;
  83. u16 cnt1, cnt2=0; //接收数据计数器
  84. u16 TimeOut;
  85. u16 TimeDelay = 0; //用于计算数据接收延时
  86.  
  87. if(pHandle == NULL) return MRTU_HANDLE_ERROR; //句柄无效
  88. TimeOut = pHandle->TimeOut/10+1; //超时初值
  89. pFrame = (MRTU_READ_FRAME *)pHandle->pTxBuff;
  90. //数据结构填充
  91. pFrame->addr = SlaveAddr; //从机地址
  92. pFrame->fun = (u8)RegType; //功能码,读取
  93. pFrame->StartReg = SWAP16(RegAddr); //寄存器起始地址
  94. pFrame->RegNum = SWAP16(1); //须要读取的寄存器数量,1
  95. crc16 = usMBCRC16(pHandle->pTxBuff, 6); //计算CRC16
  96. pFrame->CRC16 = crc16; //crc16
  97.  
  98. #if MODEBUS_RTU_DBUG
  99. {
  100. u16 i;
  101.  
  102. modebus_debug("\r\n<- MODEBUS RTU TXD(%dB)(CRC:0x%04X):\r\n",8,crc16);
  103. for(i = 0;i < 8;i ++)
  104. {
  105. modebus_debug("0x%02X ",pHandle->pTxBuff[i]);
  106. }
  107. modebus_debug("\r\n");
  108. }
  109. #endif //MODEBUS_RTU_DBUG
  110.  
  111. MODEBUS_SendData(pHandle->UartCh, pHandle->pTxBuff, 6+2); //发送数据
  112. MODEBUS_ClearRxCnt(pHandle->UartCh); //清除接收缓冲区
  113. MODEBUS_GetDataOver(pHandle->UartCh); //清除溢出标志
  114. MODEBUS_EnableRx(pHandle->UartCh); //使能接收
  115. //等待数据返回
  116. do
  117. {
  118. cnt1 = cnt2;
  119. MODEBUS_Delay10MS(); //延时10ms
  120. if(MODEBUS_GetDataOver(pHandle->UartCh) == SET) //查看是否发生溢出
  121. {
  122. MODEBUS_DisableRx(pHandle->UartCh); //关闭接收
  123. MODEBUS_ClearRxCnt(pHandle->UartCh); //清除接收缓冲区
  124. modebus_debug("接收溢出!\r\n");
  125. return MRTU_OVER_ERROR; //返回溢出错误
  126. }
  127. cnt2 = MODEBUS_GetDataCnt(pHandle->UartCh); //获取接收数据计数器
  128. if(cnt1 == cnt2) //完成接收数据了,退出等待
  129. {
  130. TimeOut --;
  131. if((cnt1 > 0)&&(TimeOut!=0)) TimeOut=1; //数据接收完成,退出
  132. TimeDelay ++;
  133. }
  134. else
  135. {
  136. TimeOut = pHandle->TimeOut/10+1; //有数据,计数器复位
  137. }
  138. }while(TimeOut);
  139. TimeDelay -= 1;
  140. //等待完成
  141. MODEBUS_DisableRx(pHandle->UartCh); //关闭接收
  142. MODEBUS_ClearRxCnt(pHandle->UartCh); //清除接收缓冲区
  143. if(cnt1 == 0) //没有接收到数据
  144. {
  145. modebus_debug("接收超时(%dmS)!\r\n",TimeDelay*10);
  146. pHandle->ReturnTime = 0xffff; //接收数据超时
  147. return MRTU_TIME_OUT; //返回超时
  148. }
  149. pHandle->ReturnTime = TimeDelay*10; //数据返回时间
  150.  
  151. #if MODEBUS_RTU_DBUG
  152. {
  153. u16 i;
  154.  
  155. modebus_debug("\r\n-> MODEBUS RTU RXD(%dB)(ping:%dmS):\r\n",cnt1,TimeDelay*10);
  156. for(i = 0;i < cnt1;i ++)
  157. {
  158. modebus_debug("0x%02X ", pHandle->pRxBuff[i]);
  159. }
  160. modebus_debug("\r\n");
  161. }
  162. #endif //MODEBUS_RTU_DBUG
  163.  
  164. pReFrame = (MRTU_RETURN_FRAME *)pHandle->pRxBuff;
  165. //检查地址
  166. if(pReFrame->addr != SlaveAddr)
  167. {
  168. modebus_debug("地址错误,目标地址为:0x%02X,返回地址为:0x%02X\r\n",SlaveAddr, pReFrame->addr);
  169. return MRTU_ADDR_ERROR;
  170. }
  171. //对接受的数据进行CRC校验
  172. crc16 = usMBCRC16(pHandle->pRxBuff, cnt1-2);//计算CRC16
  173. if((pHandle->pRxBuff[cnt1-1] != (crc16 >> 8)) || (pHandle->pRxBuff[cnt1-2] != (crc16 & 0xff)))
  174. {
  175. modebus_debug("CRC校验错误,计算CRC为:0x%04X,返回CRC为:0x%04X\r\n",crc16,(u16)(pHandle->pRxBuff[cnt1-2]<<8)|pHandle->pRxBuff[cnt1-1]);
  176. return MRTU_CRC_ERROR; //返回CRC校验错误
  177. }
  178. //返回的功能码不一致
  179. if(pReFrame->fun != (u8)RegType)
  180. {
  181. pUnuFrame = (MRTU_UNU_FRAME *)pHandle->pRxBuff; //异常数据帧
  182. if(pUnuFrame->ErrorFun == ((u8)RegType|0x80)) //返回有异常
  183. {
  184. modebus_debug("返回异常,异常码%d\r\n", pUnuFrame->unu);
  185. switch(pUnuFrame->unu)
  186. {
  187. case 1: return MRTU_UNUS1_ERROR; //异常码1
  188. case 2: return MRTU_UNUS2_ERROR; //异常码2
  189. case 3: return MRTU_UNUS3_ERROR; //异常码3
  190. case 4: return MRTU_UNUS4_ERROR; //异常码4
  191. case 5: return MRTU_UNUS5_ERROR; //异常码5
  192. case 6: return MRTU_UNUS6_ERROR; //异常码6
  193. default: return MRTU_OTHER_ERROR;
  194. }
  195. }
  196. else
  197. {
  198. modebus_debug("返回错误,返回功能码为0x%02X\r\n", pReFrame->fun);
  199. return MRTU_FUNR_ERROR;
  200. }
  201. }
  202. //推断数据长度
  203. if(pReFrame->DataLen != 2)
  204. {
  205. modebus_debug("返回数据长度错误,读取%d个寄存器,共%dB,仅仅返回了%dB\r\n",1, 1*2, pReFrame->DataLen);
  206. return MRTU_LEN_ERROR; //返回数据长度错误
  207. }
  208. //获取返回的寄存器的值
  209. *pRegData = pReFrame->DataBuff[0];
  210. *pRegData <<= 8;
  211. *pRegData |= pReFrame->DataBuff[1];
  212.  
  213. return MRTU_OK; //返回成功
  214. }
  215.  
  216. /*************************************************************************************************************************
  217. * 函数 : MRTU_ERROR MODEBUS_HOST_ReadMultReg(MODEBUS_HANDLE *pHandle, READ_REG_TYPE RegType, u8 SlaveAddr, u16 RegAddr, u8 RegNum, u16 pRegData[])
  218. * 功能 : 主机读取从机指定多个连续寄存器
  219. * 參数 : pHandle:modebus句柄;RegType:读取的寄存器类型;SlaveAddr:从机地址;RegAddr:需读取的寄存器地址;RegNum:寄存器数量;pRegData:返回寄存器的值,至少为RegNum的2倍
  220. 返回的寄存器的值依照循序存放在pRegData中
  221. * 返回 : MRTU_ERROR:通信状态
  222. * 依赖 : 底层通信驱动
  223. * 作者 : cp1300@139.com
  224. * 时间 : 2014-03-24
  225. * 最后改动时间 : 2014-11-16
  226. * 说明 : MOUEBUS RTU读取数据,读取一个寄存器
  227. 输入输出的数据都为小端模式
  228. *************************************************************************************************************************/
  229. MRTU_ERROR MODEBUS_HOST_ReadMultReg(MODEBUS_HANDLE *pHandle, READ_REG_TYPE RegType, u8 SlaveAddr, u16 RegAddr, u8 RegNum, u16 pRegData[])
  230. {
  231. MRTU_READ_FRAME *pFrame; //发送数据帧格式
  232. MRTU_RETURN_FRAME *pReFrame; //返回数据帧格式
  233. MRTU_UNU_FRAME *pUnuFrame; //返回的异常数据帧格式
  234. u16 crc16;
  235. u16 cnt1, cnt2=0; //接收数据计数器
  236. u16 TimeOut;
  237. u16 TimeDelay = 0; //用于计算数据接收延时
  238. u8 i;
  239.  
  240. if(pHandle == NULL) return MRTU_HANDLE_ERROR; //句柄无效
  241. TimeOut = pHandle->TimeOut/10+1; //超时初值
  242. pFrame = (MRTU_READ_FRAME *)pHandle->pTxBuff;
  243. //数据结构填充
  244. pFrame->addr = SlaveAddr; //从机地址
  245. pFrame->fun = (u8)RegType; //功能码,读取
  246. pFrame->StartReg = SWAP16(RegAddr); //寄存器起始地址
  247. if((RegNum > 127) || (RegNum == 0)) return MRTU_REGN_ERROR; //寄存器数量错误
  248. pFrame->RegNum = SWAP16(RegNum); //须要读取的寄存器数量
  249. crc16 = usMBCRC16(pHandle->pTxBuff, 6); //计算CRC16
  250. pFrame->CRC16 = crc16; //crc16
  251.  
  252. #if MODEBUS_RTU_DBUG
  253. {
  254. u16 i;
  255.  
  256. modebus_debug("\r\n<- MODEBUS RTU TXD(%dB)(CRC:0x%04X):\r\n",8,crc16);
  257. for(i = 0;i < 8;i ++)
  258. {
  259. modebus_debug("0x%02X ",pHandle->pTxBuff[i]);
  260. }
  261. modebus_debug("\r\n");
  262. }
  263. #endif //MODEBUS_RTU_DBUG
  264.  
  265. MODEBUS_SendData(pHandle->UartCh, pHandle->pTxBuff, 6+2); //发送数据
  266. MODEBUS_ClearRxCnt(pHandle->UartCh); //清除接收缓冲区
  267. MODEBUS_GetDataOver(pHandle->UartCh); //清除溢出标志
  268. MODEBUS_EnableRx(pHandle->UartCh); //使能接收
  269. //等待数据返回
  270. do
  271. {
  272. cnt1 = cnt2;
  273. MODEBUS_Delay10MS(); //延时10ms
  274. if(MODEBUS_GetDataOver(pHandle->UartCh) == SET) //查看是否发生溢出
  275. {
  276. MODEBUS_DisableRx(pHandle->UartCh); //关闭接收
  277. MODEBUS_ClearRxCnt(pHandle->UartCh); //清除接收缓冲区
  278. modebus_debug("接收溢出!\r\n");
  279. return MRTU_OVER_ERROR; //返回溢出错误
  280. }
  281. cnt2 = MODEBUS_GetDataCnt(pHandle->UartCh); //获取接收数据计数器
  282. if(cnt1 == cnt2) //完成接收数据了,退出等待
  283. {
  284. TimeOut --;
  285. if((cnt1 > 0)&&(TimeOut!=0)) TimeOut=1; //数据接收完成,退出
  286. TimeDelay ++;
  287. }
  288. else
  289. {
  290. TimeOut = pHandle->TimeOut/10+1; //有数据,计数器复位
  291. }
  292. }while(TimeOut);
  293. TimeDelay -= 1;
  294. //等待完成
  295. MODEBUS_DisableRx(pHandle->UartCh); //关闭接收
  296. MODEBUS_ClearRxCnt(pHandle->UartCh); //清除接收缓冲区
  297. if(cnt1 == 0) //没有接收到数据
  298. {
  299. modebus_debug("接收超时(%dmS)!\r\n",TimeDelay*10);
  300. pHandle->ReturnTime = 0xffff; //接收数据超时
  301. return MRTU_TIME_OUT; //返回超时
  302. }
  303. pHandle->ReturnTime = TimeDelay*10; //数据返回时间
  304.  
  305. #if MODEBUS_RTU_DBUG
  306. {
  307. u16 i;
  308.  
  309. modebus_debug("\r\n-> MODEBUS RTU RXD(%dB)(ping:%dmS):\r\n",cnt1,TimeDelay*10);
  310. for(i = 0;i < cnt1;i ++)
  311. {
  312. modebus_debug("0x%02X ", pHandle->pRxBuff[i]);
  313. }
  314. modebus_debug("\r\n");
  315. }
  316. #endif //MODEBUS_RTU_DBUG
  317.  
  318. pReFrame = (MRTU_RETURN_FRAME *)pHandle->pRxBuff;
  319. //检查地址
  320. if(pReFrame->addr != SlaveAddr)
  321. {
  322. modebus_debug("地址错误,目标地址为:0x%02X,返回地址为:0x%02X\r\n",SlaveAddr, pReFrame->addr);
  323. return MRTU_ADDR_ERROR;
  324. }
  325. //对接受的数据进行CRC校验
  326. crc16 = usMBCRC16(pHandle->pRxBuff, cnt1-2);//计算CRC16
  327. if((pHandle->pRxBuff[cnt1-1] != (crc16 >> 8)) || (pHandle->pRxBuff[cnt1-2] != (crc16 & 0xff)))
  328. {
  329. modebus_debug("CRC校验错误,计算CRC为:0x%04X,返回CRC为:0x%04X\r\n",crc16,(u16)(pHandle->pRxBuff[cnt1-2]<<8)|pHandle->pRxBuff[cnt1-1]);
  330. return MRTU_CRC_ERROR; //返回CRC校验错误
  331. }
  332. //返回的功能码不一致
  333. if(pReFrame->fun != (u8)RegType)
  334. {
  335. pUnuFrame = (MRTU_UNU_FRAME *)pHandle->pRxBuff; //异常数据帧
  336. if(pUnuFrame->ErrorFun == ((u8)RegType|0x80)) //返回有异常
  337. {
  338. modebus_debug("返回异常,异常码%d\r\n", pUnuFrame->unu);
  339. switch(pUnuFrame->unu)
  340. {
  341. case 1: return MRTU_UNUS1_ERROR; //异常码1
  342. case 2: return MRTU_UNUS2_ERROR; //异常码2
  343. case 3: return MRTU_UNUS3_ERROR; //异常码3
  344. case 4: return MRTU_UNUS4_ERROR; //异常码4
  345. case 5: return MRTU_UNUS5_ERROR; //异常码5
  346. case 6: return MRTU_UNUS6_ERROR; //异常码6
  347. default: return MRTU_OTHER_ERROR;
  348. }
  349. }
  350. else
  351. {
  352. modebus_debug("返回错误,返回功能码为0x%02X\r\n", pReFrame->fun);
  353. return MRTU_FUNR_ERROR;
  354. }
  355. }
  356. //推断数据长度
  357. if(pReFrame->DataLen != (RegNum*2))
  358. {
  359. modebus_debug("返回数据长度错误,读取%d个寄存器,共%dB,仅仅返回了%dB\r\n",RegNum, RegNum*2, pReFrame->DataLen);
  360. return MRTU_LEN_ERROR; //返回数据长度错误
  361. }
  362. //获取返回的寄存器的值
  363. for(i = 0;i < RegNum;i ++)
  364. {
  365. pRegData[i] = pReFrame->DataBuff[i*2];
  366. pRegData[i] <<= 8;
  367. pRegData[i] |= pReFrame->DataBuff[i*2+1];
  368. }
  369.  
  370. return MRTU_OK; //返回成功
  371. }
  372.  
  373. /*************************************************************************************************************************
  374. * 函数 : MRTU_ERROR MODEBUS_HOST_WriteReg(MODEBUS_HANDLE *pHandle,u8 SlaveAddr, u16 RegAddr, u16 RegData)
  375. * 功能 : 主机写从机一个指定寄存器
  376. * 參数 : pHandle:modebus句柄;SlaveAddr:从机地址;RegAddr:写寄存器地址;RegData:寄存器的值
  377. * 返回 : MRTU_ERROR:通信状态
  378. * 依赖 : 底层通信驱动
  379. * 作者 : cp1300@139.com
  380. * 时间 : 2014-03-24
  381. * 最后改动时间 : 2014-11-16
  382. * 说明 : MOUEBUS RTU写从机一个保持寄存器
  383. 输入输出的数据都为小端模式
  384. 预置单个寄存器的发送与接收数据包格式全然一致,理论上发送与接收的数据都应该一致
  385. *************************************************************************************************************************/
  386. MRTU_ERROR MODEBUS_HOST_WriteReg(MODEBUS_HANDLE *pHandle,u8 SlaveAddr, u16 RegAddr, u16 RegData)
  387. {
  388. MRTU_WRITE_FRAME *pFrame, *pReFrame;//发送数据帧格式
  389. MRTU_UNU_FRAME *pUnuFrame; //返回的异常数据帧格式
  390. u16 crc16;
  391. u16 cnt1, cnt2=0; //接收数据计数器
  392. u16 TimeOut;
  393. u16 TimeDelay = 0; //用于计算数据接收延时
  394.  
  395. if(pHandle == NULL) return MRTU_HANDLE_ERROR; //句柄无效
  396. TimeOut = pHandle->TimeOut/10+1; //超时初值
  397. pFrame = (MRTU_WRITE_FRAME *)pHandle->pTxBuff;
  398. //数据结构填充
  399. pFrame->addr = SlaveAddr; //从机地址
  400. pFrame->fun = (u8)MRTU_FUN_WRITE; //功能码,预置单个寄存器
  401. pFrame->StartReg = SWAP16(RegAddr); //寄存器起始地址
  402. pFrame->RegData = SWAP16(RegData); //写入寄存器内容
  403. pFrame->crc16 = usMBCRC16(pHandle->pTxBuff, 6); //计算CRC16
  404.  
  405. #if MODEBUS_RTU_DBUG
  406. {
  407. u16 i;
  408.  
  409. modebus_debug("\r\n<- MODEBUS RTU TXD(%dB)(CRC:0x%04X):\r\n",8,crc16);
  410. for(i = 0;i < 8;i ++)
  411. {
  412. modebus_debug("0x%02X ",pHandle->pTxBuff[i]);
  413. }
  414. modebus_debug("\r\n");
  415. }
  416. #endif //MODEBUS_RTU_DBUG
  417.  
  418. MODEBUS_SendData(pHandle->UartCh, pHandle->pTxBuff, 6+2); //发送数据
  419. MODEBUS_ClearRxCnt(pHandle->UartCh); //清除接收缓冲区
  420. MODEBUS_GetDataOver(pHandle->UartCh); //清除溢出标志
  421. MODEBUS_EnableRx(pHandle->UartCh); //使能接收
  422. //等待数据返回
  423. do
  424. {
  425. cnt1 = cnt2;
  426. MODEBUS_Delay10MS(); //延时10ms
  427. if(MODEBUS_GetDataOver(pHandle->UartCh) == SET) //查看是否发生溢出
  428. {
  429. MODEBUS_DisableRx(pHandle->UartCh); //关闭接收
  430. MODEBUS_ClearRxCnt(pHandle->UartCh); //清除接收缓冲区
  431. modebus_debug("接收溢出!\r\n");
  432. return MRTU_OVER_ERROR; //返回溢出错误
  433. }
  434. cnt2 = MODEBUS_GetDataCnt(pHandle->UartCh); //获取接收数据计数器
  435. if(cnt1 == cnt2) //完成接收数据了,退出等待
  436. {
  437. TimeOut --;
  438. if((cnt1 > 0)&&(TimeOut!=0)) TimeOut=1; //数据接收完成,退出
  439. TimeDelay ++;
  440. }
  441. else
  442. {
  443. TimeOut = pHandle->TimeOut/10+1; //有数据,计数器复位
  444. }
  445. }while(TimeOut);
  446. TimeDelay -= 1;
  447. //等待完成
  448. MODEBUS_DisableRx(pHandle->UartCh); //关闭接收
  449. MODEBUS_ClearRxCnt(pHandle->UartCh); //清除接收缓冲区
  450. if(cnt1 == 0) //没有接收到数据
  451. {
  452. modebus_debug("接收超时(%dmS)!\r\n",TimeDelay*10);
  453. pHandle->ReturnTime = 0xffff; //接收数据超时
  454. return MRTU_TIME_OUT; //返回超时
  455. }
  456. pHandle->ReturnTime = TimeDelay*10; //数据返回时间
  457.  
  458. #if MODEBUS_RTU_DBUG
  459. {
  460. u16 i;
  461.  
  462. modebus_debug("\r\n-> MODEBUS RTU RXD(%dB)(ping:%dmS):\r\n",cnt1,TimeDelay*10);
  463. for(i = 0;i < cnt1;i ++)
  464. {
  465. modebus_debug("0x%02X ", pHandle->pRxBuff[i]);
  466. }
  467. modebus_debug("\r\n");
  468. }
  469. #endif //MODEBUS_RTU_DBUG
  470.  
  471. pReFrame = (MRTU_WRITE_FRAME *)pHandle->pRxBuff;
  472. //检查地址
  473. if(pReFrame->addr != SlaveAddr)
  474. {
  475. modebus_debug("地址错误,目标地址为:0x%02X,返回地址为:0x%02X\r\n",SlaveAddr, pReFrame->addr);
  476. return MRTU_ADDR_ERROR;
  477. }
  478. //对接受的数据进行CRC校验
  479. crc16 = usMBCRC16(pHandle->pRxBuff, cnt1-2);//计算CRC16
  480. if((pHandle->pRxBuff[cnt1-1] != (crc16 >> 8)) || (pHandle->pRxBuff[cnt1-2] != (crc16 & 0xff)))
  481. {
  482. modebus_debug("CRC校验错误,计算CRC为:0x%04X,返回CRC为:0x%04X\r\n",crc16,(u16)(pHandle->pRxBuff[cnt1-2]<<8)|pHandle->pRxBuff[cnt1-1]);
  483. return MRTU_CRC_ERROR; //返回CRC校验错误
  484. }
  485. //返回的功能码不一致
  486. if(pReFrame->fun != (u8)MRTU_FUN_WRITE)
  487. {
  488. pUnuFrame = (MRTU_UNU_FRAME *)pHandle->pRxBuff; //异常数据帧
  489. if(pUnuFrame->ErrorFun == ((u8)MRTU_FUN_WRITE|0x80))//返回有异常
  490. {
  491. modebus_debug("返回异常,异常码%d\r\n", pUnuFrame->unu);
  492. switch(pUnuFrame->unu)
  493. {
  494. case 1: return MRTU_UNUS1_ERROR; //异常码1
  495. case 2: return MRTU_UNUS2_ERROR; //异常码2
  496. case 3: return MRTU_UNUS3_ERROR; //异常码3
  497. case 4: return MRTU_UNUS4_ERROR; //异常码4
  498. case 5: return MRTU_UNUS5_ERROR; //异常码5
  499. case 6: return MRTU_UNUS6_ERROR; //异常码6
  500. default: return MRTU_OTHER_ERROR;
  501. }
  502. }
  503. else
  504. {
  505. modebus_debug("返回错误,返回功能码为0x%02X\r\n", pReFrame->fun);
  506. return MRTU_FUNR_ERROR;
  507. }
  508. }
  509. //推断数据是否写入
  510. if(SWAP16(pReFrame->StartReg) != RegAddr) //返回的寄存器地址不一致
  511. {
  512. modebus_debug("返回寄存器地址错误,写入寄存器%d,返回寄存器%d\r\n",RegAddr, pReFrame->StartReg);
  513. return MRTU_REG_ERROR; //返回寄存器错误
  514. }
  515. if(SWAP16(pReFrame->RegData) != RegData)
  516. {
  517. modebus_debug("数据写入错误,写入值:0x%04X,返回了:0x%04X\r\n",RegData, pReFrame->RegData);
  518. return MRTU_WRITE_ERROR; //写入数据错误
  519. }
  520.  
  521. return MRTU_OK; //返回成功
  522. }
  523.  
  524. /*************************************************************************************************************************
  525. * 函数 : MRTU_ERROR MODEBUS_HOST_WriteMultReg(MODEBUS_HANDLE *pHandle,u8 SlaveAddr, u16 RegAddr, u8 RegNum, u16 pRegData[])
  526. * 功能 : 主机写从机多个指定寄存器
  527. * 參数 : pHandle:modebus句柄;SlaveAddr:从机地址;RegAddr:写寄存器地址;RegNum:寄存器数量, pRegData:须要写入的寄存器的值
  528. 写入寄存器的值依照循序排列,使用小端格式,大小必须为RegNum*2
  529. * 返回 : MRTU_ERROR:通信状态
  530. * 依赖 : 底层通信驱动
  531. * 作者 : cp1300@139.com
  532. * 时间 : 2014-03-24
  533. * 最后改动时间 : 2014-11-16
  534. * 说明 : MOUEBUS RTU写从机一个保持寄存器
  535. 输入输出的数据都为小端模式
  536. 返回数据寄存器位置与寄存器数量
  537. *************************************************************************************************************************/
  538. MRTU_ERROR MODEBUS_HOST_WriteMultReg(MODEBUS_HANDLE *pHandle,u8 SlaveAddr, u16 RegAddr, u8 RegNum, u16 pRegData[])
  539. {
  540. MRTU_WRITE_MULT_FRAME *pFrame; //发送数据帧格式
  541. MRTU_WRIT_EMULT_RFRAME *pReFrame; //返回数据帧格式
  542. MRTU_UNU_FRAME *pUnuFrame; //返回的异常数据帧格式
  543. u16 crc16;
  544. u16 cnt1, cnt2=0; //接收数据计数器
  545. u16 TimeOut;
  546. u16 TimeDelay = 0; //用于计算数据接收延时
  547. u8 i;
  548.  
  549. if(pHandle == NULL) return MRTU_HANDLE_ERROR; //句柄无效
  550. TimeOut = pHandle->TimeOut/10+1; //超时初值
  551. pFrame = (MRTU_WRITE_MULT_FRAME *)pHandle->pTxBuff;
  552. //数据结构填充
  553. pFrame->addr = SlaveAddr; //从机地址
  554. pFrame->fun = (u8)MRTU_FUN_MWRITE; //功能码,预置多个寄存器
  555. pFrame->StartReg = SWAP16(RegAddr); //寄存器起始地址
  556. if((RegNum > 127) || (RegNum == 0)) return MRTU_REGN_ERROR; //寄存器数量错误
  557. pFrame->RegNum = SWAP16(RegNum); //写入寄存器数量
  558. pFrame->DataLen = 2*RegNum; //数据长度
  559. //循环写入数据
  560. for(i = 0;i < RegNum;i ++)
  561. {
  562. pFrame->DataBuff[2*i] = pRegData[i]>>8; //高位
  563. pFrame->DataBuff[2*i+1] = pRegData[i]&0xff; //低位
  564. }
  565. crc16 = usMBCRC16(pHandle->pTxBuff, 7+pFrame->DataLen); //计算CRC16,高低位对调过
  566. pFrame->DataBuff[pFrame->DataLen] = crc16&0xff; //高位
  567. pFrame->DataBuff[pFrame->DataLen+1]=crc16>>8; //低位
  568.  
  569. #if MODEBUS_RTU_DBUG
  570. {
  571. u16 i;
  572.  
  573. modebus_debug("\r\n<- MODEBUS RTU TXD(%dB)(CRC:0x%04X):\r\n",7+pFrame->DataLen+2,crc16);
  574. for(i = 0;i < 7+pFrame->DataLen+2;i ++)
  575. {
  576. modebus_debug("0x%02X ",pHandle->pTxBuff[i]);
  577. }
  578. modebus_debug("\r\n");
  579. }
  580. #endif //MODEBUS_RTU_DBUG
  581.  
  582. MODEBUS_SendData(pHandle->UartCh, pHandle->pTxBuff, 7+pFrame->DataLen+2); //发送数据
  583. MODEBUS_ClearRxCnt(pHandle->UartCh); //清除接收缓冲区
  584. MODEBUS_GetDataOver(pHandle->UartCh); //清除溢出标志
  585. MODEBUS_EnableRx(pHandle->UartCh); //使能接收
  586. //等待数据返回
  587. do
  588. {
  589. cnt1 = cnt2;
  590. MODEBUS_Delay10MS(); //延时10ms
  591. if(MODEBUS_GetDataOver(pHandle->UartCh) == SET) //查看是否发生溢出
  592. {
  593. MODEBUS_DisableRx(pHandle->UartCh); //关闭接收
  594. MODEBUS_ClearRxCnt(pHandle->UartCh); //清除接收缓冲区
  595. modebus_debug("接收溢出!\r\n");
  596. return MRTU_OVER_ERROR; //返回溢出错误
  597. }
  598. cnt2 = MODEBUS_GetDataCnt(pHandle->UartCh); //获取接收数据计数器
  599. if(cnt1 == cnt2) //完成接收数据了,退出等待
  600. {
  601. TimeOut --;
  602. if((cnt1 > 0)&&(TimeOut!=0)) TimeOut=1; //数据接收完成,退出
  603. TimeDelay ++;
  604. }
  605. else
  606. {
  607. TimeOut = pHandle->TimeOut/10+1; //有数据,计数器复位
  608. }
  609. }while(TimeOut);
  610. TimeDelay -= 1;
  611. //等待完成
  612. MODEBUS_DisableRx(pHandle->UartCh); //关闭接收
  613. MODEBUS_ClearRxCnt(pHandle->UartCh); //清除接收缓冲区
  614. if(cnt1 == 0) //没有接收到数据
  615. {
  616. modebus_debug("接收超时(%dmS)!\r\n",TimeDelay*10);
  617. pHandle->ReturnTime = 0xffff; //接收数据超时
  618. return MRTU_TIME_OUT; //返回超时
  619. }
  620. pHandle->ReturnTime = TimeDelay*10; //数据返回时间
  621.  
  622. #if MODEBUS_RTU_DBUG
  623. {
  624. u16 i;
  625.  
  626. modebus_debug("\r\n-> MODEBUS RTU RXD(%dB)(ping:%dmS):\r\n",cnt1,TimeDelay*10);
  627. for(i = 0;i < cnt1;i ++)
  628. {
  629. modebus_debug("0x%02X ", pHandle->pRxBuff[i]);
  630. }
  631. modebus_debug("\r\n");
  632. }
  633. #endif //MODEBUS_RTU_DBUG
  634.  
  635. pReFrame = (MRTU_WRIT_EMULT_RFRAME *)pHandle->pRxBuff;
  636. //检查地址
  637. if(pReFrame->addr != SlaveAddr)
  638. {
  639. modebus_debug("地址错误,目标地址为:0x%02X,返回地址为:0x%02X\r\n",SlaveAddr, pReFrame->addr);
  640. return MRTU_ADDR_ERROR;
  641. }
  642. //对接受的数据进行CRC校验
  643. crc16 = usMBCRC16(pHandle->pRxBuff, cnt1-2);//计算CRC16
  644. if((pHandle->pRxBuff[cnt1-1] != (crc16 >> 8)) || (pHandle->pRxBuff[cnt1-2] != (crc16 & 0xff)))
  645. {
  646. modebus_debug("CRC校验错误,计算CRC为:0x%04X,返回CRC为:0x%04X\r\n",crc16,(u16)(pHandle->pRxBuff[cnt1-2]<<8)|pHandle->pRxBuff[cnt1-1]);
  647. return MRTU_CRC_ERROR; //返回CRC校验错误
  648. }
  649. //返回的功能码不一致
  650. if(pReFrame->fun != (u8)MRTU_FUN_MWRITE)
  651. {
  652. pUnuFrame = (MRTU_UNU_FRAME *)pHandle->pRxBuff; //异常数据帧
  653. if(pUnuFrame->ErrorFun == ((u8)MRTU_FUN_MWRITE|0x80))//返回有异常
  654. {
  655. modebus_debug("返回异常,异常码%d\r\n", pUnuFrame->unu);
  656. switch(pUnuFrame->unu)
  657. {
  658. case 1: return MRTU_UNUS1_ERROR; //异常码1
  659. case 2: return MRTU_UNUS2_ERROR; //异常码2
  660. case 3: return MRTU_UNUS3_ERROR; //异常码3
  661. case 4: return MRTU_UNUS4_ERROR; //异常码4
  662. case 5: return MRTU_UNUS5_ERROR; //异常码5
  663. case 6: return MRTU_UNUS6_ERROR; //异常码6
  664. default: return MRTU_OTHER_ERROR;
  665. }
  666. }
  667. else
  668. {
  669. modebus_debug("返回错误,返回功能码为0x%02X\r\n", pReFrame->fun);
  670. return MRTU_FUNR_ERROR;
  671. }
  672. }
  673. //推断数据是否写入
  674. if(SWAP16(pReFrame->StartReg) != RegAddr) //返回的寄存器地址不一致
  675. {
  676. modebus_debug("返回寄存器地址错误,写入寄存器%d,返回寄存器%d\r\n",RegAddr, pReFrame->StartReg);
  677. return MRTU_REG_ERROR; //返回寄存器错误
  678. }
  679. if(SWAP16(pReFrame->RegNum) != RegNum)
  680. {
  681. modebus_debug("写入寄存器数量错误,写入%d个寄存器,返回%d个寄存器\r\n",RegNum, pReFrame->RegNum);
  682. return MRTU_WRITE_ERROR; //写入数据错误
  683. }
  684.  
  685. return MRTU_OK; //返回成功
  686. }
  687. #endif //MODEBUS_RTU_HOST
  688.  
  689. #if(MODEBUS_RTU_SLAVE) //开启从机模式
  690. /*************************************************************************************************************************
  691. * 函数 : bool MODEBUS_SLAVE_RetrunUnu(MODEBUS_HANDLE *pHandle,u8 SlaveAddr, u8 Fun, MRTU_UNUS Unus)
  692. * 功能 : 从机返回异常编码
  693. * 參数 : pHandle:modebus句柄;SlaveAddr:从机地址;Fun:来自主机的功能码;Unus:异常码,见MRTU_UNUS
  694. * 返回 : TRUE:发送成功;FALSE:发送失败
  695. * 依赖 : 底层通信驱动
  696. * 作者 : cp1300@139.com
  697. * 时间 : 2014-03-24
  698. * 最后改动时间 : 2014-11-17
  699. * 说明 : 从机返回异常码给主机,异常码见:MRTU_UNUS
  700. MRTU_UNUS1 异常码1,无效的操作码
  701. MRTU_UNUS2 异常码2,无效的数据地址
  702. MRTU_UNUS3 异常码3,无效的数据值
  703. MRTU_UNUS4 异常码4,无效操作
  704. MRTU_UNUS5 异常码5
  705. MRTU_UNUS6 异常码6
  706. *************************************************************************************************************************/
  707. bool MODEBUS_SLAVE_RetrunUnu(MODEBUS_HANDLE *pHandle,u8 SlaveAddr, u8 Fun, MRTU_UNUS Unus)
  708. {
  709. MRTU_UNU_FRAME *pFrame; //返回异常数据包
  710. u16 crc16;
  711.  
  712. if(pHandle == NULL) return FALSE; //句柄无效
  713. //数据结构填充
  714. pFrame = (MRTU_UNU_FRAME *)pHandle->pTxBuff;
  715. pFrame->addr = SlaveAddr; //从机地址
  716. pFrame->ErrorFun = (u8)Fun|0x80; //功能码+0x80,出现异常
  717. pFrame->unu = (u8)Unus; //异常编码
  718. crc16 = usMBCRC16(pHandle->pTxBuff, 3); //计算CRC16,高低位对调过
  719. pFrame->crc16H = crc16 & 0xff;
  720. pFrame->crc16L = crc16>>8;
  721. #if MODEBUS_RTU_DBUG
  722. {
  723. u16 i;
  724.  
  725. modebus_debug("\r\n<- MODEBUS RTU TXD(%dB)(CRC:0x%04X):\r\n",5, crc16);
  726. for(i = 0;i < 5;i ++)
  727. {
  728. modebus_debug("0x%02X ",pHandle->pTxBuff[i]);
  729. }
  730. modebus_debug("\r\n");
  731. }
  732. #endif //MODEBUS_RTU_DBUG
  733.  
  734. MODEBUS_SendData(pHandle->UartCh, pHandle->pTxBuff, 5); //发送数据
  735.  
  736. return TRUE;
  737. }
  738.  
  739. /*************************************************************************************************************************
  740. * 函数 : MRTU_ERROR MODEBUS_SLAVE_FramesUnpack(MODEBUS_HANDLE *pHandle,u8 SlaveAddr, u32 DataLen, u8 *pFun)
  741. * 功能 : 从机模式接收数据拆包
  742. * 參数 : pHandle:modebus句柄;SlaveAddr:从机地址;DataLen:接收数据长度;pFun:来自主机的功能码
  743. * 返回 : MRTU_ERROR:状态,仅仅有MRTU_OK:才是有效数据包
  744. * 依赖 : 底层通信驱动
  745. * 作者 : cp1300@139.com
  746. * 时间 : 2014-03-24
  747. * 最后改动时间 : 2014-11-17
  748. * 说明 : 须要等数据接收完成后拆包
  749. *************************************************************************************************************************/
  750. MRTU_ERROR MODEBUS_SLAVE_FramesUnpack(MODEBUS_HANDLE *pHandle,u8 SlaveAddr, u32 DataLen, u8 *pFun)
  751. {
  752. u16 crc16;
  753. MRTU_READ_FRAME *pReadFrame; //来自主机的读取数据帧格式
  754. MRTU_WRITE_MULT_FRAME *pWriteMultFrame; //来自主机的写多个保持寄存器
  755.  
  756. *pFun = 0xff; //功能码无效
  757. if(pHandle->pRxBuff[0] != SlaveAddr)
  758. {
  759. modebus_debug("地址不符,丢弃;目标地址:0x%02X;本机地址:0x%02X;\r\n", pHandle->pRxBuff[0], SlaveAddr);
  760. return MRTU_ADDR_ERROR;
  761. }
  762. //对接受的数据进行CRC校验
  763. crc16 = usMBCRC16(pHandle->pRxBuff, DataLen-2); //计算CRC16
  764.  
  765. #if MODEBUS_RTU_DBUG
  766. {
  767. u16 i;
  768.  
  769. modebus_debug("\r\n-> MODEBUS RTU RXD(%dB)(CRC:0x%04X):\r\n",DataLen,crc16);
  770. for(i = 0;i < DataLen;i ++)
  771. {
  772. modebus_debug("0x%02X ",pHandle->pRxBuff[i]);
  773. }
  774. modebus_debug("\r\n");
  775. }
  776. #endif //MODEBUS_RTU_DBUG
  777.  
  778. if((pHandle->pRxBuff[DataLen-1] == (crc16 >> 8)) && (pHandle->pRxBuff[DataLen-2] == (crc16 & 0xff)))
  779. {
  780. //推断功能码
  781. switch(pHandle->pRxBuff[1])
  782. {
  783. case MRTU_FUN_READ_HOLD : //0x03读保持寄存器,可读写寄存器为保持寄存器
  784. case MRTU_FUN_READ_INPUT : //0x04读输入寄存器,为仅仅读寄存器
  785. {
  786. pReadFrame = (MRTU_READ_FRAME *)pHandle->pRxBuff;
  787. if((SWAP16(pReadFrame->RegNum) > 127) || (SWAP16(pReadFrame->RegNum) == 0))
  788. {
  789. modebus_debug("读取寄存器数量错误,读取寄存器数量为:%d\r\n", SWAP16(pReadFrame->RegNum));
  790. MODEBUS_SLAVE_RetrunUnu(pHandle, pHandle->pRxBuff[0], pHandle->pRxBuff[1], MRTU_UNUS2); //返回异常2
  791. return MRTU_REGN_ERROR; //寄存器数量错误
  792. }
  793. }break;
  794. case MRTU_FUN_WRITE :break; //0x06写单个保持寄存器
  795. case MRTU_FUN_MWRITE : //0x10写多个保持寄存器
  796. {
  797. pWriteMultFrame = (MRTU_WRITE_MULT_FRAME *)pHandle->pRxBuff;
  798. if((SWAP16(pWriteMultFrame->RegNum) > 127) || (SWAP16(pWriteMultFrame->RegNum) == 0))
  799. {
  800. modebus_debug("写寄存器数量错误,读取寄存器数量为:%d\r\n", SWAP16(pWriteMultFrame->RegNum));
  801. MODEBUS_SLAVE_RetrunUnu(pHandle, pHandle->pRxBuff[0], pHandle->pRxBuff[1], MRTU_UNUS2); //返回异常2
  802. return MRTU_REGN_ERROR; //寄存器数量错误
  803. }
  804. else if(pWriteMultFrame->DataLen != (2*SWAP16(pWriteMultFrame->RegNum)))
  805. {
  806. modebus_debug("写寄存器数据长度错误,须要写入%d个寄存器,长度为:%dB,收到数据长度为:%dB\r\n", pWriteMultFrame->RegNum, 2*pWriteMultFrame->RegNum, pWriteMultFrame->DataLen);
  807. MODEBUS_SLAVE_RetrunUnu(pHandle, pHandle->pRxBuff[0], pHandle->pRxBuff[1], MRTU_UNUS3); //返回异常3
  808. return MRTU_REGN_ERROR; //寄存器数量错误
  809. }
  810. }break;
  811. default: //不支持的功能码,返回异常1
  812. {
  813. modebus_debug("不支持的操作码:0x%02X\r\n", pHandle->pRxBuff[1]);
  814. MODEBUS_SLAVE_RetrunUnu(pHandle, pHandle->pRxBuff[0], pHandle->pRxBuff[1], MRTU_UNUS1); //返回异常1
  815. return MRTU_FUNR_ERROR;
  816. }
  817. }
  818.  
  819. *pFun = pHandle->pRxBuff[1]; //返回功能码
  820. return MRTU_OK; //返回成功
  821. }
  822. else
  823. {
  824. modebus_debug("CRC校验错误,计算CRC为:0x%04X,返回CRC为:0x%04X\r\n",crc16,(u16)(pHandle->pRxBuff[DataLen-2]<<8)|pHandle->pRxBuff[DataLen-1]);
  825. return MRTU_CRC_ERROR; //返回CRC校验错误
  826. }
  827. }
  828.  
  829. /*************************************************************************************************************************
  830. * 函数 : MRTU_ERROR MODEBUS_SLAVE_ReturnReadReg(MODEBUS_HANDLE *pHandle, u8 Fun, u8 SlaveAddr, u16 RegAddr, u8 RegNum, u16 pRegData[])
  831. * 功能 : 从机返回主机读取的寄存器
  832. * 參数 : pHandle:modebus句柄;Fun:读取的功能码;SlaveAddr:从机地址;RegAddr:需读取的寄存器地址;RegNum:寄存器数量;pRegData:返回寄存器的值,至少为RegNum的2倍
  833. 返回的寄存器的值依照循序存放在pRegData中
  834. * 返回 : MRTU_ERROR:通信状态
  835. * 依赖 : 底层通信驱动
  836. * 作者 : cp1300@139.com
  837. * 时间 : 2014-03-24
  838. * 最后改动时间 : 2014-11-16
  839. * 说明 : MOUEBUS RTU主机读取从机的指定寄存器,能够为保持寄存器,也能够为输入寄存器,能够一次读取多个
  840. 输入输出的数据都为小端模式
  841. 注意:假设直接使用数据帧的寄存器数量以及地址,必须高地位交换
  842. *************************************************************************************************************************/
  843. MRTU_ERROR MODEBUS_SLAVE_ReturnReadReg(MODEBUS_HANDLE *pHandle, u8 Fun, u8 SlaveAddr, u16 RegAddr, u8 RegNum, u16 pRegData[])
  844. {
  845. MRTU_RETURN_FRAME *pFrame; //返回数据帧格式
  846. u16 crc16;
  847. u8 i;
  848.  
  849. if(pHandle == NULL) return MRTU_HANDLE_ERROR; //句柄无效
  850. if((Fun != MRTU_FUN_READ_INPUT) && (Fun != MRTU_FUN_READ_HOLD)) return MRTU_FUNR_ERROR; //功能码错误
  851. if((RegNum > 127) || (RegNum == 0)) return MRTU_REGN_ERROR; //寄存器数量错误
  852. pFrame = (MRTU_RETURN_FRAME *)pHandle->pTxBuff;
  853. //数据结构填充
  854. pFrame->addr = SlaveAddr; //从机地址
  855. pFrame->fun = Fun; //功能码,读取
  856. pFrame->DataLen = 2*RegNum; //数据长度
  857. //循环写入返回的数据
  858. for(i = 0;i < RegNum;i ++)
  859. {
  860. pFrame->DataBuff[2*i] = pRegData[i]>>8; //数据高位
  861. pFrame->DataBuff[2*i+1] = pRegData[i]&0xff; //数据低位
  862. }
  863. crc16 = usMBCRC16(pHandle->pTxBuff, 3+pFrame->DataLen);//计算CRC16
  864. pFrame->DataBuff[pFrame->DataLen] = crc16&0xff; //数据发送交换过
  865. pFrame->DataBuff[pFrame->DataLen+1] = crc16>>8; //数据发送交换过
  866.  
  867. #if MODEBUS_RTU_DBUG
  868. {
  869. u16 i;
  870.  
  871. modebus_debug("\r\n<- MODEBUS RTU TXD(%dB)(CRC:0x%04X):\r\n",3+pFrame->DataLen+2,crc16);
  872. for(i = 0;i < 3+pFrame->DataLen+2;i ++)
  873. {
  874. modebus_debug("0x%02X ",pHandle->pTxBuff[i]);
  875. }
  876. modebus_debug("\r\n");
  877. }
  878. #endif //MODEBUS_RTU_DBUG
  879.  
  880. MODEBUS_SendData(pHandle->UartCh, pHandle->pTxBuff, 3+pFrame->DataLen+2); //发送数据
  881.  
  882. return MRTU_OK; //返回成功
  883. }
  884.  
  885. /*************************************************************************************************************************
  886. * 函数 : MRTU_ERROR MODEBUS_SLAVE_ReturnWriteHoldReg(MODEBUS_HANDLE *pHandle,u8 SlaveAddr, u16 RegAddr, u16 RegData)
  887. * 功能 : 从机返回主机预置单个保持寄存器
  888. * 參数 : pHandle:modebus句柄;Fun:读取的功能码;SlaveAddr:从机地址;RegAddr:需读取的寄存器地址;RegData:返回寄存器的值
  889. * 返回 : MRTU_ERROR:通信状态
  890. * 依赖 : 底层通信驱动
  891. * 作者 : cp1300@139.com
  892. * 时间 : 2014-03-24
  893. * 最后改动时间 : 2014-11-16
  894. * 说明 : MOUEBUS RTU主机写单个寄存器成功后返回
  895. 输入输出的数据都为小端模式
  896. 注意:假设直接使用数据帧的寄存器数量以及地址,必须高地位交换
  897. *************************************************************************************************************************/
  898. MRTU_ERROR MODEBUS_SLAVE_ReturnWriteHoldReg(MODEBUS_HANDLE *pHandle,u8 SlaveAddr, u16 RegAddr, u16 RegData)
  899. {
  900. MRTU_WRITE_FRAME *pFrame; //返回数据帧格式
  901. u16 crc16;
  902.  
  903. if(pHandle == NULL) return MRTU_HANDLE_ERROR; //句柄无效
  904. pFrame = (MRTU_WRITE_FRAME *)pHandle->pTxBuff;
  905. //数据结构填充
  906. pFrame->addr = SlaveAddr; //从机地址
  907. pFrame->fun = MRTU_FUN_WRITE; //功能码,预置单个寄存器
  908. pFrame->StartReg = SWAP16(RegAddr); //寄存器地址
  909. pFrame->RegData = SWAP16(RegData); //寄存器的值
  910. pFrame->crc16 = usMBCRC16(pHandle->pTxBuff, 6);//计算CRC16
  911.  
  912. #if MODEBUS_RTU_DBUG
  913. {
  914. u16 i;
  915.  
  916. modebus_debug("\r\n<- MODEBUS RTU TXD(%dB)(CRC:0x%04X):\r\n",8,crc16);
  917. for(i = 0;i < 8;i ++)
  918. {
  919. modebus_debug("0x%02X ",pHandle->pTxBuff[i]);
  920. }
  921. modebus_debug("\r\n");
  922. }
  923. #endif //MODEBUS_RTU_DBUG
  924.  
  925. MODEBUS_SendData(pHandle->UartCh, pHandle->pTxBuff, 8); //发送数据
  926.  
  927. return MRTU_OK; //返回成功
  928. }
  929.  
  930. /*************************************************************************************************************************
  931. * 函数 : MRTU_ERROR MODEBUS_SLAVE_ReturnWriteMultHoldReg(MODEBUS_HANDLE *pHandle, u8 SlaveAddr, u16 RegAddr, u8 RegNum)
  932. * 功能 : 从机返回主机预置多个保持寄存器
  933. * 參数 : pHandle:modebus句柄;SlaveAddr:从机地址;RegAddr:需读取的寄存器地址;RegNum:须要读取的寄存器数量
  934. * 返回 : MRTU_ERROR:通信状态
  935. * 依赖 : 底层通信驱动
  936. * 作者 : cp1300@139.com
  937. * 时间 : 2014-03-24
  938. * 最后改动时间 : 2014-11-16
  939. * 说明 : MOUEBUS RTU主机写单个寄存器成功后返回
  940. 输入输出的数据都为小端模式
  941. 注意:假设直接使用数据帧的寄存器数量以及地址,必须高地位交换
  942. *************************************************************************************************************************/
  943. MRTU_ERROR MODEBUS_SLAVE_ReturnWriteMultHoldReg(MODEBUS_HANDLE *pHandle, u8 SlaveAddr, u16 RegAddr, u8 RegNum)
  944. {
  945. MRTU_WRIT_EMULT_RFRAME *pFrame; //返回数据帧格式
  946.  
  947. if(pHandle == NULL) return MRTU_HANDLE_ERROR; //句柄无效
  948. if((RegNum > 127) || (RegNum == 0)) return MRTU_REGN_ERROR; //寄存器数量错误
  949. pFrame = (MRTU_WRIT_EMULT_RFRAME *)pHandle->pTxBuff;
  950. //数据结构填充
  951. pFrame->addr = SlaveAddr; //从机地址
  952. pFrame->fun = MRTU_FUN_MWRITE; //功能码,预置多个寄存器
  953. pFrame->StartReg = SWAP16(RegAddr); //寄存器起始地址
  954. pFrame->RegNum = SWAP16(RegNum); //寄存器数量
  955. pFrame->crc16 = usMBCRC16(pHandle->pTxBuff, 6); //计算CRC16
  956. #if MODEBUS_RTU_DBUG
  957. {
  958. u16 i;
  959.  
  960. modebus_debug("\r\n<- MODEBUS RTU TXD(%dB)(CRC:0x%04X):\r\n",8,pFrame->crc16);
  961. for(i = 0;i < 8;i ++)
  962. {
  963. modebus_debug("0x%02X ",pHandle->pTxBuff[i]);
  964. }
  965. modebus_debug("\r\n");
  966. }
  967. #endif //MODEBUS_RTU_DBUG
  968.  
  969. MODEBUS_SendData(pHandle->UartCh, pHandle->pTxBuff, 8); //发送数据
  970.  
  971. return MRTU_OK; //返回成功
  972. }
  973.  
  974. /*************************************************************************************************************************
  975. * 函数 : MRTU_ERROR MODEBUS_SLAVE_ReadUnpack(MODEBUS_HANDLE *pHandle, MRTU_SLAVE_INFO *pFrameInfo)
  976. * 功能 : 解析来自主机的读取寄存器命令
  977. * 參数 : pHandle:modebus句柄;pFrameInfo:解析的信息结构
  978. * 返回 : MRTU_ERROR:通信状态
  979. * 依赖 : 底层通信驱动
  980. * 作者 : cp1300@139.com
  981. * 时间 : 2014-11-17
  982. * 最后改动时间 : 2014-11-17
  983. * 说明 : 用于将modebus的大端模式解析为小端模式
  984. 支持 MRTU_FUN_READ_HOLD,MRTU_FUN_READ_INPUT 命令解析
  985. *************************************************************************************************************************/
  986. void MODEBUS_SLAVE_ReadUnpack(MODEBUS_HANDLE *pHandle, MRTU_SLAVE_INFO *pFrameInfo)
  987. {
  988. MRTU_READ_FRAME *pReadRegFrame; //主机读取从机数据帧
  989.  
  990. pReadRegFrame = (MRTU_READ_FRAME *)pHandle->pRxBuff;
  991. pFrameInfo->SlaveAddr = pReadRegFrame->addr; //从机地址
  992. pFrameInfo->fun = pReadRegFrame->fun; //功能码
  993. pFrameInfo->StartReg = SWAP16(pReadRegFrame->StartReg); //寄存器起始地址
  994. pFrameInfo->RegNum = SWAP16(pReadRegFrame->RegNum); //寄存器数量
  995. }
  996.  
  997. /*************************************************************************************************************************
  998. * 函数 : void MODEBUS_SLAVE_WriteUnpack(MODEBUS_HANDLE *pHandle, MRTU_SLAVE_INFO *pFrameInfo, u16 *pData)
  999. * 功能 : 解析来自主机的预置单个寄存器命令
  1000. * 參数 : pHandle:modebus句柄;pFrameInfo:解析的信息结构;pData:须要写入从机的值
  1001. * 返回 : MRTU_ERROR:通信状态
  1002. * 依赖 : 底层通信驱动
  1003. * 作者 : cp1300@139.com
  1004. * 时间 : 2014-11-17
  1005. * 最后改动时间 : 2014-11-17
  1006. * 说明 : 用于将modebus的大端模式解析为小端模式
  1007. 支持 MRTU_FUN_WRITE 命令解析
  1008. *************************************************************************************************************************/
  1009. void MODEBUS_SLAVE_WriteUnpack(MODEBUS_HANDLE *pHandle, MRTU_SLAVE_INFO *pFrameInfo, u16 *pData)
  1010. {
  1011. MRTU_WRITE_FRAME *pWriteRegFrame; //主机预置单个保持寄存器
  1012.  
  1013. pWriteRegFrame = (MRTU_WRITE_FRAME *)pHandle->pRxBuff;
  1014. pFrameInfo->SlaveAddr = pWriteRegFrame->addr; //从机地址
  1015. pFrameInfo->fun = pWriteRegFrame->fun; //功能码
  1016. pFrameInfo->StartReg = SWAP16(pWriteRegFrame->StartReg); //寄存器起始地址
  1017. pFrameInfo->RegNum = 1; //寄存器数量
  1018. *pData = SWAP16(pWriteRegFrame->RegData); //须要写入的寄存器的值
  1019. }
  1020.  
  1021. /*************************************************************************************************************************
  1022. * 函数 : void MODEBUS_SLAVE_WriteMultUnpack(MODEBUS_HANDLE *pHandle, MRTU_SLAVE_INFO *pFrameInfo, u16 *pDataBuff)
  1023. * 功能 : 解析来自主机的预置多个寄存器命令
  1024. * 參数 : pHandle:modebus句柄;pFrameInfo:解析的信息结构;pDataBuff:须要写入从机寄存器值的数组,必须足够大,防止溢出
  1025. * 返回 : MRTU_ERROR:通信状态
  1026. * 依赖 : 底层通信驱动
  1027. * 作者 : cp1300@139.com
  1028. * 时间 : 2014-11-17
  1029. * 最后改动时间 : 2014-11-17
  1030. * 说明 : 用于将modebus的大端模式解析为小端模式
  1031. 支持 MRTU_FUN_MWRITE 命令解析
  1032. *************************************************************************************************************************/
  1033. void MODEBUS_SLAVE_WriteMultUnpack(MODEBUS_HANDLE *pHandle, MRTU_SLAVE_INFO *pFrameInfo, u16 *pDataBuff)
  1034. {
  1035. MRTU_WRITE_MULT_FRAME *pWriteMultRegFrame; //主机预置多个保持寄存器
  1036. u8 i;
  1037.  
  1038. pWriteMultRegFrame = (MRTU_WRITE_MULT_FRAME *)pHandle->pRxBuff;
  1039. pFrameInfo->SlaveAddr = pWriteMultRegFrame->addr; //从机地址
  1040. pFrameInfo->fun = pWriteMultRegFrame->fun; //功能码
  1041. pFrameInfo->StartReg = SWAP16(pWriteMultRegFrame->StartReg); //寄存器起始地址
  1042. pFrameInfo->RegNum = SWAP16(pWriteMultRegFrame->RegNum); //寄存器数量
  1043. //须要写入的寄存器的值
  1044. for(i = 0;i < pFrameInfo->RegNum;i ++)
  1045. {
  1046. pDataBuff[i] = pWriteMultRegFrame->DataBuff[2*i];
  1047. pDataBuff[i] <<= 8;
  1048. pDataBuff[i] |= pWriteMultRegFrame->DataBuff[2*i+1];
  1049. }
  1050. }
  1051. #endif //MODEBUS_RTU_SLAVE
  1052.  
  1053. //MODEBUS CRC16计算
  1054. //结果为大端模式
  1055. BIG_U16 usMBCRC16( u8 * pucFrame, u16 usLen )
  1056. {
  1057. static const u8 aucCRCHi[] = {
  1058. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
  1059. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
  1060. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
  1061. 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  1062. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
  1063. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
  1064. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
  1065. 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
  1066. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
  1067. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
  1068. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
  1069. 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  1070. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
  1071. 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  1072. 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  1073. 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  1074. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
  1075. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
  1076. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
  1077. 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  1078. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
  1079. 0x00, 0xC1, 0x81, 0x40
  1080. };
  1081.  
  1082. static const u8 aucCRCLo[] = {
  1083. 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
  1084. 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
  1085. 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
  1086. 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
  1087. 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
  1088. 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
  1089. 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
  1090. 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
  1091. 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
  1092. 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
  1093. 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
  1094. 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
  1095. 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB,
  1096. 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
  1097. 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
  1098. 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
  1099. 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97,
  1100. 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
  1101. 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89,
  1102. 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
  1103. 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
  1104. 0x41, 0x81, 0x80, 0x40
  1105. };
  1106.  
  1107. u8 ucCRCHi = 0xFF;
  1108. u8 ucCRCLo = 0xFF;
  1109. int iIndex;
  1110.  
  1111. while( usLen-- )
  1112. {
  1113. iIndex = ucCRCLo ^ *( pucFrame++ );
  1114. ucCRCLo = ( u8 )( ucCRCHi ^ aucCRCHi[iIndex] );
  1115. ucCRCHi = aucCRCLo[iIndex];
  1116. }
  1117. return ( u16 )( ucCRCHi << 8 | ucCRCLo );
  1118. }
  1119.  
  1120. /*************************************************************************************************************************
  1121. * 函数 : void MODEBUS_32TO16(u16 *Out16H, u16 *Out16L, u32 In32)
  1122. * 功能 : 将32bit数据拆分为高低16位,而且使用大端模式,兼容modebus
  1123. * 參数 : Out16H:拆分的高16位,大端模式;Out16L:拆分的低16位,大端模式;In32:须要拆分的数据,小端模式,兼容STM32
  1124. * 返回 : 无
  1125. * 依赖 : 无
  1126. * 作者 : cp1300@139.com
  1127. * 时间 : 2014-05-27
  1128. * 最后改动时间 : 2014-05-27
  1129. * 说明 : 将STM32 32位数据拆分为兼容MODEBUS 大端模式
  1130. *************************************************************************************************************************/
  1131. void MODEBUS_32TO16(u16 *Out16H, u16 *Out16L, u32 In32)
  1132. {
  1133. *Out16H = SWAP16(In32 >> 16);
  1134. *Out16L = SWAP16(In32 & 0xffff);
  1135. }
  1136.  
  1137. /*************************************************************************************************************************
  1138. * 函数 : u32 MODEBUS_16TO32(u16 In16H, u16 In16L)
  1139. * 功能 : 将modebus高低16位转换为小端模式的32位数
  1140. * 參数 : In16H:大端模式的高16位数;In16L:大端模式的低16位数
  1141. * 返回 : 32bit的整形数据
  1142. * 依赖 : 无
  1143. * 作者 : cp1300@139.com
  1144. * 时间 : 2014-05-27
  1145. * 最后改动时间 : 2014-05-27
  1146. * 说明 : 将modebus的2个16bit寄存器组成一个兼容STM32的32bit整形数
  1147. *************************************************************************************************************************/
  1148. u32 MODEBUS_16TO32(u16 In16H, u16 In16L)
  1149. {
  1150. u32 temp;
  1151.  
  1152. temp = SWAP16(In16H);
  1153. temp <<= 16;
  1154. temp |= SWAP16(In16L);
  1155.  
  1156. return temp;
  1157. }

//modebus_rtu.h

/*************************************************************************************************************
* 文件名称: MODEBUS_RTU.c
* 功能: MODEBUS_RTU通信协议层
* 作者: cp1300@139.com
* 创建时间: 2014-03-24
* 最后改动时间:2014-11-17
* 具体: MODEBUS RTU通信协议层
*************************************************************************************************************/
#ifndef _MODEBUS_RTU_H_
#define _MODEBUS_RTU_H_ #include "system.h"
#include "ucos_ii.h" /***********************配置相关************************/
#define MODEBUS_RTU_HOST 1 //1:开启主机模式;0:关闭主机模式
#define MODEBUS_RTU_SLAVE 1 //1:开启从机模式;0:关闭从机模式
/*********************************************************/ //16位整形数高低对调
#define SWAP16(x) (((x & 0xff00) >> 8) | ((x & 0xff) << 8)) /***********************关接口函数************************/
/**********************移植须要改动***********************/
#define MODEBUS_UartInit(ch,Speed) UARTx_Init((UART_CH_Type)ch, Speed, ENABLE) //串口初始化
#define MODEBUS_GetDataCnt(ch) UARTx_GetRxCnt((UART_CH_Type)ch) //获取接收数据计数器
#define MODEBUS_ClearRxCnt(ch) UARTx_ClearRxCnt((UART_CH_Type)ch) //清除接收数据计数器
#define MODEBUS_GetDataOver(ch) UARTx_GetRxBuffFullFlag((UART_CH_Type)ch) //获取数据溢出标志
#define MODEBUS_SendData(ch,pbuff,len) UARTx_SendData((UART_CH_Type)ch, pbuff, len) //数据发送
#define MODEBUS_SetRxBuff(ch, RxBuff, RxBuffSize) UARTx_SetRxBuff((UART_CH_Type)ch, RxBuff, RxBuffSize) //设置串口接收缓冲区
#define MODEBUS_DisableRx(ch) (UARTx_EnableRx((UART_CH_Type)ch, DISABLE)) //串口接收关闭
#define MODEBUS_EnableRx(ch) (UARTx_EnableRx((UART_CH_Type)ch, ENABLE)) //串口接收使能
#define MODEBUS_SetBaudRate(ch, x) (UARTx_SetBaudRate((UART_CH_Type)ch, x)) //设置串口波特率
//系统延时函数,依据实际改动,假设使用ucos建议使用ucos系统延时
#define MODEBUS_Delay10MS() OSTimeDlyHMSM(0,0,0,10) //10ms延时,字节超时固定为10ms
/*********************************************************/ //支持的功能码
#define MRTU_FUN_READ_HOLD 0x03 //读保持寄存器,可读写寄存器为保持寄存器
#define MRTU_FUN_READ_INPUT 0x04 //读输入寄存器,为仅仅读寄存器
#define MRTU_FUN_WRITE 0x06 //写单个保持寄存器
#define MRTU_FUN_MWRITE 0x10 //写多个保持寄存器 //大端数据标记
#define BIG_U16 u16 //16位整形数,须要转换为大端模式,兼容modubus //读取寄存器类型选择
typedef enum
{
HOLD_REG = MRTU_FUN_READ_HOLD, //保持寄存器
INPUT_REG = MRTU_FUN_READ_INPUT, //输入寄存器
} READ_REG_TYPE; //数据读取 主机数据帧,主机读取从机的数据帧
typedef __packed struct
{
u8 addr; //地址 address
u8 fun; //功能码 function
BIG_U16 StartReg; //数据起始地址
BIG_U16 RegNum; //须要读取的寄存器个数
BIG_U16 CRC16; //CRC16
} MRTU_READ_FRAME; //MODEBUS RTU master Read Reg Frame //预置单个保持寄存器,主机写从机单个寄存器的数据帧
//从机返回数据帧与主机预置单个寄存器数据帧一样
typedef __packed struct
{
u8 addr; //地址 address
u8 fun; //功能码 function
BIG_U16 StartReg; //数据起始地址
BIG_U16 RegData; //数据值
BIG_U16 crc16; //CRC校验值
} MRTU_WRITE_FRAME; //MODEBUS RTU master Write Reg Frame //预置多个保持寄存器,主机写从机多个寄存器的数据帧
typedef __packed struct
{
u8 addr; //地址 address
u8 fun; //功能码 function
BIG_U16 StartReg; //数据起始地址
BIG_U16 RegNum; //寄存器数量
u8 DataLen; //数据长度
u8 DataBuff[2]; //寄存器的值
} MRTU_WRITE_MULT_FRAME; //预置多个保持寄存器后返回数据帧,从机返回主机的数据帧
typedef __packed struct
{
u8 addr; //地址 address
u8 fun; //功能码 function
BIG_U16 StartReg; //数据起始地址
BIG_U16 RegNum; //寄存器数量
BIG_U16 crc16; //CRC校验值
} MRTU_WRIT_EMULT_RFRAME; //读取从机返回数据帧格式,从机返回给主机的数据帧
typedef __packed struct
{
u8 addr; //地址 address
u8 fun; //功能码 function
u8 DataLen; //数据长度
u8 DataBuff[2]; //数据区,CRC16放在最后结尾处
//MRTU_REG16 CRC16; //CRC16
} MRTU_RETURN_FRAME; //MODEBUS RTU master Read Reg Frame //从机返回的异常数据帧,从机返回的异常数据帧
typedef __packed struct
{
u8 addr; //地址 address
u8 ErrorFun; //错误功能码 function+0x80
u8 unu; //异常码
u8 crc16H; //CRC16放在最后结尾处
u8 crc16L; //CRC16放在最后结尾处
} MRTU_UNU_FRAME; //从机数据包解析后的相关信息
typedef struct
{
u8 SlaveAddr; //主机发送的从机地址
u8 RegNum; //主机须要读取从机的寄存器数量
u8 fun; //主机发送给从机的功能码
u16 StartReg; //主机须要读写的从机寄存器地址
} MRTU_SLAVE_INFO; //异常码定义
typedef enum
{
MRTU_UNUS1 = 0x01, //异常码1,无效的操作码
MRTU_UNUS2 = 0x02, //异常码2,无效的数据地址
MRTU_UNUS3 = 0x03, //异常码3,无效的数据值
MRTU_UNUS4 = 0x04, //异常码4,无效操作
MRTU_UNUS5 = 0x05, //异常码5
MRTU_UNUS6 = 0x06, //异常码6
} MRTU_UNUS; //错误状态
typedef enum
{
MRTU_OK = 0, //OK
MRTU_TIME_OUT = 1, //超时
MRTU_OVER_ERROR = 2, //溢出
MRTU_CRC_ERROR = 3, //CRC错误
MRTU_ADDR_ERROR = 4, //地址错误,返回地址不一致
MRTU_REG_ERROR = 5, //寄存器地址错误,返回寄存器地址不一致
MRTU_FUNR_ERROR = 6, //功能码错误,返回功能码不一致或者不支持的功能码
MRTU_HANDLE_ERROR = 7, //句柄错误,句柄为空
MRTU_REGN_ERROR = 8, //寄存器数量错误
MRTU_LEN_ERROR = 9, //返回数据长度错误
MRTU_WRITE_ERROR = 10, //写寄存器错误,写入与读取不一致
MRTU_UNUS1_ERROR = 0x81, //异常码1,无效的操作码
MRTU_UNUS2_ERROR = 0x82, //异常码2,无效的数据地址
MRTU_UNUS3_ERROR = 0x83, //异常码3,无效的数据值
MRTU_UNUS4_ERROR = 0x84, //异常码4,无效操作
MRTU_UNUS5_ERROR = 0x85, //异常码5
MRTU_UNUS6_ERROR = 0x86, //异常码6
MRTU_OTHER_ERROR = 0xff
} MRTU_ERROR; //MODEBUS句柄结构
typedef struct
{
u8 UartCh; //串口通道
u32 BaudRate; //通信波特率
u8 *pRxBuff; //接收缓冲区
u8 *pTxBuff; //发送缓冲区
u32 RxBuffSize; //接收缓冲区大小
u32 TxPacketNum; //发送数据包计数
u32 RxPacketNum; //接收数据包计数
u32 ErrorNum; //通信错误计数
u16 TimeOut; //通信超时时间,单位ms
u16 ReturnTime; //数据返回时间,单位ms,仅仅对于主机有效
} MODEBUS_HANDLE; bool MODEBUS_Init(MODEBUS_HANDLE *pHandle, u8 UartCh, u32 BaudRate, u8 *pRxBuff,u8 *pTxBuff, u32 RxBuffSize, u32 TimeOut); //初始化modebus
#if(MODEBUS_RTU_HOST) //开启主机模式
MRTU_ERROR MODEBUS_HOST_ReadReg(MODEBUS_HANDLE *pHandle, READ_REG_TYPE RegType, u8 SlaveAddr, u16 RegAddr, u16 *pRegData); //主机读取从机指定单个寄存器
MRTU_ERROR MODEBUS_HOST_ReadMultReg(MODEBUS_HANDLE *pHandle, READ_REG_TYPE RegType, u8 SlaveAddr, u16 RegAddr, u8 RegNum, u16 pRegData[]); //主机读取从机多个指定寄存器
MRTU_ERROR MODEBUS_HOST_WriteReg(MODEBUS_HANDLE *pHandle,u8 SlaveAddr, u16 RegAddr, u16 RegData); //主机写从机单个保持寄存器
MRTU_ERROR MODEBUS_HOST_WriteMultReg(MODEBUS_HANDLE *pHandle,u8 SlaveAddr, u16 RegAddr, u8 RegNum, u16 pRegData[]); //主机写从机单个保持寄存器
#endif #if(MODEBUS_RTU_SLAVE) //开启从机模式
bool MODEBUS_SLAVE_RetrunUnu(MODEBUS_HANDLE *pHandle,u8 SlaveAddr, u8 Fun, MRTU_UNUS Unus); //从机返回异常码
MRTU_ERROR MODEBUS_SLAVE_FramesUnpack(MODEBUS_HANDLE *pHandle,u8 SlaveAddr, u32 DataLen, u8 *pFun); //从机解析数据包
MRTU_ERROR MODEBUS_SLAVE_ReturnReadReg(MODEBUS_HANDLE *pHandle, u8 Fun, u8 SlaveAddr, u16 RegAddr, u8 RegNum, u16 pRegData[]); //从机返回主机读取的寄存器
MRTU_ERROR MODEBUS_SLAVE_ReturnWriteHoldReg(MODEBUS_HANDLE *pHandle,u8 SlaveAddr, u16 RegAddr, u16 RegData); //从机返回主机写入单个寄存器命令
MRTU_ERROR MODEBUS_SLAVE_ReturnWriteMultHoldReg(MODEBUS_HANDLE *pHandle, u8 SlaveAddr, u16 RegAddr, u8 RegNum); //从机返回主机写多个寄存器命令
void MODEBUS_SLAVE_ReadUnpack(MODEBUS_HANDLE *pHandle, MRTU_SLAVE_INFO *pFrameInfo); //从机解析主机读取命令
void MODEBUS_SLAVE_WriteUnpack(MODEBUS_HANDLE *pHandle, MRTU_SLAVE_INFO *pFrameInfo, u16 *pData); //从机解析主机写单个寄存器命令
void MODEBUS_SLAVE_WriteMultUnpack(MODEBUS_HANDLE *pHandle, MRTU_SLAVE_INFO *pFrameInfo, u16 *pDataBuff); //从机解析主机多个寄存器命令
#endif u16 usMBCRC16( u8 * pucFrame, u16 usLen ); //crc计算
void MODEBUS_32TO16(u16 *Out16H, u16 *Out16L, u32 In32); //将32bit数据拆分为高低16位,而且使用大端模式,兼容modebus
u32 MODEBUS_16TO32(u16 In16H, u16 In16L); //将modebus高低16位转换为小端模式的32位数 #endif /*_MODEBUS_RTU_H_*/

//从机測试

//主机比較简单就不写了

//任务2:
//ModeBus
u8 ModebusBuff[128];
void TaskModeBus(void *pdata)
{
MODEBUS_HANDLE ModebusHandle1;
MRTU_SLAVE_INFO FrameInfo; //modebus读写信息 u16 data;
u16 RegBuff[20];
u8 i;
u32 cnt1 = 0,cnt2 = 0;
u8 Fun; for(i = 0;i < 10;i ++)
{
RegBuff[i] = i+1;
}
MODEBUS_Init(&ModebusHandle1, UART_CH2, 115200, ModebusBuff, ModebusBuff, 128-1, 200);
MODEBUS_EnableRx(ModebusHandle1.UartCh); //使能接收
MODEBUS_ClearRxCnt(ModebusHandle1.UartCh); //清除接收
while(1)
{
cnt2 = cnt1;
cnt1 = MODEBUS_GetDataCnt(ModebusHandle1.UartCh);
if((cnt1 == cnt2) && (cnt1 != 0))
{
MODEBUS_DisableRx(ModebusHandle1.UartCh); //关闭接收
MODEBUS_ClearRxCnt(ModebusHandle1.UartCh); //清除接收
if(MODEBUS_SLAVE_FramesUnpack(&ModebusHandle1, 1, cnt1, &Fun) == MRTU_OK)
{
uart_printf("收到数据,功能码:0x%02X\r\n", Fun);
switch(Fun)
{
case MRTU_FUN_READ_HOLD : //读保持寄存器,可读写寄存器为保持寄存器
case MRTU_FUN_READ_INPUT : //读输入寄存器,为仅仅读寄存器
{
//解析
MODEBUS_SLAVE_ReadUnpack(&ModebusHandle1, &FrameInfo);
//数据处理
uart_printf("主机读取从机(%d)从%d開始的寄存器,共须要读取%d个\r\n", FrameInfo.SlaveAddr, FrameInfo.StartReg, FrameInfo.RegNum);
//返回
MODEBUS_SLAVE_ReturnReadReg(&ModebusHandle1, FrameInfo.fun, FrameInfo.SlaveAddr, FrameInfo.StartReg, FrameInfo.RegNum, RegBuff);
}break;
case MRTU_FUN_WRITE : //写单个保持寄存器
{
//解析
MODEBUS_SLAVE_WriteUnpack(&ModebusHandle1, &FrameInfo, &data);
//数据处理
uart_printf("主机写从机(%d)的寄存器%d值为:0x%02X\r\n", FrameInfo.SlaveAddr, FrameInfo.StartReg, data);
//返回
MODEBUS_SLAVE_ReturnWriteHoldReg(&ModebusHandle1, FrameInfo.SlaveAddr, FrameInfo.StartReg, data);
}break;
case MRTU_FUN_MWRITE : //写多个保持寄存器
{
//解析
MODEBUS_SLAVE_WriteMultUnpack(&ModebusHandle1, &FrameInfo, RegBuff);
//数据处理
uart_printf("主机写从机(%d),从%d開始的寄存器,共%d个,数据为:", FrameInfo.SlaveAddr, FrameInfo.StartReg, FrameInfo.RegNum);
for(i = 0;i < FrameInfo.RegNum;i ++)
{
uart_printf("0x%04X ", RegBuff[i]); //打印数据
}
uart_printf("\r\n");
//返回
MODEBUS_SLAVE_ReturnWriteMultHoldReg(&ModebusHandle1, FrameInfo.SlaveAddr, FrameInfo.StartReg, FrameInfo.RegNum);
}break;
default:break;
} }
MODEBUS_EnableRx(ModebusHandle1.UartCh); //使能接收
}
OSTimeDlyHMSM(0,0,0,200);
}
}

模拟主机

从机接收处理

单片机modebus RTU通信实现,採用C语言,可适用于单片机,VC,安卓等的更多相关文章

  1. 单片机modebus RTU通信实现,采用C语言,可适用于单片机,VC,安卓等(转)

    源:单片机modebus RTU通信实现,采用C语言,可适用于单片机,VC,安卓等 //modebus_rtu.c /***************************************** ...

  2. Modbus RTU 通信工具设计(转)

    Modbus RTU 通信工具设计 Modbus 是一个工业上常用的通讯协议.一种通讯约定. ModBus 协议是应用层报文传输协议(OSI 模型第7层),它定义了一个与通信层无关的协议数据单元(PD ...

  3. Modbus RTU 通信应用案例

    如何打开项目归档文件 例程中的TIA博途项目文件与STEP 7项目文件均为归档文件,需要按如下方式打开: TIA博途项目文件 1. 打开TIA博途软件,通过软件左下方“项目视图”按钮切换至项目视图: ...

  4. C# NModbus RTU通信实现

    Modbus协议时应用于电子控制器上的一种通用语言.通过此协议,控制器相互之间.控制器经由网络/串口和其它设备之间可以进行通信.它已经成为了一种工业标准.有了这个通信协议,不同的厂商生成的控制设备就可 ...

  5. 安卓能用的modebus CRC16计算,附上对应的C语言的CRC16(转)

    源:安卓能用的modebus CRC16计算,附上对应的C语言的CRC16 “源”即是原文地址,想了解作都更多文章及思想请移步到“源”.转过只是为了本人感兴趣的文章查找方便. 正文: 最近写安卓串口通 ...

  6. 单片机成长之路(51基础篇) - 002 STC单片机冷启动和复位有什么区别

    STC单片机简介 STC单片机是一款增强型51单片机,完全兼容MCS-51,还增加了新的功能,比如新增两级中断优先级,多一个外中断,内置EEPROM,硬件看门狗,具有掉电模式,512B内存等.还支持I ...

  7. c语言编写51单片机中断程序,执行过程是怎样的?

    Q:c语言编写51单片机中断程序,执行过程是怎样的? 例如程序:#include<reg52.h>  void main(void)  {   EA=1;      //开放总中断   E ...

  8. PC和单片机通过MODBUS RTU通信

    最近研究了一下MODBUS通信,在STC12C5A60S2单片机上实现了MODBUS协议的部分功能,方便上位机从单片机系统上获取数据,比如由单片机获取的温度.湿度.或者控制信号的状态等.有了MODBU ...

  9. Android蓝牙实例(和单片机蓝牙模块通信)

    最近做毕设,需要写一个简单的蓝牙APP进行交互,在网上也找了很多资料,终于给搞定了,这里分享一下^_^. 1.Android蓝牙编程 蓝牙3.0及以下版本编程需要使用UUID,UUID是通用唯一识别码 ...

随机推荐

  1. NSIS学习笔记(转)

    转自:http://blog.csdn.net/lee353086/article/details/45919901 NSIS学习笔记Date:2015-05-20Author:kagulaEnv:V ...

  2. Linux网卡启动报错(this device is not active)

    重启网络服务 service network restart   报如下错误:   shutting down interface eth0: error:device "eth0" ...

  3. Java多线程学习总结--线程同步(2)

    线程同步是为了让多个线程在共享数据时,保持数据的一致性.举个例子,有两个人同时取钱,假设用户账户余额是1000,第一个用户取钱800,在第一个用户取钱的同时,第二个用户取钱600.银行规定,用户不允许 ...

  4. 非阻塞式socket的select()用法

    Select在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只 是习惯写诸如 connect.accept.recv或recvfrom这样的阻塞程 ...

  5. mysql 中时间和日期函数应用

    一.MySQL 获得当前日期时间 函数 1.1 获得当前日期+时间(date + time)函数:now() mysql> select now(); +-------------------- ...

  6. 用python产生一个好的秘钥

    import os os.urandom(24)

  7. HDU5874:Friends and Enemies

    题目链接: Friends and Enemies 分析: 是一道想法题,我们假设x个人互相敌对,然后有y个人与这x个人都是朋友,而这y个人互相敌对. 则有 x+y=m x*y<=n 举个例子: ...

  8. 使用Sunny-grok实现内网转发

    Sunny-grok 申请地址:http://www.ngrok.cc ngrok.cfg配置: server_addr: "server.ngrok.cc:4443" auth_ ...

  9. 前端复习-01-dom操作包括ie和现代浏览器处理相关

    一.事件流事件流描述的是从页面中接受事件的顺序.IE的事件流是事件冒泡流,而Netscape的事件流是事件捕获流1.事件冒泡事件冒泡,即事件最开始由最具体的元素(文档中嵌套层次最深的那个节点)接收,然 ...

  10. 缓存需要注意的问题以及使用.net正则替换字符串的方法

    参考资料:http://www.infoq.com/cn/news/2015/09/cache-problems 正则替换字符串的简单方法: var regTableType = new Regex( ...