找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3088|回复: 4
收起左侧

我的ModBus主机-协议篇

[复制链接]
ID:446156 发表于 2021-11-15 13:22 | 显示全部楼层 |阅读模式
该章节是整个系列中最简单的由"Modbus_Master.c"和"Modbus_Master.h"两个文件组成。
首先来看"Modbus_Master.h"
  1. #ifndef __MODBUSMASTER_H
  2. #define __MODBUSMASTER_H

  3. #include "Header.h"
  4. #include "UartDebug.h"
  5. #include "Delay.h"

  6. struct ModbusMasterDevice
  7. {
  8.         struct UartDebugMember *UDM;
  9.         uint8_t State;
  10.         uint16_t DelayTime;
  11.         uint16_t Input_Reg[8];  
  12.         uint16_t Hold_Reg[8];
  13.         uint8_t RIR_Update;
  14.         uint8_t WHR_Success;
  15. };

  16. extern struct ModbusMasterDevice MMDPort1;

  17. void ModBusMasterInit(void);
  18. uint8_t WriteHoldReg(struct ModbusMasterDevice *MBM,uint8_t DeviceAddr,uint16_t Addr,uint16_t Len,uint16_t *Data);
  19. uint8_t ReadHoldInputReg(struct ModbusMasterDevice *MBM,uint8_t DeviceAddr,uint8_t Com,uint16_t Addr,uint16_t Len);

  20. #endif
复制代码
该文件包含了最基本的"Header.h"和UART篇介绍的 "UartDebug.h"以及我个人最常用的"Delay.h"。
为了更方便的讲解后续代码我们首先介绍一下"Delay.c"中的三个函数。
  1. void Set_Delay_Time(uint16_t Time,uint16_t *DelayTime_Count)
  2. {
  3.         *DelayTime_Count=Time;
  4. }
  5. void DelayTimeCount_ms(uint16_t *DelayTime_Count)
  6. {
  7.         if(*DelayTime_Count==0)
  8.         {
  9.                 *DelayTime_Count=0;
  10.         }
  11.         else
  12.         {
  13.                 *DelayTime_Count-=1;
  14.         }
  15. }
  16. uint8_t CheckDelay(uint16_t *DelayTime_Count)
  17. {
  18.         if(*DelayTime_Count==0)
  19.         {
  20.                 return 0;
  21.         }
  22.         else
  23.         {
  24.                 return 1;
  25.         }
  26. }
