stm32編寫Modbus步驟


1. modbus協議簡介:

  modbus協議基於rs485總線,采取一主多從的形式,主設備輪詢各從設備信息,從設備不主動上報。

日常使用都是RTU模式,協議幀格式如下所示:

  地址   功能碼     寄存器地址       讀取寄存器個數        寄存器數據1   .....       CrcL   CrcH

/*
AA      03     00     00        00     0A     DC     16 
addr   cmd    regH    regL     lenH  lenL    crcL    crcH     主機發送
AA    03    14 00 00 00 00 00 00 00 00 00 03 00 01 00 00 00 18 00 1C 00 00 81 4B      從機回復
addr  cmd   datelen ....

AA      10    00     0a      00 01      02         00 02       主機修改從機寄存器值
addr   cmd   regH   regL    regNum     datalen     data
*/

   功能碼及對應的操作字長:

 

 

 

 

 

目前比較簡單的實現了讀多個保持寄存器,以及寫多個保持寄存器,由於不是使用的PLC,所以寄存器地址的划分沒有嚴格按照上表,具體地址后面解釋。

 

2.Modbus協議編寫步驟:很多設備廠家都會有自己的modbus協議,大多數都不是很標准

   (1)分析板子的具體信息,編寫不同的設備結構體,比如只讀的結構體,可讀寫的結構體,保存配置信息的結構體(當主機發送改變配置信息的消息幀時,會改變相應的變量,並寫入flash)

   (2) modbus寄存器映射,定義保持寄存器的指針;

   (2)本此編寫采用輪詢處理485串口接受到的數據,每次的間隔肯定大於3.5個字符時間(標准的Modbus幀間隔),所以不用但心接受不完整的情況。串口接收完成之后

會首先進行處理在串口數據中找出符合要求,接收正確的數據幀,並記錄其功能碼,輸出幀的真實地址,就可以得到主機想要操作的從機的寄存器地址。

   (3)根據上一步獲取的從機寄存器地址,對保持寄存器的指針進行偏移指向,即指向不同信息結構體的首地址,此過程判斷寄存器地址是否溢出。

   (4)根據功能碼,進行解析操作設備,讀寫操作就是將寄存器地址里的值直接操作指針讀取出/寫入。

 

以上過程都會判斷是否錯誤發生,錯誤碼如下所示:

  (1)0x01 功能碼錯誤,或者不存在

  (2)0x02  寄存器地址超出范圍

  (3)0x04 CRC校驗錯誤

錯誤回復幀的格式為:地址碼   功能碼|0x80  錯誤碼  CRCL    CRCH

