找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 6667|回復: 10
打印 上一主題 下一主題
收起左側(cè)

支持作為Modbus從站設備的Modbus RTU模式的源碼

  [復制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:360570 發(fā)表于 2018-6-27 20:47 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
  1. //----------------------------------------------------------------------------//
  2. //此代碼只支持作為Modbus從站設備的Modbus RTU模式
  3. //
  4. //支持的功能碼:
  5. //0x03 讀保持寄存器(讀多個保持寄存器的值,有效地位為0-99)
  6. //0x06 寫單個寄存器(寫入一個寄存器的值,有效地址為0-99)
  7. //0x10 寫多個寄存器(寫入多個寄存器的值,有效地址為0-99)
  8. //
  9. //支持的異常碼:
  10. //0x01 非法功能碼(不支持的功能碼)
  11. //0x02 非法數(shù)據(jù)地址(起始地址不在有效范圍內(nèi))
  12. //0x03 非法數(shù)據(jù)值(在起始地址的基礎(chǔ)上,數(shù)量是不合法的)
  13. //----------------------------------------------------------------------------//

  14. #include "Modbus.h"
  15. #include "main.h"

  16. /* 變量定義 ------------------------------------------------------------------*/
  17. uint8_t Modbus_Send_Buff[Modbus_Max_Send_Buff];                //發(fā)送數(shù)據(jù)緩沖區(qū)
  18. uint8_t Modbus_Rcv_Buff[Modbus_Max_Rcv_Buff];                //接收數(shù)據(jù)緩沖區(qū)
  19. uint8_t Modbus_Timeout_Cnt;                                                        //定時器中斷計數(shù)
  20. uint8_t Modbus_Rcv_Cnt;                                                                //接收字節(jié)計數(shù)
  21. uint8_t        Modbus_Rcv_flag;                                                        //設備進入接收狀態(tài)標志
  22. uint8_t Modbus_Cmd_flag;                                                        //設備進入命令解析狀態(tài)標志
  23. uint8_t Modbus_Exe_flag;                                                        //設備進入命令執(zhí)行狀態(tài)標志
  24. uint8_t Modbus_Function;                                                        //從站設備需執(zhí)行的功能

  25. uint16_t HoldingReg[100] = {0x0123, 0x4567, 0x89AB, 0xCDEF};                                //保持寄存器

  26. /* 函數(shù)定義 ------------------------------------------------------------------*/

  27. //----------------------------------------------------------------------------//
  28. //函數(shù)功能:逐位計算法CRC16校驗,在Modbus中CRC結(jié)果要進行高低字節(jié)交換,即低字節(jié)在前,高字節(jié)在后
  29. //入口參數(shù):puchMsg是要進行CRC校驗的消息;usDataLen是消息中字節(jié)數(shù)
  30. //出口參數(shù):計算出來的CRC校驗碼,16位長度
  31. //最后修改:2015.11.29
  32. //備注:
  33. //----------------------------------------------------------------------------//
  34. uint16_t Modbus_CRC16(uint8_t *puchMsg, uint8_t usDataLen)
  35. {
  36.         uint16_t CRC_Cal = 0xFFFF;
  37.         uint8_t CRC_High, CRC_Low;
  38.         uint8_t i, j;
  39.         
  40.         for(j = 0; j < usDataLen; j++)
  41.         {
  42.                 CRC_Cal = CRC_Cal ^ *puchMsg++;
  43.                
  44.                 for (i = 0; i < 8; i++)
  45.                 {
  46.                         if((CRC_Cal & 0x0001) == 0x0001)
  47.                         {
  48.                                 CRC_Cal = CRC_Cal >> 1;
  49.                                 CRC_Cal = CRC_Cal ^ 0xA001;
  50.                         }
  51.                         else
  52.                         {
  53.                                 CRC_Cal = CRC_Cal >> 1;
  54.                         }
  55.                 }
  56.         }
  57.         
  58.         CRC_High = (uint8_t)(CRC_Cal >> 8);
  59.         CRC_Low = (uint8_t)(CRC_Cal & 0x00FF);
  60.         
  61.         return (CRC_Low << 8 | CRC_High);
  62.         
  63. //        return CRC_Cal;

  64. }

  65. //----------------------------------------------------------------------------//
  66. //函數(shù)功能:Modbus初始化
  67. //入口參數(shù):ID是從站站號
  68. //出口參數(shù):無
  69. //最后修改:2015.11.20
  70. //備注:
  71. //----------------------------------------------------------------------------//
  72. void Modbus_Init(void)
  73. {
  74.         uint16_t i;
  75.         
  76.         //----------------------------------------------------------//
  77.         //Modbus相關(guān)變量初始化
  78.         //----------------------------------------------------------//
  79.         Modbus_Timeout_Cnt = 0;
  80.         Modbus_Rcv_Cnt = 0;
  81.         Modbus_Rcv_flag = 0;
  82.         Modbus_Cmd_flag = 0;
  83.         Modbus_Exe_flag = 0;
  84.         
  85.         for(i = 0; i < Modbus_Max_Rcv_Buff; i++)                //清除接收緩沖區(qū)
  86.         {
  87.                 Modbus_Rcv_Buff[i] = '\0';
  88.         }
  89.         
  90.         for(i = 0; i < Modbus_Max_Send_Buff; i++)                //清除發(fā)送緩沖區(qū)
  91.         {
  92.                 Modbus_Send_Buff[i] = '\0';
  93.         }
  94.         
  95.         //----------------------------------------------------------//
  96.         //TIM2定時器使能
  97.         //----------------------------------------------------------//
  98.         TIM_Cmd(TIM2, ENABLE);
  99. }

  100. //----------------------------------------------------------------------------//
  101. //函數(shù)功能:Modbus命令解析函數(shù)
  102. //入口參數(shù):無
  103. //出口參數(shù):無
  104. //最后修改:2015.12.11
  105. //備注:
  106. //----------------------------------------------------------------------------//
  107. void Modbus_Cmd(void)
  108. {
  109.         uint8_t Modbus_CRC_Rcv_Hi;                //接收到的ModbusCRC校驗碼高字節(jié)
  110.         uint8_t Modbus_CRC_Rcv_Lo;                //接收到的ModbusCRC校驗碼低字節(jié)
  111.         uint16_t Modbus_CRC_Rcv;                //接收到的ModbusCRC校驗碼
  112.         uint16_t Modbus_CRC_Cal;                //根據(jù)接收到的數(shù)據(jù)計算出來的CRC值
  113.         
  114.         //----------------------------------------------------------//
  115.         //開始命令解析
  116.         //----------------------------------------------------------//
  117.         if(Modbus_Cmd_flag == 1)
  118.         {
  119.                 if(Modbus_Rcv_Cnt > 4)                //如果接收到的一幀的字節(jié)數(shù)大于4 首先確保幀的長度在正常范圍
  120.                 {
  121.                         Modbus_CRC_Rcv_Lo = Modbus_Rcv_Buff[Modbus_Rcv_Cnt - 2];                                        //接收到的ModbusCRC校驗碼低字節(jié)
  122.                         Modbus_CRC_Rcv_Hi = Modbus_Rcv_Buff[Modbus_Rcv_Cnt - 1];                                        //接收到的ModbusCRC校驗碼高字節(jié)
  123.                         Modbus_CRC_Rcv = (uint16_t)(Modbus_CRC_Rcv_Lo << 8 | Modbus_CRC_Rcv_Hi);        //接收到的ModbusCRC校驗碼(16位)
  124.                         Modbus_CRC_Cal = Modbus_CRC16(Modbus_Rcv_Buff, Modbus_Rcv_Cnt - 2);                        //根據(jù)接收到的數(shù)據(jù)計算CRC值
  125.                         
  126.                         if(Modbus_CRC_Cal == Modbus_CRC_Rcv)                //如果計算的CRC值與接受的CRC值相等
  127.                         {
  128.                                 //USART_SendByte(USART1, 0xAC);
  129.                                 if(Slave_Address == Modbus_Rcv_Buff[0])        //如果是本機地址
  130.                                 {
  131.                                         switch(Modbus_Rcv_Buff[1])                        //用switch分支語句來確定功能
  132.                                         {
  133.                                         case Modbus_ReadHoldingReg:                                                //如果是讀保存寄存器
  134.                                                 Modbus_Function = Modbus_ReadHoldingReg;        //將從站設備需執(zhí)行的功能賦值為讀保存寄存器
  135.                                                 Modbus_Exe_flag = 1;                                                //設備進入命令執(zhí)行狀態(tài)
  136.                                                 break;                                                                                //跳出分支語句
  137.                                                 
  138.                                         case Modbus_WriteSingleReg:
  139.                                                 Modbus_Function = Modbus_WriteSingleReg;        //將從站設備需執(zhí)行的功能賦值為寫單個寄存器
  140.                                                 Modbus_Exe_flag = 1;                                                //設備進入命令執(zhí)行狀態(tài)
  141.                                                 break;                                                                                //跳出分支語句
  142.                                        
  143.                                         case Modbus_WriteMultipleReg:
  144.                                                 Modbus_Function = Modbus_WriteMultipleReg;        //將從站設備需執(zhí)行的功能賦值為寫多個寄存器
  145.                                                 Modbus_Exe_flag = 1;                                                //設備進入命令執(zhí)行狀態(tài)
  146.                                                 break;                                                                                //跳出分支語句
  147.                                                 
  148.                                         default:
  149.                                                 Modbus_ErrorHandling(0x01);                //所有功能碼都不符合,則返回功能碼錯誤異常響應報文
  150.                                                 return;
  151.                                         }
  152.                                 }
  153.                                 
  154.                                 else                //否則清空接收數(shù)據(jù)緩沖區(qū)和發(fā)送數(shù)據(jù)緩沖區(qū)
  155.                                 {
  156.                                         Modbus_ClearBuff();
  157.                                 }
  158.                         }
  159.                         
  160.                         else                //否則清空接收數(shù)據(jù)緩沖區(qū)和發(fā)送數(shù)據(jù)緩沖區(qū)
  161.                         {
  162.                                 Modbus_ClearBuff();
  163.                         }
  164.                         
  165.                 }
  166.                
  167.                 else                //否則清空接收數(shù)據(jù)緩沖區(qū)和發(fā)送數(shù)據(jù)緩沖區(qū)
  168.                 {
  169.                         Modbus_ClearBuff();
  170.                 }
  171.                
  172.                 Modbus_Cmd_flag = 0;                //設備退出命令解析狀態(tài)標志
  173.         }
  174. }

  175. //----------------------------------------------------------------------------//
  176. //函數(shù)功能:Modbus命令執(zhí)行函數(shù)
  177. //入口參數(shù):無
  178. //出口參數(shù):無
  179. //最后修改:2015.12.6
  180. //備注:
  181. //----------------------------------------------------------------------------//
  182. void Modbus_Exe(void)
  183. {
  184.         if(Modbus_Exe_flag == 1)
  185.         {
  186.                 switch(Modbus_Function)
  187.                 {
  188.                 case Modbus_ReadHoldingReg:
  189.                         Modbus_ReadHoldingReg_Process();
  190.                         break;
  191.                         
  192.                 case Modbus_WriteSingleReg:
  193.                         Modbus_WriteSingleReg_Process();
  194.                         break;
  195.                
  196.                 case Modbus_WriteMultipleReg:
  197.                         Modbus_WriteMultipleReg_Process();
  198.                         break;
  199.                         
  200.                 }
  201.                 Modbus_Exe_flag = 0;
  202.         }
  203. }

  204. //----------------------------------------------------------------------------//
  205. //函數(shù)功能:功能碼0x03,讀保持寄存器
  206. //入口參數(shù):無
  207. //出口參數(shù):無
  208. //最后修改:2015.12.5
  209. //備注:
  210. //----------------------------------------------------------------------------//
  211. void Modbus_ReadHoldingReg_Process(void)
  212. {
  213.         uint8_t Send_Cnt;                        //發(fā)送字節(jié)數(shù)量
  214.         uint16_t StartAddress_Reg;        //要讀取的寄存器起始地址
  215.         uint16_t Num_Reg;                        //要讀取的寄存器的數(shù)量
  216.         uint16_t CRC_Cal;                        //CRC校驗碼
  217.         uint16_t i, j;                                //臨時變量
  218.         
  219.         StartAddress_Reg = Modbus_Rcv_Buff[2] << 8 | Modbus_Rcv_Buff[3];        //從接收數(shù)據(jù)緩沖區(qū)得到要讀取的寄存器起始地址
  220.         Num_Reg = Modbus_Rcv_Buff[4] << 8 | Modbus_Rcv_Buff[5];                                //從接收數(shù)據(jù)緩沖區(qū)得到要讀取的寄存器數(shù)量
  221.         
  222.         if(StartAddress_Reg < 100)                //寄存器起始地址在正確范圍內(nèi)
  223.         {
  224.                 if(StartAddress_Reg + Num_Reg < 100 && Num_Reg > 0)                //起始地址+寄存器數(shù)量位于正確范圍內(nèi) 并且 寄存器數(shù)量正確
  225.                 {        
  226.                         Send_Cnt = 3 + (Num_Reg << 1) + 2;                //計算發(fā)送字節(jié)數(shù)量
  227.         
  228.                         Modbus_Send_Buff[0] = Slave_Address;                        //從站地址
  229.                         Modbus_Send_Buff[1] = Modbus_ReadHoldingReg;        //功能碼
  230.                         Modbus_Send_Buff[2] = Num_Reg << 1;                                //寄存器字節(jié)數(shù)量 等于 寄存器數(shù)量乘2
  231.                         
  232.                         for(i = StartAddress_Reg, j = 3; i < StartAddress_Reg + Num_Reg; i++, j += 2)        //讀取寄存器的數(shù)據(jù)
  233.                         {
  234.                                 Modbus_Send_Buff[j] = (uint8_t)(HoldingReg[i] >> 8);
  235.                                 Modbus_Send_Buff[j + 1] = (uint8_t)(HoldingReg[i] & 0x00FF);
  236.                         }
  237.         
  238.                         CRC_Cal = Modbus_CRC16(Modbus_Send_Buff, 3 + (Num_Reg << 1));                                //計算發(fā)送數(shù)據(jù)的CRC校驗碼
  239.                         Modbus_Send_Buff[3 + (Num_Reg << 1)] = (uint8_t)(CRC_Cal >> 8);                                //先是低字節(jié)
  240.                         Modbus_Send_Buff[3 + (Num_Reg << 1) + 1] = (uint8_t)(CRC_Cal & 0x00FF);                //后是高字節(jié)
  241.         
  242.                         USART_SendString(USART1, Modbus_Send_Buff, Send_Cnt);                        //發(fā)送響應報文
  243.         
  244.                         Modbus_ClearBuff();                //清空接收數(shù)據(jù)緩沖區(qū)和發(fā)送數(shù)據(jù)緩沖區(qū)
  245.                 }
  246.                
  247.                 else
  248.                 {
  249.                         Modbus_ErrorHandling(0x03);                //非法數(shù)據(jù)值
  250.                 }
  251.         }
  252.         
  253.         else
  254.         {
  255.                 Modbus_ErrorHandling(0x02);                        //非法數(shù)據(jù)地址
  256.         }
  257.         
  258. }

  259. //----------------------------------------------------------------------------//
  260. //函數(shù)功能:功能碼0x06,寫單個寄存器
  261. //入口參數(shù):無
  262. //出口參數(shù):無
  263. //最后修改:2015.12.6
  264. //備注:
  265. //----------------------------------------------------------------------------//
  266. void Modbus_WriteSingleReg_Process(void)
  267. {
  268.         uint8_t Send_Cnt;                        //發(fā)送字節(jié)數(shù)量
  269.         uint16_t Address_Reg;                //要寫入的寄存器地址
  270.         uint16_t Value_Reg;                        //要寫入的寄存器值
  271.         uint16_t CRC_Cal;                        //CRC校驗碼
  272.         
  273.         Address_Reg = Modbus_Rcv_Buff[2] << 8 | Modbus_Rcv_Buff[3];                //從接收數(shù)據(jù)緩沖區(qū)得到要寫入的寄存器地址
  274.         Value_Reg = Modbus_Rcv_Buff[4] << 8 | Modbus_Rcv_Buff[5];                //從接收數(shù)據(jù)緩沖區(qū)得到要寫入的寄存器值
  275.         
  276.         if(Address_Reg < 100)                //寄存器起始地址在正確范圍內(nèi)
  277.         {
  278.                 Send_Cnt = 6 + 2;                //計算發(fā)送字節(jié)數(shù)量
  279.                
  280.                 HoldingReg[Address_Reg] = Value_Reg;                //將要寫入的寄存器值寫入寄存器
  281.                
  282.                 Modbus_Send_Buff[0] = Slave_Address;                                                                        //從站地址
  283.                 Modbus_Send_Buff[1] = Modbus_WriteSingleReg;                                                        //功能碼
  284.                 Modbus_Send_Buff[2] = (uint8_t)(Address_Reg >> 8);                                                //寄存器地址高字節(jié)
  285.                 Modbus_Send_Buff[3] = (uint8_t)(Address_Reg & 0x00FF);                                        //寄存器地址低字節(jié)
  286.                 Modbus_Send_Buff[4] = (uint8_t)(HoldingReg[Address_Reg] >> 8);                        //寄存器值高字節(jié)
  287.                 Modbus_Send_Buff[5] = (uint8_t)(HoldingReg[Address_Reg] & 0x00FF);                //寄存器值低字節(jié)
  288.                
  289.                 CRC_Cal = Modbus_CRC16(Modbus_Send_Buff, 6);                        //計算發(fā)送數(shù)據(jù)的CRC校驗碼
  290.                 Modbus_Send_Buff[6] = (uint8_t)(CRC_Cal >> 8);                        //先是低字節(jié)
  291.                 Modbus_Send_Buff[7] = (uint8_t)(CRC_Cal & 0x00FF);                //后是高字節(jié)
  292.                
  293.                 USART_SendString(USART1, Modbus_Send_Buff, Send_Cnt);        //發(fā)送響應報文
  294.         
  295.                 Modbus_ClearBuff();                //清空接收數(shù)據(jù)緩沖區(qū)和發(fā)送數(shù)據(jù)緩沖區(qū)
  296.         }
  297.         
  298.         else
  299.         {
  300.                 Modbus_ErrorHandling(0x02);                        //非法數(shù)據(jù)地址
  301.         }
  302. }

  303. //----------------------------------------------------------------------------//
  304. //函數(shù)功能:功能碼0x10,寫多個寄存器
  305. //入口參數(shù):無
  306. //出口參數(shù):無
  307. //最后修改:2015.12.9
  308. //備注:
  309. //----------------------------------------------------------------------------//
  310. void Modbus_WriteMultipleReg_Process(void)
  311. {
  312.         uint8_t Send_Cnt;                        //發(fā)送字節(jié)數(shù)量
  313.         uint16_t StartAddress_Reg;        //要寫入的寄存器起始地址
  314.         uint16_t Num_Reg;                        //要寫入的寄存器的數(shù)量
  315.         uint16_t CRC_Cal;                        //CRC校驗碼
  316.         uint16_t i, j;                                //臨時變量
  317.         
  318.         StartAddress_Reg = Modbus_Rcv_Buff[2] << 8 | Modbus_Rcv_Buff[3];        //從接收數(shù)據(jù)緩沖區(qū)得到要寫入的寄存器起始地址
  319.         Num_Reg = Modbus_Rcv_Buff[4] << 8 | Modbus_Rcv_Buff[5];                                //從接收數(shù)據(jù)緩沖區(qū)得到要寫入的寄存器數(shù)量
  320.         
  321.         if(StartAddress_Reg < 100)                        //寄存器起始地址在正確范圍內(nèi)
  322.         {
  323.                 if(StartAddress_Reg + Num_Reg < 100 && Num_Reg > 0)                                //起始地址+寄存器數(shù)量位于正確范圍內(nèi) 并且 寄存器數(shù)量正確                        
  324.                 {
  325.                         for(i = StartAddress_Reg, j = 7; i < StartAddress_Reg + Num_Reg; i++, j += 2)        //將要寫入的寄存器值寫入寄存器
  326.                         {
  327.                                 HoldingReg[i] = Modbus_Rcv_Buff[j] << 8 | Modbus_Rcv_Buff[j + 1];
  328.                         }
  329.                         
  330.                         Send_Cnt = 6 + 2;
  331.                         
  332.                         Modbus_Send_Buff[0] = Slave_Address;                                                //從站地址
  333.                         Modbus_Send_Buff[1] = Modbus_WriteMultipleReg;                                //功能碼
  334.                         Modbus_Send_Buff[2] = (uint8_t)(StartAddress_Reg >> 8);                //寄存器起始地址高字節(jié)
  335.                         Modbus_Send_Buff[3] = (uint8_t)(StartAddress_Reg & 0x00FF);        //寄存器起始地址低字節(jié)
  336.                         Modbus_Send_Buff[4] = (uint8_t)(Num_Reg >> 8);                                //寄存器數(shù)量高字節(jié)
  337.                         Modbus_Send_Buff[5] = (uint8_t)(Num_Reg & 0x00FF);                        //寄存器數(shù)量低字節(jié)
  338.                         
  339.                         CRC_Cal = Modbus_CRC16(Modbus_Send_Buff, 6);                        //計算發(fā)送數(shù)據(jù)的CRC校驗碼
  340.                         Modbus_Send_Buff[6] = (uint8_t)(CRC_Cal >> 8);                        //先是低字節(jié)
  341.                         Modbus_Send_Buff[7] = (uint8_t)(CRC_Cal & 0x00FF);                //后是高字節(jié)
  342.                         
  343.                         USART_SendString(USART1, Modbus_Send_Buff, Send_Cnt);        //發(fā)送響應報文
  344.         
  345.                         Modbus_ClearBuff();                //清空接收數(shù)據(jù)緩沖區(qū)和發(fā)送數(shù)據(jù)緩沖區(qū)
  346.                 }
  347.                
  348.                 else
  349.                 {
  350.                         Modbus_ErrorHandling(0x03);
  351.                 }
  352.         }
  353.         
  354.         else
  355.         {
  356.                 Modbus_ErrorHandling(0x02);
  357.         }
  358. }

  359. //----------------------------------------------------------------------------//
  360. //函數(shù)功能:錯誤處理
  361. //入口參數(shù):ErrorType是錯誤類型
  362. //出口參數(shù):無
  363. //最后修改:2015.12.11
  364. //備注:
  365. //----------------------------------------------------------------------------//
  366. void Modbus_ErrorHandling(uint8_t ErrorType)
  367. {
  368.         uint16_t CRC_Cal;                        //CRC校驗碼
  369.         
  370.         switch(ErrorType)                        //用switch分支語句來確定Modbus異常碼
  371.         {
  372.         case 0x01:                                        //非法功能碼
  373.                 Modbus_Send_Buff[0] = Slave_Address;                                        //從站地址
  374.                 Modbus_Send_Buff[1] = Modbus_Rcv_Buff[1] + 0x80;                //異常功能碼
  375.                 Modbus_Send_Buff[2] = 0x01;                                                                //異常碼
  376.                 CRC_Cal = Modbus_CRC16(Modbus_Send_Buff, 3);                        //計算發(fā)送數(shù)據(jù)的CRC校驗碼
  377.                 Modbus_Send_Buff[3] = (uint8_t)(CRC_Cal >> 8);                        //先是低字節(jié)
  378.                 Modbus_Send_Buff[4] = (uint8_t)(CRC_Cal & 0x00FF);                //后是高字節(jié)
  379.                
  380.                 USART_SendString(USART1, Modbus_Send_Buff, 5);                        //發(fā)送異常響應報文
  381.                 break;
  382.                
  383.         case 0x02:                                        //非法數(shù)據(jù)地址
  384.                 Modbus_Send_Buff[0] = Slave_Address;                                        //從站地址
  385.                 Modbus_Send_Buff[1] = Modbus_Rcv_Buff[1] + 0x80;                //異常功能碼
  386.                 Modbus_Send_Buff[2] = 0x02;                                                                //異常碼
  387.                 CRC_Cal = Modbus_CRC16(Modbus_Send_Buff, 3);                        //計算發(fā)送數(shù)據(jù)的CRC校驗碼
  388.                 Modbus_Send_Buff[3] = (uint8_t)(CRC_Cal >> 8);                        //先是低字節(jié)
  389.                 Modbus_Send_Buff[4] = (uint8_t)(CRC_Cal & 0x00FF);                //后是高字節(jié)
  390.                
  391.                 USART_SendString(USART1, Modbus_Send_Buff, 5);                        //發(fā)送異常響應報文
  392.                 break;
  393.                
  394.         case 0x03:                                        //非法數(shù)據(jù)值
  395.                 Modbus_Send_Buff[0] = Slave_Address;                                        //從站地址
  396.                 Modbus_Send_Buff[1] = Modbus_Rcv_Buff[1] + 0x80;                //異常功能碼
  397.                 Modbus_Send_Buff[2] = 0x03;                                                                //異常碼
  398.                 CRC_Cal = Modbus_CRC16(Modbus_Send_Buff, 3);                        //計算發(fā)送數(shù)據(jù)的CRC校驗碼
  399.                 Modbus_Send_Buff[3] = (uint8_t)(CRC_Cal >> 8);                        //先是低字節(jié)
  400.                 Modbus_Send_Buff[4] = (uint8_t)(CRC_Cal & 0x00FF);                //后是高字節(jié)
  401.                
  402.                 USART_SendString(USART1, Modbus_Send_Buff, 5);                        //發(fā)送異常響應報文
  403.                 break;
  404.                
  405. //        default:
  406. //                return;
  407.                
  408.         }
  409.         
  410.         Modbus_ClearBuff();                //清空接收數(shù)據(jù)緩沖區(qū)和發(fā)送數(shù)據(jù)緩沖區(qū)
  411. }

  412. //----------------------------------------------------------------------------//
  413. //函數(shù)功能:清空接收數(shù)據(jù)緩沖區(qū)和發(fā)送數(shù)據(jù)緩沖區(qū)
  414. //入口參數(shù):無
  415. //出口參數(shù):無
  416. //最后修改:2015.12.5
  417. //備注:
  418. //----------------------------------------------------------------------------//
  419. void Modbus_ClearBuff(void)
  420. {
  421.         uint16_t i;
  422.         
  423.         for(i = 0; i < Modbus_Max_Rcv_Buff; i++)                //清除接收緩沖區(qū)
  424.         {
  425.                 Modbus_Rcv_Buff[i] = '\0';
  426.         }
  427.         Modbus_Rcv_Cnt = 0;                        //接收字節(jié)計數(shù)清0
  428.         
  429.         for(i = 0; i < Modbus_Max_Send_Buff; i++)                //清除發(fā)送緩沖區(qū)
  430.         {
  431.                 Modbus_Send_Buff[i] = '\0';
  432.         }
  433.         
  434. }

  435. //----------------------------------------------------------------------------//
  436. //函數(shù)功能:把一個字節(jié)的高4位十六進制數(shù)存到另一個字節(jié)的低4位里
  437. //入口參數(shù):一個字節(jié)的數(shù)據(jù)
  438. //出口參數(shù):另一個字節(jié)
  439. //最后修改:2015.11.28
  440. //備注:
  441. //----------------------------------------------------------------------------//
  442. uint8_t High4BitsToOneByte(uint8_t Byte)
  443. {
  444.         uint8_t tempByte;
  445.         
  446.         tempByte = (Byte >> 4) & 0x0F;
  447.         
  448.         return tempByte;
  449. }

  450. //----------------------------------------------------------------------------//
  451. //函數(shù)功能:把一個字節(jié)的低4位十六進制數(shù)存到另一個字節(jié)的低4位里
  452. //入口參數(shù):一個字節(jié)的數(shù)據(jù)
  453. //出口參數(shù):另一個字節(jié)
  454. //最后修改:2015.11.28
  455. //備注:
  456. //----------------------------------------------------------------------------//
  457. uint8_t Low4BitsToOneByte(uint8_t Byte)
  458. {
  459.         uint8_t tempByte;
  460.         
  461.         tempByte = Byte & 0x0F;
  462.         
  463.         return tempByte;
  464. }

  465. //----------------------------------------------------------------------------//
  466. //函數(shù)功能:把低4位16進制數(shù)轉(zhuǎn)換為在OLED字庫上對應的0~9和A~F
  467. //入口參數(shù):HexByte是低4位16進制數(shù)
  468. //出口參數(shù):OLED字庫上對應的0~9和A~F
  469. //最后修改:2015.11.28
  470. //備注:
  471. //----------------------------------------------------------------------------//
  472. uint8_t HexToOLEDAsc(uint8_t HexByte)
  473. {
  474.         if((HexByte >= 0x00) && (HexByte <= 0x09))                        //數(shù)字0~9
  475.         {
  476.                 HexByte += 0x30;
  477.         }
  478.         else if((HexByte >= 0x0A) && (HexByte <= 0x0F))        //數(shù)字A~F
  479.         {
  480.                 HexByte += 0x37;
  481.         }
  482.         else
  483.         {
  484.                 HexByte = 0xff;
  485.         }
  486.         
  487.         return HexByte;
  488. }
復制代碼
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏10 分享淘帖 頂1 踩
回復

使用道具 舉報

沙發(fā)
ID:20154 發(fā)表于 2018-7-7 10:53 | 只看該作者
謝謝樓主分享
回復

使用道具 舉報

板凳
ID:389253 發(fā)表于 2018-8-23 13:59 | 只看該作者
多謝樓主分享
回復

使用道具 舉報

地板
ID:245836 發(fā)表于 2018-12-6 14:23 | 只看該作者

多謝樓主分享
回復

使用道具 舉報

5#
ID:448641 發(fā)表于 2019-3-21 22:53 | 只看該作者
謝謝樓主分享
回復

使用道具 舉報

6#
ID:87734 發(fā)表于 2019-4-24 23:33 | 只看該作者
樓豬肯定辛苦了,謝謝
回復

使用道具 舉報

7#
ID:42131 發(fā)表于 2020-1-4 16:13 | 只看該作者
學習了   收下代碼了
回復

使用道具 舉報

8#
ID:699438 發(fā)表于 2020-2-28 10:07 | 只看該作者
代碼很棒,謝謝分享
回復

使用道具 舉報

9#
ID:165291 發(fā)表于 2022-6-22 10:38 | 只看該作者
沒有工程下載嗎?
回復

使用道具 舉報

10#
ID:74687 發(fā)表于 2023-5-25 18:47 | 只看該作者
樓主有完整代碼嗎?
回復

使用道具 舉報

11#
ID:74687 發(fā)表于 2023-5-26 11:38 | 只看該作者
感謝樓主,使我理解了清理緩沖區(qū),現(xiàn)在大部分代碼跑不了,不少原因就是沒有清理緩沖區(qū)。
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復 返回頂部 返回列表