標(biāo)題: 我的ModBus主機(jī)-協(xié)議篇 [打印本頁]
作者: qinlu123 時(shí)間: 2021-11-15 13:22
標(biāo)題: 我的ModBus主機(jī)-協(xié)議篇 該章節(jié)是整個(gè)系列中最簡單的由"Modbus_Master.c"和"Modbus_Master.h"兩個(gè)文件組成。
首先來看"Modbus_Master.h"
- #ifndef __MODBUSMASTER_H
- #define __MODBUSMASTER_H
- #include "Header.h"
- #include "UartDebug.h"
- #include "Delay.h"
- struct ModbusMasterDevice
- {
- struct UartDebugMember *UDM;
- uint8_t State;
- uint16_t DelayTime;
- uint16_t Input_Reg[8];
- uint16_t Hold_Reg[8];
- uint8_t RIR_Update;
- uint8_t WHR_Success;
- };
- extern struct ModbusMasterDevice MMDPort1;
- void ModBusMasterInit(void);
- uint8_t WriteHoldReg(struct ModbusMasterDevice *MBM,uint8_t DeviceAddr,uint16_t Addr,uint16_t Len,uint16_t *Data);
- uint8_t ReadHoldInputReg(struct ModbusMasterDevice *MBM,uint8_t DeviceAddr,uint8_t Com,uint16_t Addr,uint16_t Len);
- #endif
復(fù)制代碼 該文件包含了最基本的"Header.h"和UART篇介紹的 "UartDebug.h"以及我個(gè)人最常用的"Delay.h"。
為了更方便的講解后續(xù)代碼我們首先介紹一下"Delay.c"中的三個(gè)函數(shù)。
- void Set_Delay_Time(uint16_t Time,uint16_t *DelayTime_Count)
- {
- *DelayTime_Count=Time;
- }
- void DelayTimeCount_ms(uint16_t *DelayTime_Count)
- {
- if(*DelayTime_Count==0)
- {
- *DelayTime_Count=0;
- }
- else
- {
- *DelayTime_Count-=1;
- }
- }
- uint8_t CheckDelay(uint16_t *DelayTime_Count)
- {
- if(*DelayTime_Count==0)
- {
- return 0;
- }
- else
- {
- return 1;
- }
- }
復(fù)制代碼 第一個(gè)函數(shù)“void Set_Delay_Time(uint16_t Time,uint16_t *DelayTime_Count)”就是把Time賦值給*DelayTime_Count,具體使用示例會(huì)在下文體現(xiàn);
第二個(gè)函數(shù)“void DelayTimeCount_ms(uint16_t *DelayTime_Count)”就是把輸入的變量作累減直到0,該函數(shù)需要每隔1ms或者其他時(shí)間來周期執(zhí)行;
第三個(gè)函數(shù)“uint8_t CheckDelay(uint16_t *DelayTime_Count)”就是查詢輸入的變量是否為0并返回相應(yīng)的值,具體使用示例會(huì)在下文體現(xiàn)。
好了我們接著看"Modbus_Master.h"。
“struct UartDebugMember *UDM;” ModBus主機(jī)使用的端口信息;
“uint8_t State;” ModBus主機(jī)當(dāng)前的工作狀態(tài);
“uint16_t DelayTime;” 從機(jī)未響應(yīng)計(jì)時(shí);
“uint16_t Input_Reg[8];” 輸入寄存器;
“uint16_t Hold_Reg[8];” 保持寄存器;
“uint8_t RIR_Update;” 讀取輸入/保持寄存器成功標(biāo)志;
“uint8_t WHR_Success;” 寫保持寄存器成功標(biāo)志。
從代碼中可以看出我們的ModBus主機(jī)僅實(shí)現(xiàn)了讀取輸入/保持寄存器和寫保持寄存器兩個(gè)功能,因?yàn)檫@兩個(gè)功能最常用,其他的功能我也懶得寫了�,F(xiàn)在看看具體代碼。
- #include "Modbus_Master.h"
- struct ModbusMasterDevice MMDPort1;
- void ModBusMasterInit(void)
- {
- MMDPort1.UDM = &U_D_Uart7;
- }
- /*******************************************************************************
- *Function Name : CRC16_CHECK
- *Input :
- *Return :
- *Description :
- *******************************************************************************/
- static unsigned short int CRC16_CHECK(unsigned char *Buf, unsigned char CRC_CNT)
- {
- unsigned short int CRC16_Temp;
- unsigned char i,j;
- CRC16_Temp = 0xffff;
- for (i=0;i<CRC_CNT; i++)
- {
- CRC16_Temp ^= Buf[i];
- for (j=0;j<8;j++)
- {
- if (CRC16_Temp & 0x01)
- CRC16_Temp = (CRC16_Temp >>1 ) ^ 0xa001;
- else
- CRC16_Temp = CRC16_Temp >> 1;
- }
- }
- return CRC16_Temp;
- }
- uint8_t WriteHoldReg(struct ModbusMasterDevice *MBM,uint8_t DeviceAddr,uint16_t Addr,uint16_t Len,uint16_t *Data)
- {
- uint16_t CRC16=0;
- uint16_t CRC16_Receive=0;
- uint8_t i=0;
-
- switch(MBM->State)
- {
- case 0:
- {
- MBM->UDM->TransmitBuf[0] = DeviceAddr;
- MBM->UDM->TransmitBuf[1] = 0x10;
- MBM->UDM->TransmitBuf[2] = Addr>>8;
- MBM->UDM->TransmitBuf[3] = Addr;
- MBM->UDM->TransmitBuf[4] = Len>>8;
- MBM->UDM->TransmitBuf[5] = Len;
- MBM->UDM->TransmitBuf[6] = Len*2;
- for(i=0;i<Len;i++)
- {
- MBM->UDM->TransmitBuf[i*2+7] = *(Data+i)>>8;
- MBM->UDM->TransmitBuf[i*2+8] = *(Data+i);
- }
- CRC16 = CRC16_CHECK(MBM->UDM->TransmitBuf,7+Len*2);
- MBM->UDM->TransmitBuf[8+Len*2] = CRC16>>8;
- MBM->UDM->TransmitBuf[7+Len*2] = CRC16;
- TransmitData(MBM->UDM,MBM->UDM->TransmitBuf,9+Len*2);
- Set_Delay_Time(100,&MBM->DelayTime);
- MBM->State ++;
- }break;
- case 1:
- {
- if(MBM->UDM->ReceiveFinish)
- {
- CRC16_Receive=(MBM->UDM->ReceiveBuf[MBM->UDM->ReceivePoint-1]<<8)|MBM->UDM->ReceiveBuf[MBM->UDM->ReceivePoint-2];
- CRC16 = CRC16_CHECK(MBM->UDM->ReceiveBuf,MBM->UDM->ReceivePoint-2);
- if(CRC16_Receive == CRC16)
- {
- /*這么寫是有bug的,算了先這么著吧*/
- MBM->WHR_Success = 1;
- }
- MBM->State = 0;
- ClearRxData(MBM->UDM);
- return 1;
- }
- else if(CheckDelay(&MBM->DelayTime) == 0)
- {
- MBM->State = 0;
- ClearRxData(MBM->UDM);
- return 1;
- }
- }break;
- }
- return 0;
- }
- uint8_t ReadHoldInputReg(struct ModbusMasterDevice *MBM,uint8_t DeviceAddr,uint8_t Com,uint16_t Addr,uint16_t Len)
- {
- uint16_t CRC16=0;
- uint16_t CRC16_Receive=0;
- uint8_t i=0;
-
- switch(MBM->State)
- {
- case 0:
- {
- MBM->UDM->TransmitBuf[0] = DeviceAddr;
- MBM->UDM->TransmitBuf[1] = Com;
- MBM->UDM->TransmitBuf[2] = Addr>>8;
- MBM->UDM->TransmitBuf[3] = Addr;
- MBM->UDM->TransmitBuf[4] = Len>>8;
- MBM->UDM->TransmitBuf[5] = Len;
- CRC16 = CRC16_CHECK(MBM->UDM->TransmitBuf,6);
- MBM->UDM->TransmitBuf[7] = CRC16>>8;
- MBM->UDM->TransmitBuf[6] = CRC16;
- TransmitData(MBM->UDM,MBM->UDM->TransmitBuf,8);
- Set_Delay_Time(100,&MBM->DelayTime);
- MBM->State ++;
- }break;
- case 1:
- {
- if(MBM->UDM->ReceiveFinish)
- {
- CRC16_Receive=(MBM->UDM->ReceiveBuf[MBM->UDM->ReceivePoint-1]<<8)|MBM->UDM->ReceiveBuf[MBM->UDM->ReceivePoint-2];
- CRC16 = CRC16_CHECK(MBM->UDM->ReceiveBuf,MBM->UDM->ReceivePoint-2);
- if(CRC16_Receive == CRC16)
- {
- for(i=0;i<MBM->UDM->ReceiveBuf[2]/2;i++)
- {
- if(Com == 0x04)
- {
- MBM->Input_Reg[Addr+i] = (MBM->UDM->ReceiveBuf[3+i*2])<<8 | MBM->UDM->ReceiveBuf[4+i*2];
- }
- else
- {
- MBM->Hold_Reg[Addr+i] = (MBM->UDM->ReceiveBuf[3+i*2])<<8 | MBM->UDM->ReceiveBuf[4+i*2];
- }
- }
- MBM->RIR_Update = 1;
- }
- MBM->State = 0;
- ClearRxData(MBM->UDM);
- return 1;
- }
- else if(CheckDelay(&MBM->DelayTime) == 0)
- {
- MBM->State = 0;
- ClearRxData(MBM->UDM);
- return 1;
- }
- }break;
- }
- return 0;
- }
復(fù)制代碼 可以看到首先定義了一個(gè)ModbusMasterDevice實(shí)體MMDPort1,然后初始化該實(shí)體將其要使用的端口與U_D_Uart7對接起來。
其余的代碼就很簡單了,需要注意的有兩個(gè)地方,一是我們把給從機(jī)發(fā)數(shù)據(jù)和接收從機(jī)數(shù)據(jù)分成了兩部分來完成。為什么要這么做呢?這是為了當(dāng)從機(jī)響應(yīng)不及時(shí)或者從機(jī)不在線時(shí)MCU可以去做其他的事情而不必在這里死等。二是當(dāng)收到從機(jī)應(yīng)答(無論CRC校驗(yàn)是否成功)或者從機(jī)響應(yīng)超時(shí)(這里就涉及到前文中提及的“delay”三個(gè)函數(shù))都需要執(zhí)行ClearRxData()并返回1,這點(diǎn)非常重要。
在該函數(shù)中沒有做重發(fā)機(jī)制,并不是沒有重發(fā)機(jī)制而是在更往上的層中來實(shí)現(xiàn)的后面會(huì)介紹到。
作者: rfvrfv 時(shí)間: 2022-10-18 09:40
Input_Reg[Addr+i]這里代表啥寄存器?
作者: wxcsmzh 時(shí)間: 2022-12-2 19:10
extern struct ModbusMasterDevice MMDPort1; void ModBusMasterInit(void); uint8_t WriteHoldReg(struct ModbusMasterDevice *MBM,uint8_t DeviceAddr,uint16_t Addr,uint16_t Len,uint16_t *Data); uint8_t ReadHoldInputReg(struct ModbusMasterDevice *MBM,uint8_t DeviceAddr,uint8_t Com,uint16_t Addr,uint16_t Len); #endif
作者: woyaodwn 時(shí)間: 2023-3-2 12:14
這個(gè)基于什么芯片的��?
作者: liixaofei5 時(shí)間: 2023-4-16 09:45
,標(biāo)記學(xué)習(xí)一下,感謝分享
作者: qinlu123 時(shí)間: 2024-8-16 11:47
stm32,可以輕松移植到任何單片機(jī)平臺
歡迎光臨 (http://www.torrancerestoration.com/bbs/) |
Powered by Discuz! X3.1 |
|