下面就是本次用到的代碼,包括將配置信息結構體讀寫flash:

 

  1 /*******************************************  Modbus  **********************************************/
  2 
  3 uint16_t *Modbus_HoldReg = NULL;//保持寄存器
  4 TRtuCommand g_tCurRtuCmd;
  5 
  6 /*
  7 AA      03     00     00        00     0A     DC     16 
  8 addr   cmd    regH    regL     lenH  lenL    crcL    crcH      讀寄存器值
  9 
 10 AA    03    14 00 00 00 00 00 00 00 00 00 03 00 01 00 00 00 18 00 1C 00 00 81 4B 
 11 addr  cmd   datelen ....
 12 
 13 AA      10    00     0a      00 01      02         00 02        寫寄存器值
 14 addr   cmd   regH   regL    regNum     datalen     data
 15 */
 16 
 17 
 18 
 19 /*====================================================================
 20   函數名:Modbus_RegMap
 21   功  能:根據讀取寄存器的起始地址選擇映射對象,將不同的地址映射到
 22                     不同的結構體數據
 23   輸入參數說明:
 24   輸出參數說明:
 25   返回值說明:無
 26     備 注: 
 27  ====================================================================*/
 28 void Modbus_RegMap(uint16_t wStartAddr)
 29 {
 30     uint16_t woffset = 0;
 31     uint16_t wTemp = 0;
 32     
 33     if((wStartAddr >= REG_BASE_INFO_OFFSET) && (wStartAddr < (REG_BASE_INFO_OFFSET + REG_BASE_INFO_NUM)))
 34     {
 35             Modbus_HoldReg  = (uint16_t *)&g_tdeviceinfo;
 36           woffset = wStartAddr - REG_BASE_INFO_OFFSET;
 37             wTemp = REG_BASE_INFO_NUM;
 38     }
 39     else if(wStartAddr >= (REG_BASE_INFO_OFFSET + REG_BASE_INFO_NUM)  && (wStartAddr < REG_CONFIG_INFO_OFFSET) )
 40     {
 41           g_tCurRtuCmd.m_byExceptionCode = 0x02;   //異常碼0x02超出寄存器范圍
 42     }
 43     else if((wStartAddr >= REG_CONFIG_INFO_OFFSET) && (wStartAddr < (REG_CONFIG_INFO_OFFSET + REG_CONFIG_INFO_NUM )))
 44     {
 45             Modbus_HoldReg  = (uint16_t *)&g_tConfigInfo;
 46           woffset = wStartAddr - REG_CONFIG_INFO_OFFSET;
 47           wTemp = REG_CONFIG_INFO_NUM;
 48     }
 49     else if(wStartAddr >= (REG_CONFIG_INFO_OFFSET + REG_CONFIG_INFO_NUM))
 50     {
 51             g_tCurRtuCmd.m_byExceptionCode = 0x02;   //異常碼0x02超出寄存器范圍
 52     }
 53     g_tCurRtuCmd.m_wStartAddr = woffset;
 54     g_tCurRtuCmd.m_wRegOffsetNum = wTemp;
 55 }
 56 
 57 
 58 /*====================================================================
 59   函數名:DeviceInfoRefresh
 60   功  能:更新設備運行的狀態值同時更新modbus寄存器的值
 61   輸入參數說明:
 62   輸出參數說明:
 63   返回值說明:無
 64     備 注: 
 65  ====================================================================*/
 66 void DeviceInfoRefresh(void)
 67 {
 68 
 69         GetHumiAndTempVlue();
 70     
 71         g_tdeviceinfo.m_wlightStripRly = HAL_GPIO_ReadPin(DOOR_LED_RELAY_GPIO_Port,DOOR_LED_RELAY_Pin);
 72         g_tdeviceinfo.m_wFanRly        = HAL_GPIO_ReadPin(FAN_RELAY_GPIO_Port,FAN_RELAY_Pin);
 73         g_tdeviceinfo.m_wWarningLed1   = HAL_GPIO_ReadPin(WARNING_LED_1_GPIO_Port,WARNING_LED_1_Pin);
 74         g_tdeviceinfo.m_wWarningLed2   = HAL_GPIO_ReadPin(WARNING_LED_2_GPIO_Port,WARNING_LED_2_Pin);
 75     
 76         g_tdeviceinfo.m_wGMvalue       = LightLevelPersenGet();   /* 光照等級 */
 77         g_tdeviceinfo.m_wDoorLimit     = HAL_GPIO_ReadPin(LIMIT_SW_DOOR_GPIO_Port,LIMIT_SW_DOOR_Pin);
 78         g_tdeviceinfo.m_wWaterLimit    = HAL_GPIO_ReadPin(WATER_MARK_GPIO_Port,WATER_MARK_Pin);
 79         g_tdeviceinfo.m_Temp                 = (uint16_t)s_tsht2xInfo.m_fTemp;
 80         g_tdeviceinfo.m_Humi                     = (uint16_t)s_tsht2xInfo.m_fHumi;
 81         g_tdeviceinfo.m_vibration          =  Mma8452StatusGet();
 82 }
 83 
 84 
 85 /*====================================================================
 86   函數名:RtuReceiveHandle
 87   功  能:處理接受到的modbus數據,並讀取/設置相應寄存器的值
 88   輸入參數說明:
 89     pbydata :串口接收到的數據
 90   輸出參數說明:
 91     dwLength :輸入數據長度
 92   返回值說明:無
 93     備注:由於modubusRtu函數不支持功能碼0x06(寫單一寄存器),所以0x06不處理
 94  ====================================================================*/
 95 void RtuReceiveHandle(uint8_t *pbydata,uint32_t dwLength)
 96 {        
 97         uint8_t i;
 98         uint16_t wCrc = 0;
 99         uint16_t wIndex = 0, wRealLength = 0, wStartOff = 0;
100         uint8_t byAddr = (g_tConfigInfo.m_bydeviceAddr) & 0xFF;
101         g_tCurRtuCmd.m_byExceptionCode = 0;
102     
103         if(pbydata == NULL || dwLength == 0)
104         {
105             TCLX_PLATFORM_DIAG(("No data received\n"));
106             return;
107         }
108             
109         for(wIndex = 0; wIndex < dwLength; wIndex++)
110         {
111             if(modubusRtu(pbydata + wIndex, dwLength - wIndex, &byAddr, 1, &wRealLength, &(g_tCurRtuCmd.m_byFunCode), &wStartOff))
112             {
113                 wStartOff += wIndex;          /* 找到真實的Modbus數據幀 */
114             
115                 /* 記錄命令,在主循環處理 */
116                 g_tCurRtuCmd.m_wStartAddr = (pbydata[wStartOff + 2] << 8) + pbydata[wStartOff + 3];
117                 
118                 Modbus_RegMap(g_tCurRtuCmd.m_wStartAddr); 
119                 
120                 TCLX_PLATFORM_DIAG(("Offset[%d] Len[%d] FunCode[0x%x] StartAddr[0x%x] RegNum[%d]\n", wStartOff, wRealLength,g_tCurRtuCmd.m_byFunCode, g_tCurRtuCmd.m_wStartAddr, g_tCurRtuCmd.m_wRegNum));
121                 
122                 switch(g_tCurRtuCmd.m_byFunCode)
123                 {
124                     case 0x03:
125                             g_tCurRtuCmd.m_wRegNum = (pbydata[wStartOff + 4] << 8) + pbydata[wStartOff + 5];
126                             if((g_tCurRtuCmd.m_wRegNum + g_tCurRtuCmd.m_wStartAddr) <= g_tCurRtuCmd.m_wRegOffsetNum)
127                             {
128                                 abySendData[0] = g_tConfigInfo.m_bydeviceAddr;
129                                 abySendData[1] = g_tCurRtuCmd.m_byFunCode;
130                                 abySendData[2] = g_tCurRtuCmd.m_wRegNum * 2;
131                                  for(i = 0; i < g_tCurRtuCmd.m_wRegNum; i++)
132                                  {
133                                                 abySendData[3+i*2] = (Modbus_HoldReg[g_tCurRtuCmd.m_wStartAddr+i]>>8)&0xFF;//           /////////先發送高字節--在發送低字節
134                                                 abySendData[4+i*2] = (Modbus_HoldReg[g_tCurRtuCmd.m_wStartAddr+i])&0xFF; //
135                                  }
136                                 wCrc = crc16(abySendData, g_tCurRtuCmd.m_wRegNum*2 + 3);
137                                 abySendData[g_tCurRtuCmd.m_wRegNum*2 + 3] = wCrc & 0x00FF;
138                                 abySendData[g_tCurRtuCmd.m_wRegNum*2 + 4] = (wCrc >> 8) & 0x00FF;
139                              
140                                 usart_send(USART_485_INDEX, abySendData, g_tCurRtuCmd.m_wRegNum*2 + 5);
141                             }
142                             else
143                             {
144                                          g_tCurRtuCmd.m_byExceptionCode = 0x02;   //異常碼,超出寄存范圍
145                             }
146                         break;
147                     case 0x06:
148                             
149                             Modbus_HoldReg[g_tCurRtuCmd.m_wStartAddr]  = pbydata[wStartOff + 4]<<8  | ((uint16_t)pbydata[wStartOff + 5]);//高字節在前               
150                             
151                             abySendData[0] = pbydata[wStartOff];
152                             abySendData[1] = pbydata[wStartOff + 1];
153                             abySendData[2] = pbydata[wStartOff + 2];
154                             abySendData[3] = pbydata[wStartOff + 3];
155                             abySendData[4] = pbydata[wStartOff + 4];
156                             abySendData[5] = pbydata[wStartOff + 5];
157                             
158                             wCrc = crc16(abySendData,6);
159 
160                             abySendData[6]=(wCrc>>8)&0xFF;
161                             abySendData[7]=(wCrc)&0xFF;
162                             usart_send(USART_485_INDEX, abySendData,8);
163                         break;
164                     
165                     case 0x10:
166                             g_tCurRtuCmd.m_wRegNum = (pbydata[wStartOff + 4] << 8) + pbydata[wStartOff + 5];
167                             if((g_tCurRtuCmd.m_wRegNum + g_tCurRtuCmd.m_wStartAddr) <= g_tCurRtuCmd.m_wRegOffsetNum)
168                             {
169                                     for(i=0;i<g_tCurRtuCmd.m_wRegNum ;i++)
170                                     {
171                                                     Modbus_HoldReg[g_tCurRtuCmd.m_wStartAddr+i]=   pbydata[wStartOff + 7+i*2] <<8 ; //低字節在前               
172                                                     Modbus_HoldReg[g_tCurRtuCmd.m_wStartAddr+i]|=((uint16_t)pbydata[wStartOff + 8+i*2]); //高字節在后
173                                     }
174                                     abySendData[0] = pbydata[wStartOff];
175                                     abySendData[1] = pbydata[wStartOff + 1];
176                                     abySendData[2] = pbydata[wStartOff + 2];
177                                     abySendData[3] = pbydata[wStartOff + 3];
178                                     abySendData[4] = pbydata[wStartOff + 4];
179                                     abySendData[5] = pbydata[wStartOff + 5];
180                             
181                                     wCrc = crc16(abySendData,6);
182                                     abySendData[6]=(wCrc>>8)&0xFF;
183                                     abySendData[7]=(wCrc)&0xFF;
184                             
185                                     /* 如果配置信息發生改變就寫入flash,不用做比較相等處理,寫flash函數已經處理 */
186                                     writeConfigInfoToFlash(CONFIG_DATA_FLASH_ADDR,&g_tConfigInfo);
187                                                         
188                                     
189                                     usart_send(USART_485_INDEX, abySendData,8);
190                             }
191                             else
192                             {
193                                     g_tCurRtuCmd.m_byExceptionCode = 0x02;    //異常碼,超出寄存范圍
194                             }
195                         break;
196                     default:
197                                  g_tCurRtuCmd.m_byExceptionCode = 0x01;     //異常碼,功能碼錯誤或者不存在 
198                         break;
199                 }
200         
201         if(g_tCurRtuCmd.m_byExceptionCode != 0)
202         {
203             TCLX_PLATFORM_DIAG(("exception code[%d]\n",  g_tCurRtuCmd.m_byExceptionCode));
204             abySendData[0] = g_tConfigInfo.m_bydeviceAddr;
205             abySendData[1] = g_tCurRtuCmd.m_byFunCode + 0x80;
206             abySendData[2] = g_tCurRtuCmd.m_byExceptionCode;
207             wCrc = crc16(abySendData, 3);
208             abySendData[3] = wCrc & 0x00FF;
209             abySendData[4] = (wCrc >> 8) & 0x00FF;
210             usart_send(USART_485_INDEX, abySendData, 5);
211         }
212     
213       memset(&g_tCurRtuCmd, 0, sizeof(TRtuCommand));
214         
215       wIndex += (wStartOff + wRealLength - 1);
216      }/* switch(g_tCurRtuCmd.m_byFunCode) */
217 
218   }/* if modbusRtu do.... */
219         usartRcvRestore(USART_485_INDEX);
220 }
221 
222 
223 /************************************** flash opration *****************************************/
224 
225 
226 /*====================================================================
227   函數名:Read_FlashData
228   功  能:從flash讀取配置信息
229   輸入參數說明:
230 FlashReadBaseAdd:配置信息基地址
231   輸出參數說明:
232 DeviceCfg      :配置參數
233   返回值說明:無
234     備 注: 
235  ====================================================================*/
236 void Read_FlashData(uint32_t FlashReadBaseAdd,DeviceConfigInfo_t *DeviceCfg)
237 {
238     if(NULL == DeviceCfg)
239     {
240         return;
241     }
242     __IO DeviceConfigInfo_t *ptPos = (__IO DeviceConfigInfo_t*)FlashReadBaseAdd;
243     
244     memcpy(DeviceCfg,(const char *)ptPos,sizeof(DeviceConfigInfo_t));
245 }
246 
247 /*====================================================================
248   函數名:writeConfigInfoToFlash
249   功  能:向flash寫配置信息
250   輸入參數說明:
251 FlashReadBaseAdd:配置信息基地址
252   輸出參數說明:
253 DeviceCfg      :配置參數
254   返回值說明:無
255     備 注: 
256  ====================================================================*/
257 void writeConfigInfoToFlash(uint32_t FlashWriteBaseAdd,DeviceConfigInfo_t *DeviceCfg)
258 {
259       uint8_t  byIndex = 0;
260     uint16_t wIndex = 0;
261    
262     DeviceConfigInfo_t DeviceCfgTemp = {0};
263     
264     for(byIndex = 0;byIndex < 10;byIndex++)
265     {
266         Read_FlashData(FlashWriteBaseAdd,&DeviceCfgTemp);
267         
268         if(0 == memcmp(&DeviceCfg,&DeviceCfgTemp,sizeof(DeviceConfigInfo_t)))
269         {
270             TCLX_PLATFORM_DIAG(("write succeed: Data equal\r\n"));
271             return;   
272         }
273         else
274         {
275             HAL_Delay(500);
276             DIS_INT;
277             HAL_StatusTypeDef status = HAL_OK;
278             if(HAL_OK != (status = HAL_FLASH_Unlock()))
279             {
280                 TCLX_PLATFORM_DIAG((" falsh unlock err\r\n"));
281                 continue;
282             }
283             FLASH_EraseInitTypeDef f;
284             f.TypeErase = FLASH_TYPEERASE_PAGES;
285             f.PageAddress = (uint32_t)FlashWriteBaseAdd;
286             f.NbPages = 1;
287             uint32_t PageError = 0;
288             
289             if(HAL_OK != (status = HAL_FLASHEx_Erase(&f, &PageError)))
290             {
291                 if(0 != PageError)
292                 {
293                     TCLX_PLATFORM_DIAG(("HAL_FLASHEx_Erase:failed(%d-%d)\n",status,PageError));
294                     HAL_FLASH_Lock();
295                     continue;
296                 }
297             }
298             for(wIndex = 0; wIndex < (sizeof(DeviceConfigInfo_t) / sizeof(uint32_t)); wIndex ++)
299             {
300                 if(HAL_OK != (status = HAL_FLASH_Program(TYPEPROGRAM_WORD,FlashWriteBaseAdd + (wIndex * sizeof(uint32_t)) ,((uint32_t *)DeviceCfg)[wIndex])))
301                 {
302                     TCLX_PLATFORM_DIAG(("HAL_FLASH_Program:CONFIG_DATA_FLASH_ADDR failed(%d)\n",status));
303                     HAL_FLASH_Lock();
304                     continue;
305                 }
306             
307             }    
308             if(HAL_OK != (status = HAL_FLASH_Lock()))
309             {
310                 TCLX_PLATFORM_DIAG(("HAL_FLASH_Lock:HAL_FLASH_Lock(%d)\n",status));
311             }
312             EN_INT;
313             return ;
314         }
315     }
316 }

 

 