复制代码
第一个函数“void Set_Delay_Time(uint16_t Time,uint16_t *DelayTime_Count)”就是把Time赋值给*DelayTime_Count,具体使用示例会在下文体现;
第二个函数“void DelayTimeCount_ms(uint16_t *DelayTime_Count)”就是把输入的变量作累减直到0,该函数需要每隔1ms或者其他时间来周期执行;
第三个函数“uint8_t CheckDelay(uint16_t *DelayTime_Count)”就是查询输入的变量是否为0并返回相应的值,具体使用示例会在下文体现。
好了我们接着看"Modbus_Master.h"。
“struct UartDebugMember *UDM;” ModBus主机使用的端口信息;
“uint8_t State;” ModBus主机当前的工作状态;
“uint16_t DelayTime;” 从机未响应计时;
“uint16_t Input_Reg[8];” 输入寄存器;
“uint16_t Hold_Reg[8];” 保持寄存器;
“uint8_t RIR_Update;” 读取输入/保持寄存器成功标志;
“uint8_t WHR_Success;” 写保持寄存器成功标志。
从代码中可以看出我们的ModBus主机仅实现了读取输入/保持寄存器和写保持寄存器两个功能,因为这两个功能最常用,其他的功能我也懒得写了。现在看看具体代码。
  1. #include "Modbus_Master.h"

  2. struct ModbusMasterDevice MMDPort1;

  3. void ModBusMasterInit(void)
  4. {
  5.         MMDPort1.UDM = &U_D_Uart7;
  6. }
  7. /*******************************************************************************
  8. *Function Name    : CRC16_CHECK
  9. *Input            :
  10. *Return           :
  11. *Description      :
  12. *******************************************************************************/
  13. static unsigned short int CRC16_CHECK(unsigned char *Buf, unsigned char CRC_CNT)
  14. {
  15.         unsigned short int CRC16_Temp;
  16.         unsigned char i,j;
  17.         CRC16_Temp = 0xffff;

  18.         for (i=0;i<CRC_CNT; i++)
  19.         {      
  20.                 CRC16_Temp ^= Buf[i];
  21.                 for (j=0;j<8;j++)
  22.                 {
  23.                         if (CRC16_Temp & 0x01)
  24.                                 CRC16_Temp = (CRC16_Temp >>1 ) ^ 0xa001;
  25.                         else
  26.                                 CRC16_Temp = CRC16_Temp >> 1;
  27.                 }
  28.         }
  29.         return CRC16_Temp;
  30. }
  31. uint8_t WriteHoldReg(struct ModbusMasterDevice *MBM,uint8_t DeviceAddr,uint16_t Addr,uint16_t Len,uint16_t *Data)
  32. {
  33.         uint16_t CRC16=0;
  34.         uint16_t CRC16_Receive=0;
  35.         uint8_t i=0;
  36.        
  37.         switch(MBM->State)
  38.         {
  39.                 case 0:
  40.                 {
  41.                         MBM->UDM->TransmitBuf[0] = DeviceAddr;
  42.                         MBM->UDM->TransmitBuf[1] = 0x10;
  43.                         MBM->UDM->TransmitBuf[2] = Addr>>8;
  44.                         MBM->UDM->TransmitBuf[3] = Addr;
  45.                         MBM->UDM->TransmitBuf[4] = Len>>8;
  46.                         MBM->UDM->TransmitBuf[5] = Len;
  47.                         MBM->UDM->TransmitBuf[6] = Len*2;
  48.                         for(i=0;i<Len;i++)
  49.                         {
  50.                                 MBM->UDM->TransmitBuf[i*2+7] = *(Data+i)>>8;
  51.                                 MBM->UDM->TransmitBuf[i*2+8] = *(Data+i);
  52.                         }
  53.                         CRC16 = CRC16_CHECK(MBM->UDM->TransmitBuf,7+Len*2);
  54.                         MBM->UDM->TransmitBuf[8+Len*2] = CRC16>>8;
  55.                         MBM->UDM->TransmitBuf[7+Len*2] = CRC16;
  56.                         TransmitData(MBM->UDM,MBM->UDM->TransmitBuf,9+Len*2);
  57.                         Set_Delay_Time(100,&MBM->DelayTime);
  58.                         MBM->State ++;
  59.                 }break;
  60.                 case 1:
  61.                 {
  62.                         if(MBM->UDM->ReceiveFinish)
  63.                         {
  64.                                 CRC16_Receive=(MBM->UDM->ReceiveBuf[MBM->UDM->ReceivePoint-1]<<8)|MBM->UDM->ReceiveBuf[MBM->UDM->ReceivePoint-2];       
  65.                                 CRC16 = CRC16_CHECK(MBM->UDM->ReceiveBuf,MBM->UDM->ReceivePoint-2);
  66.                                 if(CRC16_Receive == CRC16)
  67.                                 {
  68.                                         /*这么写是有bug的,算了先这么着吧*/
  69.                                         MBM->WHR_Success = 1;
  70.                                 }
  71.                                 MBM->State = 0;
  72.                 ClearRxData(MBM->UDM);
  73.                                 return 1;
  74.                         }
  75.                         else if(CheckDelay(&MBM->DelayTime) == 0)
  76.                         {
  77.                                 MBM->State = 0;
  78.                                 ClearRxData(MBM->UDM);
  79.                                 return 1;
  80.                         }
  81.                 }break;
  82.         }
  83.         return 0;       
  84. }
  85. uint8_t ReadHoldInputReg(struct ModbusMasterDevice *MBM,uint8_t DeviceAddr,uint8_t Com,uint16_t Addr,uint16_t Len)
  86. {
  87.         uint16_t CRC16=0;
  88.         uint16_t CRC16_Receive=0;
  89.         uint8_t i=0;
  90.        
  91.         switch(MBM->State)
  92.         {
  93.                 case 0:
  94.                 {
  95.                         MBM->UDM->TransmitBuf[0] = DeviceAddr;
  96.                         MBM->UDM->TransmitBuf[1] = Com;
  97.                         MBM->UDM->TransmitBuf[2] = Addr>>8;
  98.                         MBM->UDM->TransmitBuf[3] = Addr;
  99.                         MBM->UDM->TransmitBuf[4] = Len>>8;
  100.                         MBM->UDM->TransmitBuf[5] = Len;
  101.                         CRC16 = CRC16_CHECK(MBM->UDM->TransmitBuf,6);
  102.                         MBM->UDM->TransmitBuf[7] = CRC16>>8;
  103.                         MBM->UDM->TransmitBuf[6] = CRC16;
  104.                         TransmitData(MBM->UDM,MBM->UDM->TransmitBuf,8);
  105.                         Set_Delay_Time(100,&MBM->DelayTime);
  106.                         MBM->State ++;
  107.                 }break;
  108.                 case 1:
  109.                 {
  110.                         if(MBM->UDM->ReceiveFinish)
  111.                         {
  112.                                 CRC16_Receive=(MBM->UDM->ReceiveBuf[MBM->UDM->ReceivePoint-1]<<8)|MBM->UDM->ReceiveBuf[MBM->UDM->ReceivePoint-2];       
  113.                                 CRC16 = CRC16_CHECK(MBM->UDM->ReceiveBuf,MBM->UDM->ReceivePoint-2);
  114.                                 if(CRC16_Receive == CRC16)
  115.                                 {
  116.                                         for(i=0;i<MBM->UDM->ReceiveBuf[2]/2;i++)
  117.                                         {
  118.                                                 if(Com == 0x04)
  119.                                                 {
  120.                                                         MBM->Input_Reg[Addr+i] = (MBM->UDM->ReceiveBuf[3+i*2])<<8 | MBM->UDM->ReceiveBuf[4+i*2];
  121.                                                 }
  122.                                                 else
  123.                                                 {
  124.                                                         MBM->Hold_Reg[Addr+i] = (MBM->UDM->ReceiveBuf[3+i*2])<<8 | MBM->UDM->ReceiveBuf[4+i*2];
  125.                                                 }
  126.                                         }
  127.                                         MBM->RIR_Update = 1;
  128.                                 }
  129.                                 MBM->State = 0;
  130.                 ClearRxData(MBM->UDM);
  131.                                 return 1;
  132.                         }
  133.                         else if(CheckDelay(&MBM->DelayTime) == 0)
  134.                         {
  135.                                 MBM->State = 0;
  136.                                 ClearRxData(MBM->UDM);
  137.                                 return 1;
  138.                         }
  139.                 }break;
  140.         }
  141.         return 0;
  142. }
复制代码
可以看到首先定义了一个ModbusMasterDevice实体MMDPort1,然后初始化该实体将其要使用的端口与U_D_Uart7对接起来。
其余的代码就很简单了,需要注意的有两个地方,一是我们把给从机发数据和接收从机数据分成了两部分来完成。为什么要这么做呢?这是为了当从机响应不及时或者从机不在线时MCU可以去做其他的事情而不必在这里死等。二是当收到从机应答(无论CRC校验是否成功)或者从机响应超时(这里就涉及到前文中提及的“delay”三个函数)都需要执行ClearRxData()并返回1,这点非常重要。
在该函数中没有做重发机制,并不是没有重发机制而是在更往上的层中来实现的后面会介绍到。





评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:84103 发表于 2022-10-18 09:40 | 显示全部楼层
Input_Reg[Addr+i]这里代表啥寄存器?
回复

使用道具 举报

ID:1055247 发表于 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
回复

使用道具 举报

ID:462629 发表于 2023-3-2 12:14 | 显示全部楼层
这个基于什么芯片的啊?
回复

使用道具 举报

ID:821429 发表于 2023-4-16 09:45 | 显示全部楼层
,标记学习一下,感谢分享
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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