參考下面例程,此例程比較詳細

  1 #include "modbus.h"
  2 #include "led.h"
  3 #include "lcd.h"
  4 #include "stm32f10x_tim.h"
  5 
  6 
  7 ///////////////////////////////////////////////////////////
  8 u32 RS485_Baudrate=9600;//通訊波特率
  9 u8 RS485_Parity=0;//0無校驗;1奇校驗;2偶校驗
 10 u8 RS485_Addr=1;//從機地址
 11 u16 RS485_Frame_Distance=4;//數據幀最小間隔(ms),超過此時間則認為是下一幀
 12 
 13 u8 RS485_RX_BUFF[2048];//接收緩沖區2048字節
 14 u16 RS485_RX_CNT=0;//接收計數器
 15 u8 RS485_FrameFlag=0;//幀結束標記
 16 u8 RS485_TX_BUFF[2048];//發送緩沖區
 17 u16 RS485_TX_CNT=0;//發送計數器
 18 
 19 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
 20 //Modbus寄存器和單片機寄存器的映射關系
 21 vu32 *Modbus_InputIO[100];//輸入開關量寄存器指針(這里使用的是位帶操作)
 22 vu32 *Modbus_OutputIO[100];//輸出開關量寄存器指針(這里使用的是位帶操作)
 23 u16 *Modbus_HoldReg[1000];//保持寄存器指針
 24 u32 testData1=1201,testData2=1002,testData3=2303,testData4=8204;
 25 void Modbus_RegMap(void)
 26 {
 27         
 28       
 29          //輸入開關量寄存器指針指向
 30         Modbus_InputIO[0]=(vu32*)&PEin(4);//KEY0     //&PEin(4):取PE4的地址,(vu32*)&PEin(4)將PE4地址強制轉換為uw32類型的地址,Modbus_InputIO[0]=(vu32*)&PEin(4); 將轉換好的地址送給地址指針Modbus_InputIO[0];
 31         Modbus_InputIO[1]=(vu32*)&PEin(3);//KEY1     //*Modbus_InputIO[0] 取出地址中的內容。
 32         Modbus_InputIO[2]=(vu32*)&PEin(2);//KEY2
 33         Modbus_InputIO[3]=(vu32*)&PAin(0);//KEY3
 34         
 35         //輸出開關量寄存器指針指向
 36         Modbus_OutputIO[0]=(vu32*)&PBout(5);//LED0
 37         Modbus_OutputIO[1]=(vu32*)&PEout(5);//LED1
 38         
 39         //保持寄存器指針指向
 40         Modbus_HoldReg[0]=(u16*)&testData1;//測試數據1 
 41         Modbus_HoldReg[1]=(u16*)&testData2;//((u16*)&testData1)+1;//測試數據1 
 42         Modbus_HoldReg[2]=(u16*)&testData3;//(u16*)&testData2;//測試數據2
 43         Modbus_HoldReg[3]=(u16*)&testData4;//((u16*)&testData2)+1;//測試數據2 
 44         Modbus_HoldReg[4]=(u16*)&testData1;
 45         Modbus_HoldReg[5]=(u16*)&testData2;
 46         Modbus_HoldReg[6]=(u16*)&testData3;
 47 }
 48 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 49 
 50 //CRC校驗 自己后面添加的
 51 
 52 const u8 auchCRCHi[] = { 
 53 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
 54 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 
 55 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 
 56 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
 57 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 
 58 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 
 59 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 
 60 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 
 61 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
 62 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
 63 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 
 64 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
 65 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40} ; 
 66 
 67 
 68 const u8 auchCRCLo[] = { 
 69 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 
 70 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 
 71 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 
 72 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 
 73 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 
 74 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 
 75 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 
 76 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 
 77 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 
 78 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 
 79 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 
 80 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 
 81 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,0x43, 0x83, 0x41, 0x81, 0x80, 0x40} ;
 82 
 83 
 84 u16 CRC_Compute(u8 *puchMsg, u16 usDataLen) 
 85 { 
 86     u8 uchCRCHi = 0xFF ; 
 87     u8 uchCRCLo = 0xFF ; 
 88     u32 uIndex ; 
 89     while (usDataLen--) 
 90     { 
 91         uIndex = uchCRCHi ^ *puchMsg++ ; 
 92         uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ; 
 93         uchCRCLo = auchCRCLo[uIndex] ; 
 94     } 
 95     return ((uchCRCHi<< 8)  | (uchCRCLo)) ; 
 96 }//uint16 crc16(uint8 *puchMsg, uint16 usDataLen)
 97 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 98 
 99 //初始化USART2
100 void RS485_Init(void)
101 {
102         GPIO_InitTypeDef GPIO_InitStructure;
103         USART_InitTypeDef USART_InitStructure;
104         NVIC_InitTypeDef NVIC_InitStructure;
105         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD,ENABLE);
106         RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
107         
108         GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2;//PA2(TX)復用推挽輸出
109         GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
110         GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
111         GPIO_Init(GPIOA,&GPIO_InitStructure);
112         GPIO_SetBits(GPIOA,GPIO_Pin_2);//默認高電平
113         
114         GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3;//PA3(RX)輸入上拉
115         GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;   //修改原GPIO_Mode_IPU(輸入上拉)->GPIO_Mode_IN_FLOATING(浮空輸入)/////////////////////////////////////////////
116         GPIO_Init(GPIOA,&GPIO_InitStructure);
117         
118         GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//修改PG9(RE/DE)通用推挽輸出->PD7(RE/DE)通用推挽輸出//////////////////////////////////////////////////////////////////////
119         GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
120         GPIO_Init(GPIOG,&GPIO_InitStructure);
121         GPIO_ResetBits(GPIOG,GPIO_Pin_9);//默認接收狀態
122         
123         USART_DeInit(USART2);//復位串口2
124         USART_InitStructure.USART_BaudRate=RS485_Baudrate;
125         USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
126         USART_InitStructure.USART_WordLength=USART_WordLength_8b;
127         USART_InitStructure.USART_StopBits=USART_StopBits_1;
128         USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;//收發模式
129         switch(RS485_Parity)
130         {
131                 case 0:USART_InitStructure.USART_Parity=USART_Parity_No;break;//無校驗
132                 case 1:USART_InitStructure.USART_Parity=USART_Parity_Odd;break;//奇校驗
133                 case 2:USART_InitStructure.USART_Parity=USART_Parity_Even;break;//偶校驗
134         }
135         USART_Init(USART2,&USART_InitStructure);
136         
137         USART_ClearITPendingBit(USART2,USART_IT_RXNE);
138         USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);//使能串口2接收中斷
139         
140         NVIC_InitStructure.NVIC_IRQChannel=USART2_IRQn;
141         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
142         NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;
143         NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
144         NVIC_Init(&NVIC_InitStructure);
145         
146         USART_Cmd(USART2,ENABLE);//使能串口2
147         RS485_TX_EN=0;//默認為接收模式
148         
149         Timer7_Init();//定時器7初始化,用於監視空閑時間
150         Modbus_RegMap();//Modbus寄存器映射
151 }
152 
153 //定時器7初始化
154 void Timer7_Init(void)
155 {
156         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
157         NVIC_InitTypeDef NVIC_InitStructure;
158 
159         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE); //TIM7時鍾使能 
160 
161         //TIM7初始化設置
162         TIM_TimeBaseStructure.TIM_Period = RS485_Frame_Distance*10; //設置在下一個更新事件裝入活動的自動重裝載寄存器周期的值
163         TIM_TimeBaseStructure.TIM_Prescaler =7200; //設置用來作為TIMx時鍾頻率除數的預分頻值 設置計數頻率為10kHz
164         TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設置時鍾分割:TDTS = Tck_tim
165         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上計數模式
166         TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure); //根據TIM_TimeBaseInitStruct中指定的參數初始化TIMx的時間基數單位
167 
168         TIM_ITConfig( TIM7, TIM_IT_Update, ENABLE );//TIM7 允許更新中斷
169 
170         //TIM7中斷分組配置
171         NVIC_InitStructure.NVIC_IRQChannel =TIM7_IRQn;  //TIM7中斷
172         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;  //先占優先級2級
173         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //從優先級3級
174         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
175         NVIC_Init(&NVIC_InitStructure);  //根據NVIC_InitStruct中指定的參數初始化外設NVIC寄存器                                                                  
176 }
177 
178 
179 
180 //////////////////////////////////////////////////////////////////////////////
181 //發送n個字節數據
182 //buff:發送區首地址
183 //len:發送的字節數
184 void RS485_SendData(u8 *buff,u8 len)
185 { 
186         RS485_TX_EN=1;//切換為發送模式
187         while(len--)
188         {
189                 while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);//等待發送區為空
190                 USART_SendData(USART2,*(buff++));
191         }
192         while(USART_GetFlagStatus(USART2,USART_FLAG_TC)==RESET);//等待發送完成
193 }
194 
195 
196 /////////////////////////////////////////////////////////////////////////////////////
197 void USART2_IRQHandler(void)//串口2中斷服務程序
198 {
199        
200         u8 res;
201         u8 err;
202      
203         if(USART_GetITStatus(USART2,USART_IT_RXNE)!=RESET)
204         {
205                 if(USART_GetFlagStatus(USART2,USART_FLAG_NE|USART_FLAG_FE|USART_FLAG_PE)) err=1;//檢測到噪音、幀錯誤或校驗錯誤
206                 else err=0;
207                 LED0=0;
208                 res=USART_ReceiveData(USART2); //讀接收到的字節,同時相關標志自動清除
209                 
210                 if((RS485_RX_CNT<2047)&&(err==0))
211                 {
212                         RS485_RX_BUFF[RS485_RX_CNT]=res;
213                         RS485_RX_CNT++;
214                         
215                         TIM_ClearITPendingBit(TIM7,TIM_IT_Update);//清除定時器溢出中斷
216                         TIM_SetCounter(TIM7,0);//當接收到一個新的字節,將定時器7復位為0,重新計時(相當於喂狗)
217                         TIM_Cmd(TIM7,ENABLE);//開始計時
218                 }
219         }
220 }
221 
222 ///////////////////////////////////////////////////////////////////////////////////////
223 //用定時器7判斷接收空閑時間,當空閑時間大於指定時間,認為一幀結束
224 //定時器7中斷服務程序         
225 void TIM7_IRQHandler(void)
226 {                                                                   
227         if(TIM_GetITStatus(TIM7,TIM_IT_Update)!=RESET)
228         {
229                 TIM_ClearITPendingBit(TIM7,TIM_IT_Update);//清除中斷標志
230                 TIM_Cmd(TIM7,DISABLE);//停止定時器
231                 RS485_TX_EN=1;//停止接收,切換為發送狀態
232                 RS485_FrameFlag=1;//置位幀結束標記
233         }
234 }
235 
236 /////////////////////////////////////////////////////////////////////////////////////
237 //RS485服務程序,用於處理接收到的數據(請在主函數中循環調用)
238 u16 startRegAddr;
239 u16 RegNum;
240 u16 calCRC;
241 void RS485_Service(void)
242 {
243         u16 recCRC;
244         if(RS485_FrameFlag==1)
245         {
246                 if(RS485_RX_BUFF[0]==RS485_Addr)//地址正確
247                 {
248                         if((RS485_RX_BUFF[1]==01)||(RS485_RX_BUFF[1]==02)||(RS485_RX_BUFF[1]==03)||(RS485_RX_BUFF[1]==05)||(RS485_RX_BUFF[1]==06)||(RS485_RX_BUFF[1]==15)||(RS485_RX_BUFF[1]==16))//功能碼正確
249                   {
250                                 startRegAddr=(((u16)RS485_RX_BUFF[2])<<8)|RS485_RX_BUFF[3];//獲取寄存器起始地址
251                                 if(startRegAddr<1000)//寄存器地址在范圍內
252                                 {
253                                         calCRC=CRC_Compute(RS485_RX_BUFF,RS485_RX_CNT-2);//計算所接收數據的CRC
254                                         recCRC=RS485_RX_BUFF[RS485_RX_CNT-1]|(((u16)RS485_RX_BUFF[RS485_RX_CNT-2])<<8);//接收到的CRC(低字節在前,高字節在后)
255                                         if(calCRC==recCRC)//CRC校驗正確
256                                         {
257                                                 ///////////顯示用
258      
259         LCD_ShowxNum(10,230,RS485_RX_BUFF[0],3,16,0X80);//顯示數據
260          LCD_ShowxNum(42,230,RS485_RX_BUFF[1],3,16,0X80);//顯示數據
261         LCD_ShowxNum(74,230,RS485_RX_BUFF[2],3,16,0X80);//顯示數據
262         LCD_ShowxNum(106,230,RS485_RX_BUFF[3],3,16,0X80);//顯示數據
263         LCD_ShowxNum(138,230,RS485_RX_BUFF[4],3,16,0X80);//顯示數據
264         LCD_ShowxNum(170,230,RS485_RX_BUFF[5],3,16,0X80);//顯示數據        
265 ///////////////////////        
266                                                 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
267                                                 switch(RS485_RX_BUFF[1])//根據不同的功能碼進行處理
268                                                 {
269                                                         case 2://讀輸入開關量
270                                                         {
271                                                                 Modbus_02_Solve();
272                                                                 break;
273                                                         }
274                                                         
275                                                         case 1://讀輸出開關量
276                                                         {
277                                                                 Modbus_01_Solve();
278                                                                 break;
279                                                         }
280                                                                 
281                                                         case 5://寫單個輸出開關量
282                                                         {
283                                                                 Modbus_05_Solve();
284                                                                 break;
285                                                         }
286                                                                 
287                                                         case 15://寫多個輸出開關量
288                                                         {
289                                                                 Modbus_15_Solve();
290                                                                 break;
291                                                         }
292                                                                 
293                                                         case 03: //讀多個寄存器
294                                                         {                                                                
295                                                                 Modbus_03_Solve();
296                                                                 break;
297                                                         }
298                                                                 
299                                                         case 06: //寫單個寄存器
300                                                         {
301                                                                 Modbus_06_Solve();
302                                                                 break;
303                                                         }
304                                                                 
305                                                         case 16: //寫多個寄存器
306                                                         {
307                                                                 Modbus_16_Solve();
308                                                                 break;
309                                                         }
310                                                           
311                                                                                                         
312                                                 }
313                                                 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
314                                         }
315                                         else//CRC校驗錯誤
316                                         {
317 
318                                                 RS485_TX_BUFF[0]=RS485_RX_BUFF[0];
319                                                 RS485_TX_BUFF[1]=RS485_RX_BUFF[1]|0x80;
320                                                 RS485_TX_BUFF[2]=0x04; //異常碼
321                                                 RS485_SendData(RS485_TX_BUFF,3);
322                                         }        
323                                 }
324                                 else//寄存器地址超出范圍
325                                 {
326                                         RS485_TX_BUFF[0]=RS485_RX_BUFF[0];
327                                         RS485_TX_BUFF[1]=RS485_RX_BUFF[1]|0x80;
328                                         RS485_TX_BUFF[2]=0x02; //異常碼
329                                         RS485_SendData(RS485_TX_BUFF,3);
330                                 }                                                
331                         }
332                         else//功能碼錯誤
333                         {
334                                 RS485_TX_BUFF[0]=RS485_RX_BUFF[0];
335                                 RS485_TX_BUFF[1]=RS485_RX_BUFF[1]|0x80;
336                                 RS485_TX_BUFF[2]=0x01; //異常碼
337                                 RS485_SendData(RS485_TX_BUFF,3);
338                         }
339           }
340                                 
341                 RS485_FrameFlag=0;//復位幀結束標志
342                 RS485_RX_CNT=0;//接收計數器清零
343                 RS485_TX_EN=0;//開啟接收模式                
344         }                
345 }
346 
347 //Modbus功能碼02處理程序/////////////////////////////////////////////////////程序已驗證OK -----必須先配置PE4 PE3 PE2 PA0 初始化按鍵才可以OK    KEY_Init();
348 //讀輸入開關量
349 void Modbus_02_Solve(void)
350 {
351         u16 ByteNum;
352         u16 i;
353         RegNum= (((u16)RS485_RX_BUFF[4])<<8)|RS485_RX_BUFF[5];//獲取寄存器數量
354         if((startRegAddr+RegNum)<100)//寄存器地址+數量在范圍內
355         {
356                 RS485_TX_BUFF[0]=RS485_RX_BUFF[0];
357                 RS485_TX_BUFF[1]=RS485_RX_BUFF[1];
358                 ByteNum=RegNum/8;//字節數
359                 if(RegNum%8) ByteNum+=1;//如果位數還有余數,則字節數+1
360                 RS485_TX_BUFF[2]=ByteNum;//返回要讀取的字節數
361                 for(i=0;i<RegNum;i++)
362                 {
363                         if(i%8==0) RS485_TX_BUFF[3+i/8]=0x00;
364                         RS485_TX_BUFF[3+i/8]>>=1;//低位先發送
365                         RS485_TX_BUFF[3+i/8]|=((*Modbus_InputIO[startRegAddr+i])<<7)&0x80;
366                         if(i==RegNum-1)//發送到最后一個位了
367                         {
368                                 if(RegNum%8) RS485_TX_BUFF[3+i/8]>>=8-(RegNum%8);//如果最后一個字節還有余數,則剩余MSB填充0
369                         }
370                 }
371                 calCRC=CRC_Compute(RS485_TX_BUFF,ByteNum+3);
372                 RS485_TX_BUFF[ByteNum+3]=(calCRC>>8)&0xFF;
373                 RS485_TX_BUFF[ByteNum+4]=(calCRC)&0xFF;
374                 RS485_SendData(RS485_TX_BUFF,ByteNum+5);
375         }
376         else//寄存器地址+數量超出范圍
377         {
378                 RS485_TX_BUFF[0]=RS485_RX_BUFF[0];
379                 RS485_TX_BUFF[1]=RS485_RX_BUFF[1]|0x80;
380                 RS485_TX_BUFF[2]=0x02; //異常碼
381                 RS485_SendData(RS485_TX_BUFF,3);
382         }
383 }
384 
385 //Modbus功能碼01處理程序 ///////////////////////////////////////////////////////////程序已驗證OK
386 //讀輸出開關量
387 void Modbus_01_Solve(void)
388 {
389         u16 ByteNum;
390         u16 i;
391         RegNum= (((u16)RS485_RX_BUFF[4])<<8)|RS485_RX_BUFF[5];//獲取寄存器數量
392         if((startRegAddr+RegNum)<100)//寄存器地址+數量在范圍內
393         {
394                 RS485_TX_BUFF[0]=RS485_RX_BUFF[0];
395                 RS485_TX_BUFF[1]=RS485_RX_BUFF[1];
396                 ByteNum=RegNum/8;//字節數
397                 if(RegNum%8) ByteNum+=1;//如果位數還有余數,則字節數+1
398                 RS485_TX_BUFF[2]=ByteNum;//返回要讀取的字節數
399                 for(i=0;i<RegNum;i++)
400                 {
401                         if(i%8==0) RS485_TX_BUFF[3+i/8]=0x00;
402                         RS485_TX_BUFF[3+i/8]>>=1;//低位先發送
403                         RS485_TX_BUFF[3+i/8]|=((*Modbus_OutputIO[startRegAddr+i])<<7)&0x80;
404                         if(i==RegNum-1)//發送到最后一個位了
405                         {
406                                 if(RegNum%8) RS485_TX_BUFF[3+i/8]>>=8-(RegNum%8);//如果最后一個字節還有余數,則剩余MSB填充0
407                         }
408                 }
409                 calCRC=CRC_Compute(RS485_TX_BUFF,ByteNum+3);
410                 RS485_TX_BUFF[ByteNum+3]=(calCRC>>8)&0xFF;
411                 RS485_TX_BUFF[ByteNum+4]=(calCRC)&0xFF;
412                 RS485_SendData(RS485_TX_BUFF,ByteNum+5);
413         }
414         else//寄存器地址+數量超出范圍
415         {
416                 RS485_TX_BUFF[0]=RS485_RX_BUFF[0];
417                 RS485_TX_BUFF[1]=RS485_RX_BUFF[1]|0x80;
418                 RS485_TX_BUFF[2]=0x02; //異常碼
419                 RS485_SendData(RS485_TX_BUFF,3);
420         }
421 }
422 
423 //Modbus功能碼05處理程序   ///////////////////////////////////////////////////////程序已驗證OK
424 //寫單個輸出開關量
425 void Modbus_05_Solve(void)
426 {
427         if(startRegAddr<100)//寄存器地址在范圍內
428         {
429                 if((RS485_RX_BUFF[4]==0xFF)||(RS485_RX_BUFF[5]==0xFF)) *Modbus_OutputIO[startRegAddr]=0x01;
430                 else *Modbus_OutputIO[startRegAddr]=0x00;
431                 
432                 RS485_TX_BUFF[0]=RS485_RX_BUFF[0];
433                 RS485_TX_BUFF[1]=RS485_RX_BUFF[1];
434                 RS485_TX_BUFF[2]=RS485_RX_BUFF[2];
435                 RS485_TX_BUFF[3]=RS485_RX_BUFF[3];
436                 RS485_TX_BUFF[4]=RS485_RX_BUFF[4];
437                 RS485_TX_BUFF[5]=RS485_RX_BUFF[5];
438                 
439                 calCRC=CRC_Compute(RS485_TX_BUFF,6);
440                 RS485_TX_BUFF[6]=(calCRC>>8)&0xFF;
441                 RS485_TX_BUFF[7]=(calCRC)&0xFF;
442                 RS485_SendData(RS485_TX_BUFF,8);
443         }
444         else//寄存器地址超出范圍
445         {
446                 RS485_TX_BUFF[0]=RS485_RX_BUFF[0];
447                 RS485_TX_BUFF[1]=RS485_RX_BUFF[1]|0x80;
448                 RS485_TX_BUFF[2]=0x02; //異常碼
449                 RS485_SendData(RS485_TX_BUFF,3);
450         }
451 }
452 
453 //Modbus功能碼15處理程序   //////////////////////////////////////////////////////程序已驗證OK
454 //寫多個輸出開關量
455 void Modbus_15_Solve(void)
456 {
457         u16 i;
458         RegNum=(((u16)RS485_RX_BUFF[4])<<8)|RS485_RX_BUFF[5];//獲取寄存器數量
459         if((startRegAddr+RegNum)<100)//寄存器地址+數量在范圍內
460         {        
461                 for(i=0;i<RegNum;i++)
462                 {
463                         if(RS485_RX_BUFF[7+i/8]&0x01) *Modbus_OutputIO[startRegAddr+i]=0x01;
464                         else *Modbus_OutputIO[startRegAddr+i]=0x00;
465                         RS485_RX_BUFF[7+i/8]>>=1;//從低位開始
466                 }
467                 
468                 RS485_TX_BUFF[0]=RS485_RX_BUFF[0];
469                 RS485_TX_BUFF[1]=RS485_RX_BUFF[1];
470                 RS485_TX_BUFF[2]=RS485_RX_BUFF[2];
471                 RS485_TX_BUFF[3]=RS485_RX_BUFF[3];
472                 RS485_TX_BUFF[4]=RS485_RX_BUFF[4];
473                 RS485_TX_BUFF[5]=RS485_RX_BUFF[5];
474                 calCRC=CRC_Compute(RS485_TX_BUFF,6);
475                 RS485_TX_BUFF[6]=(calCRC>>8)&0xFF;
476                 RS485_TX_BUFF[7]=(calCRC)&0xFF;
477                 RS485_SendData(RS485_TX_BUFF,8);
478         }
479         else//寄存器地址+數量超出范圍
480         {
481                 RS485_TX_BUFF[0]=RS485_RX_BUFF[0];
482                 RS485_TX_BUFF[1]=RS485_RX_BUFF[1]|0x80;
483                 RS485_TX_BUFF[2]=0x02; //異常碼
484                 RS485_SendData(RS485_TX_BUFF,3);
485         }
486 }
487 
488 //Modbus功能碼03處理程序///////////////////////////////////////////////////////////////////////////////////////已驗證程序OK
489 //讀保持寄存器
490 void Modbus_03_Solve(void)
491 {
492         u8 i;
493         RegNum= (((u16)RS485_RX_BUFF[4])<<8)|RS485_RX_BUFF[5];//獲取寄存器數量
494         if((startRegAddr+RegNum)<1000)//寄存器地址+數量在范圍內
495         {
496                 RS485_TX_BUFF[0]=RS485_RX_BUFF[0];
497                 RS485_TX_BUFF[1]=RS485_RX_BUFF[1];
498                 RS485_TX_BUFF[2]=RegNum*2;
499                 for(i=0;i<RegNum;i++)
500                 {
501                         RS485_TX_BUFF[3+i*2]=(*Modbus_HoldReg[startRegAddr+i]>>8)&0xFF;//           /////////先發送高字節--在發送低字節
502                         RS485_TX_BUFF[4+i*2]=(*Modbus_HoldReg[startRegAddr+i])&0xFF; //
503                 }
504                 calCRC=CRC_Compute(RS485_TX_BUFF,RegNum*2+3);
505                 RS485_TX_BUFF[RegNum*2+3]=(calCRC>>8)&0xFF;         //CRC高地位不對嗎?  // 先高后低
506                 RS485_TX_BUFF[RegNum*2+4]=(calCRC)&0xFF;
507                 RS485_SendData(RS485_TX_BUFF,RegNum*2+5);
508         }
509         else//寄存器地址+數量超出范圍
510         {
511                 RS485_TX_BUFF[0]=RS485_RX_BUFF[0];
512                 RS485_TX_BUFF[1]=RS485_RX_BUFF[1]|0x80;
513                 RS485_TX_BUFF[2]=0x02; //異常碼
514                 RS485_SendData(RS485_TX_BUFF,3);
515         }
516 }
517 
518 
519 //Modbus功能碼06處理程序   //////////////////////////////////////////////////////////////////////////////////已驗證程序OK
520 //寫單個保持寄存器
521 void Modbus_06_Solve(void)
522 {
523         *Modbus_HoldReg[startRegAddr]=RS485_RX_BUFF[4]<<8;//高字節在前                    ////////修改為高字節在前,低字節在后
524         *Modbus_HoldReg[startRegAddr]|=((u16)RS485_RX_BUFF[5]);//低字節在后
525         
526         RS485_TX_BUFF[0]=RS485_RX_BUFF[0];
527         RS485_TX_BUFF[1]=RS485_RX_BUFF[1];
528         RS485_TX_BUFF[2]=RS485_RX_BUFF[2];
529         RS485_TX_BUFF[3]=RS485_RX_BUFF[3];
530         RS485_TX_BUFF[4]=RS485_RX_BUFF[4];
531         RS485_TX_BUFF[5]=RS485_RX_BUFF[5];
532         
533         calCRC=CRC_Compute(RS485_TX_BUFF,6);
534         RS485_TX_BUFF[6]=(calCRC>>8)&0xFF;
535         RS485_TX_BUFF[7]=(calCRC)&0xFF;
536         RS485_SendData(RS485_TX_BUFF,8);
537 }
538 
539 //Modbus功能碼16處理程序 /////////////////////////////////////////////////////////////////////////////////////////////////已驗證程序OK
540 //寫多個保持寄存器
541 void Modbus_16_Solve(void)
542 {
543         u8 i;
544         RegNum= (((u16)RS485_RX_BUFF[4])<<8)|((RS485_RX_BUFF[5]));//獲取寄存器數量
545         if((startRegAddr+RegNum)<1000)//寄存器地址+數量在范圍內
546         {
547                 for(i=0;i<RegNum;i++)
548                 {
549                         *Modbus_HoldReg[startRegAddr+i]=RS485_RX_BUFF[7+i*2]; //低字節在前                 /////// 低字節在前,高字節在后正常
550                         *Modbus_HoldReg[startRegAddr+i]|=((u16)RS485_RX_BUFF[8+i*2])<<8; //高字節在后
551                 }
552                 
553                 RS485_TX_BUFF[0]=RS485_RX_BUFF[0];
554                 RS485_TX_BUFF[1]=RS485_RX_BUFF[1];
555                 RS485_TX_BUFF[2]=RS485_RX_BUFF[2];
556                 RS485_TX_BUFF[3]=RS485_RX_BUFF[3];
557                 RS485_TX_BUFF[4]=RS485_RX_BUFF[4];
558                 RS485_TX_BUFF[5]=RS485_RX_BUFF[5];
559                 
560                 calCRC=CRC_Compute(RS485_TX_BUFF,6);
561                 RS485_TX_BUFF[6]=(calCRC>>8)&0xFF;
562                 RS485_TX_BUFF[7]=(calCRC)&0xFF;
563                 RS485_SendData(RS485_TX_BUFF,8);
564         }
565         else//寄存器地址+數量超出范圍
566         {
567                 RS485_TX_BUFF[0]=RS485_RX_BUFF[0];
568                 RS485_TX_BUFF[1]=RS485_RX_BUFF[1]|0x80;
569                 RS485_TX_BUFF[2]=0x02; //異常碼
570                 RS485_SendData(RS485_TX_BUFF,3);
571         }
572 }
573 
574  
575 
576  

 

 

 

 

 

 

 

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM