无需短信和注册的ModBus从站RTU / ASCII

图片



有许多公共可用的库可用于实现ModBus从站设备,但它们通常包含冗余功能,难以学习且包含严重错误。本文以作者的谦逊观点讨论了一个没有这些缺点的图书馆。



该库软件作为开源C代码提供。



modbus.h
////////////////////////////////////////////////////////////////////
//       ModBus v2   //
//     - I                                                      //
///////////////////////////////////////////////////////////////////
#ifndef __MODBUS_H
#define __MODBUS_H

#include "main.h"

///////////////////////////////////////////////////////////////////////////////
// 
//,   
#define ModBusUseGlobal (0) //  /, / 
//  
#define ModBusUseFunc1  (0) //  1  -   Coils (  )
#define ModBusUseFunc2  (0) //  2  -    
#define ModBusUseFunc3  (1) //  3  -    
#define ModBusUseFunc4  (0) //  4  -    
#define ModBusUseFunc5  (0) //  5  -   
#define ModBusUseFunc6  (1) //  6  -   
#define ModBusUseFunc15 (0) //  15 -    
#define ModBusUseFunc16 (1) //  16 -    
// 
#define ModBusID (1) //   
#define ModBusID_FF (255) //   ,    
//
#define ModBusMaxPause (5)//  ,     [mS], 
#define ModBusMaxPauseResp (2) //       [mS]
// 
#define ModBusMaxPaketRX (96)//    <127
// 
#define ModBusMaxInBit (0) //   
#define ModBusMaxInBitTX (8) //       
#define ModBusMaxInByte ((ModBusMaxInBit+7)/8) //    
// 
#define ModBusMaxOutBit (0) //  
#define ModBusMaxOutByte ((ModBusMaxOutBit+7)/8) //    
#define ModBusMaxOutBitTX (8) //       
#define ModBusMaxOutBitRX (8) //       
//   
#define ModBusMaxInReg (0) //   (   )
#define ModBusMaxInRegTX (24) //       
//   -
#define ModBusMaxOutReg (48) //  
#define ModBusMaxOutRegTX (32)//       
#define ModBusMaxOutRegRX (32)//        
////////////////////////////////////////////////////////////////////////////////
// ,   
// ,   
#define ModBusSysTimer TimingDelay
//      - void ModBusPUT(unsigned char A)
#define ModBusPUT(A) PutFifo0(A) 
//     , - unsigned short ModBusGET(void)
//    00000,   001
#define ModBusGET()  Inkey16Fifo0() 
////////////////////////////////////////////////////////////////////////////////

// 
void ModBusIni(void);

//    RTU
//     
//  ModbusPUT(A) ModbusGET()
void ModBusRTU(void);

//    ASCII
//     
//  ModbusPUT(A) ModbusGET()
void ModBusASCII(void);

//  
//       
void Prg2ModBusOutBit(void);
void Prg2ModBusInBit(void);
void Prg2ModBusOutReg(void);
void Prg2ModBusInReg(void);
//  
//       
void ModBus2PrgOutBit(void);
void ModBus2PrgOutReg(void);

#pragma pack(push,1)
//      /
typedef union
  {
  unsigned char byte;
  struct
    {
    unsigned char bit0:1;
    unsigned char bit1:1;
    unsigned char bit2:1;
    unsigned char bit3:1;
    unsigned char bit4:1;
    unsigned char bit5:1;
    unsigned char bit6:1;
    unsigned char bit7:1;
    };
  }
  ModBusBit_t;
#pragma pack(pop)
  
#ifdef __MODBUS2PRG_C
#if ModBusMaxInBit!=0
ModBusBit_t ModBusInBit[ModBusMaxInByte]; //  
#endif
#if ModBusMaxOutBit!=0
ModBusBit_t ModBusOutBit[ModBusMaxOutByte]; //  
#endif
#if ModBusMaxInReg!=0
unsigned short ModBusInReg[ModBusMaxInReg]; //  
#endif
#if ModBusMaxOutReg!=0
unsigned short ModBusOutReg[ModBusMaxOutReg]; //  
#endif
#else 
#if ModBusUseGlobal!=0 || defined(__MODBUS_C)
#if ModBusMaxInBit!=0
extern ModBusBit_t ModBusInBit[ModBusMaxInByte]; //  
#endif
#if ModBusMaxOutBit!=0
extern ModBusBit_t ModBusOutBit[ModBusMaxOutByte]; //  
#endif
#if ModBusMaxInReg!=0
extern unsigned short ModBusInReg[ModBusMaxInReg]; //  
#endif
#if ModBusMaxOutReg!=0
extern unsigned short ModBusOutReg[ModBusMaxOutReg]; //  
#endif
#endif//#if ModBusUseGlobal!=0
#endif//#ifdef __MODBUS2PRG_C
#endif//#ifndef __MODBUS_H




modbus.c
#define __MODBUS_C
#include "modbus.h"

static unsigned char PaketRX[ModBusMaxPaketRX];//   
static unsigned char UkPaket;//  ,    
static unsigned long TimModbus; //     
static unsigned short CRCmodbus;// CRC
static unsigned char Sost;// 0/1 /

// 
void ModBusIni(void)
  {
  TimModbus=ModBusSysTimer;// 
  UkPaket=0;//  
  CRCmodbus=0xFFFF; //   CRC
  //  
#if ModBusMaxOutBit!=0
  Prg2ModBusOutBit();
#endif  
#if ModBusMaxInBit!=0  
  Prg2ModBusInBit();
#endif  
#if ModBusMaxOutReg!=0  
  Prg2ModBusOutReg();
#endif  
#if ModBusMaxInReg!=0
  Prg2ModBusInReg();
#endif  
  return;
  }

//  CRC
static inline unsigned short CRCfunc(unsigned short inCRC, unsigned char in)
  {
  inCRC=inCRC^in;
  for(int j=0;j<8;j++){if(inCRC&1){inCRC=(inCRC>>1)^0xA001U;}else {inCRC=inCRC>>1;}}
  return inCRC;
  }

//   
void ModBusRTU(void)
  {
  if(Sost==0)
    {// 
    while(!0)
      {//  
      unsigned short Tmp=ModBusGET(); //    
      if(Tmp==0) return; //   -  
      // 
      Tmp=Tmp&0xFF;//   
      //    
      if((ModBusSysTimer-TimModbus)>ModBusMaxPause)
        {// ,    
        PaketRX[0]=Tmp;//     
        UkPaket=1;//  
        TimModbus=ModBusSysTimer;// 
        // CRC
        CRCmodbus=CRCfunc(0xFFFF,Tmp);
        continue;//  
        }
      else
        {//  ,    
        TimModbus=ModBusSysTimer;// 
        PaketRX[UkPaket]=Tmp;//  
        UkPaket++;//  
        if(UkPaket==ModBusMaxPaketRX)//   
          {//  
          UkPaket=0;//  
          CRCmodbus=0xFFFF; //   CRC
          return;//,    
          }
        // CRC
        CRCmodbus=CRCfunc(CRCmodbus,Tmp);
        }
      //   
      if(UkPaket<8) continue; //  
      //   
      if(CRCmodbus==0) 
        {//   
        if(PaketRX[1]==15 || PaketRX[1]==16)
          {//   (15,16) ,  " "
          if((PaketRX[6]+9)!=UkPaket) continue;
          }
        break; //!  !!!
        }
      }
    //////////////////////////////////////////////////////////////////////////////
    //                         !  !!!
    /////////////////////////////////////////////////////////////////////////////
    UkPaket=0;//  
    
    // 
    if((PaketRX[0]!=ModBusID)&&(PaketRX[0]!=ModBusID_FF))
      {//  
      CRCmodbus=0xFFFF; //   CRC
      return;//   
      }    
      
    //    
    Sost=!0;
#if ModBusMaxPauseResp!=0  
    return;//   
#endif 
    }
  
  ///////////////////////////////////////////////////////////////////////////// 
  if(Sost!=0 
#if ModBusMaxPauseResp!=0     
     && (ModBusSysTimer-TimModbus)>=ModBusMaxPauseResp
#endif     
     )
    {//  
    Sost=0;
    /////////////////////////////////////////////////////////////////////////////    
    //                                                          //
    /////////////////////////////////////////////////////////////////////////////
    //  01 -   Coils (  ). 
    /*-         . 
        0. 
     -      ,
           8  . 
         ,      . 
          .
    01    
           
            ON/OFF    . 
           
                   . 
              :  1-16   0-15.
                 20-56    17. 
           						
                                                                  (Hex) 
           					11	0
          						01	1
            Hi					00	2
            Lo					13	3
           Hi						00	4
           Lo						25	5
            (CRC  LRC)			--

           
                    .
                ,           0. 
                  . 
           						
                                                                  (Hex) 
           					11	0
          						01	1
           						05	2
          ( 27-20)					CD	3
          ( 35-28)					6B	4
          ( 43-36)					B2	5
          ( 51-44)					0E	6
          ( 56-52)					1B	7
            (CRC  LRC)			--
    */
#if ModBusUseFunc1!=0       
    if(PaketRX[1]==0x01)
      {
      //   
      unsigned short AdresBit=(((((unsigned short)PaketRX[2])<<8)|(PaketRX[3])));
      //   
      unsigned short KolvoBit=((((unsigned short)PaketRX[4])<<8)|(PaketRX[5]));
      //    
      if((AdresBit+KolvoBit)>(ModBusMaxOutBit) || KolvoBit>ModBusMaxOutBitTX || KolvoBit==0)
        {//   
        CRCmodbus=0xFFFF; //   CRC
        return;//   
        }
      Prg2ModBusOutBit();//   (GlobalDate->ModBus)
      //  
      //
      ModBusPUT(PaketRX[0]);
      CRCmodbus=CRCfunc(0xFFFF,PaketRX[0]);
      //     
      ModBusPUT(1);
      CRCmodbus=CRCfunc(CRCmodbus,1);
      //  
      ModBusPUT((KolvoBit+7)>>3);
      CRCmodbus=CRCfunc(CRCmodbus,((KolvoBit+7)>>3));
      //    
      unsigned char TxByte=0;// 
      unsigned char Bit=AdresBit&7;//   ModBusOutBit[]
      AdresBit=AdresBit>>3;//  ModBusOutBit[]
      //   ModBusOutBit[]  
      int i=0;
      while(!0)
        {
        if((ModBusOutBit[AdresBit].byte)&(1<<Bit))
          {
          TxByte=TxByte|(1<<(i&7));
          }
        //  
        Bit++;
        if(Bit==8){Bit=0;AdresBit++;}
        i++;
        if((i&7)==0)
          {
          ModBusPUT(TxByte);
          CRCmodbus=CRCfunc(CRCmodbus,TxByte);
          TxByte=0;
          if(i==KolvoBit) break; else continue;
          }
        if(i==KolvoBit) 
          {
          ModBusPUT(TxByte);
          CRCmodbus=CRCfunc(CRCmodbus,TxByte);
          break;
          }
        }
      ModBusPUT(CRCmodbus);
      ModBusPUT(CRCmodbus>>8);
      //
      CRCmodbus=0xFFFF; //   CRC
      return;//    
      }
#endif    
    /////////////////////////////////////////////////////////////////////////////
    //  2 -    
    /*02 Read Input Status 
           
           ON/OFF    ( 1)  . 
           
                   .     0.
                 10197-10218    17. 
                   
           						
                                                                  (Hex) 
           					11	0
          						02	1
            .					00	2
            .					C4	3
          -  .					00	4
          -  .					16	5
           					--

           
                    .
                ,           0. 
                  . 
           						
                                                                  (Hex) 
           					11	0
          						01	1
           						03	2
          ( 10204-10197)				AC	3
          ( 10212-10205)				DB	4
          ( 10218-10213)				35	5
            (CRC  LRC)			--  
    */
#if ModBusUseFunc2!=0     
    if(PaketRX[1]==0x02)
      {
      //   
      unsigned short AdresBit=(((((unsigned short)PaketRX[2])<<8)|(PaketRX[3])));
      //   
      unsigned short KolvoBit=((((unsigned short)PaketRX[4])<<8)|(PaketRX[5]));
      //    
      if((AdresBit+KolvoBit)>(ModBusMaxInBit) || KolvoBit>ModBusMaxInBitTX || KolvoBit==0)
        {//   
        CRCmodbus=0xFFFF; //   CRC
        return;//   
        }
      Prg2ModBusInBit();//   (GlobalDate->ModBus)
      //  
      //
      ModBusPUT(PaketRX[0]);
      CRCmodbus=CRCfunc(0xFFFF,PaketRX[0]);
      //     
      ModBusPUT(2);
      CRCmodbus=CRCfunc(CRCmodbus,2);
      //  
      ModBusPUT((KolvoBit+7)>>3);
      CRCmodbus=CRCfunc(CRCmodbus,((KolvoBit+7)>>3));
      //    
      unsigned char TxByte=0;// 
      unsigned char Bit=AdresBit&7;//  
      AdresBit=AdresBit>>3;//  
      //   ModBusInBit[]  
      int i=0;
      while(!0)
        {
        if((ModBusInBit[AdresBit].byte)&(1<<Bit))
          {//   
          TxByte=TxByte|(1<<(i&7));
          }
        //  
        Bit++;
        if(Bit==8){Bit=0;AdresBit++;}
        i++;
        if((i&7)==0)
          {
          ModBusPUT(TxByte);
          CRCmodbus=CRCfunc(CRCmodbus,TxByte);
          TxByte=0;
          if(i==KolvoBit) break; else continue;
          }
        if(i==KolvoBit)
          {
          ModBusPUT(TxByte);
          CRCmodbus=CRCfunc(CRCmodbus,TxByte);
          break;
          }
        }
      ModBusPUT(CRCmodbus);
      ModBusPUT(CRCmodbus>>8);
      //
      CRCmodbus=0xFFFF; //   CRC
      return;//   
      }
#endif    
    /////////////////////////////////////////////////////////////////////////////
    //  03 -   / . 
    /*-    /  ( ), 
        .     0.
    03 Read Holding Registers 
           
              ( 4)  . 
           
                   . 
              0:  1-16   0-15.
               40108-40110    17. 
           
           						
                                                                  (Hex) 
           					11	0
          						03	1
            .					00	2
            .					6B	3
          -  .					00	4
          -  .					03	5
           					--

           
                   . 
            ,          .
               125    984-8 (984-685  ..), 
           32    .      .
                : 
           
           						
                                                                  (Hex) 
           					11	0
          						03	1
           						06	2
           ( 40108) .				02	3
           ( 40108) .				2B	4
           ( 40109) .				00	5
           ( 40109) .				00	6
           ( 40110) .				00	7
           ( 40110) .				64	8
           					--
    */
#if ModBusUseFunc3!=0      
    if(PaketRX[1]==0x03)
      {
      //   
      unsigned short AdresWord=(((((unsigned short)PaketRX[2])<<8)|(PaketRX[3])));
      //    
      unsigned short KolvoWord=((((unsigned short)PaketRX[4])<<8)|(PaketRX[5])); 
      //    
      if(((AdresWord+KolvoWord)>ModBusMaxOutReg) || (KolvoWord>ModBusMaxOutRegTX))
        {// 
        CRCmodbus=0xFFFF;//   CRC
        return;//,    
        }
      Prg2ModBusOutReg();//   (GlobalDate->ModBus)
      //  
      //
      ModBusPUT(PaketRX[0]);
      CRCmodbus=CRCfunc(0xFFFF,PaketRX[0]);
      //     
      ModBusPUT(3);
      CRCmodbus=CRCfunc(CRCmodbus,3);
      //  
      ModBusPUT(KolvoWord<<1);
      CRCmodbus=CRCfunc(CRCmodbus,(KolvoWord<<1));
      //   ModBusOutReg[]   
      for(int i=0;i<KolvoWord;i++)
        {
        ModBusPUT(ModBusOutReg[AdresWord+i]>>8);
        CRCmodbus=CRCfunc(CRCmodbus,(ModBusOutReg[AdresWord+i]>>8));
        ModBusPUT(ModBusOutReg[AdresWord+i]>>0);
        CRCmodbus=CRCfunc(CRCmodbus,(ModBusOutReg[AdresWord+i]>>0));
        }
      ModBusPUT(CRCmodbus);
      ModBusPUT(CRCmodbus>>8);
      //
      CRCmodbus=0xFFFF; //   CRC
      return;//   
      }
#endif     
    /////////////////////////////////////////////////////////////////////////////
    //  04 -    
    /*04 Read Input Registers 
           
               ( 3)  . 
           
                   .
                 30009    17. 
           
           						
                                                                  (Hex) 
           					11	0
          						03	1
            .					00	2
            .					6B	3
          -  .					00	4
          -  .					03	5
           					--
   
           
                   . 
            ,          .
               125    984-8 (984-685  ..), 
           32    .      .
                : 
           
           						
                                                                  (Hex) 
           					11	0
          						03	1
           						02	2
           ( 30009) .				00	3
           ( 30009) .				2A	4
           					--  
    */
#if ModBusUseFunc4!=0     
    if(PaketRX[1]==0x04)
      {
      //   
      unsigned short AdresWord=(((((unsigned short)PaketRX[2])<<8)|(PaketRX[3])));
      //    
      unsigned short KolvoWord=((((unsigned short)PaketRX[4])<<8)|(PaketRX[5])); 
      //    
      if(((AdresWord+KolvoWord)>ModBusMaxInReg) || (KolvoWord>ModBusMaxInRegTX))
        {// 
        CRCmodbus=0xFFFF;//   CRC
        return;//,    
        }
      Prg2ModBusInReg();//   (GlobalDate->ModBus)
      //  
      //
      ModBusPUT(PaketRX[0]);
      CRCmodbus=CRCfunc(0xFFFF,(PaketRX[0]));
      //     
      ModBusPUT(4);
      CRCmodbus=CRCfunc(CRCmodbus,4);
      //  
      ModBusPUT(KolvoWord<<1);
      CRCmodbus=CRCfunc(CRCmodbus,(KolvoWord<<1));
      //   ModBusInReg[]   
      for(int i=0;i<KolvoWord;i++)
        {
        ModBusPUT(ModBusInReg[AdresWord+i]>>8);
        CRCmodbus=CRCfunc(CRCmodbus,(ModBusInReg[AdresWord+i]>>8));
        ModBusPUT(ModBusInReg[AdresWord+i]>>0);
        CRCmodbus=CRCfunc(CRCmodbus,(ModBusInReg[AdresWord+i]>>0));
        }
      ModBusPUT(CRCmodbus);
      ModBusPUT(CRCmodbus>>8);
      //
      CRCmodbus=0xFFFF; //   CRC
      return;//   
      }
#endif      
    /////////////////////////////////////////////////////////////////////////////
    //  05 -  / 
    /*05 Force Single Coil 
           
             ( 0)  ON  OFF. 
                       . 
                
                              . 
           
               .     0.  1   0.
          ,      (ON/OFF)    . 
           FF00 Hex - ON.  0000 - OFF.         .
                173   ON    17. 
           
           						
                                                                  (Hex) 
           					11	0
          						05	1
            .					00	2
            .					AC	3
           .						FF	4
           .						00	5
           					--
   
           
             . 
           
           						
                                                                  (Hex) 
           					11	0
          						05	1
            .					00	2
            .					AC	3
           .						FF	4
           .						00	5
           					--  
    */
#if ModBusUseFunc5!=0     
    if(PaketRX[1]==0x05)
      {
      //   
      unsigned short AdresBit=(((((unsigned short)PaketRX[2])<<8)|(PaketRX[3])));
      //     
      if(AdresBit>=ModBusMaxOutBit)
        {//  
        CRCmodbus=0xFFFF; //   CRC
        return;//,    
        }
      //  
      switch (((((unsigned short)PaketRX[4])<<8)|(PaketRX[5])))
        {
        case 0xFF00:
        // 
        ModBusOutBit[(AdresBit>>3)].byte|=(1<<(AdresBit&7));
        break;
        case 0x0000:
        // 
        ModBusOutBit[(AdresBit>>3)].byte&=(~(1<<(AdresBit&7)));
        break;
        default:
          {//
          CRCmodbus=0xFFFF; //   CRC
          return;//,    
          } 
        }
      //
      for(int i=0;i<8;i++) ModBusPUT(PaketRX[i]);//   
      ModBus2PrgOutBit();//   (ModBus->GlobalDate)
      //
      CRCmodbus=0xFFFF; //   CRC
      return;//    
      }
#endif     
    /////////////////////////////////////////////////////////////////////////////
    //  06 -  / . 
    /*  05,     (). 
        /    . 
    06 Preset Single Register 
          .      ( 4).
                      . 
           
                . 
           
              ,   .    0.
          ,         . 
           M84  484  10-  ,     0. 
             16 .
                40002   0003 Hex    17. 
           
           						
                                                                  (Hex) 
           					11	0
          						06	1
            .					00	2
            .					01	3
           .						00	4
           .						03	5
           					--
   
           
             . 
           
           						
                                                                  (Hex) 
           					11	0
          						06	1
            .					00	2
            .					01	3
           .						00	4
           .						03	5
           					--  
    */
#if ModBusUseFunc6!=0    
    if(PaketRX[1]==0x06)
      {
      //   
      unsigned short AdresWord=(((((unsigned short)PaketRX[2])<<8)|(PaketRX[3])));
      //     
      if(AdresWord>=(ModBusMaxOutReg))
        {//  
        CRCmodbus=0xFFFF; //   CRC
        return;//,    
        }
      // 
      ModBusOutReg[AdresWord]=(((((unsigned short)PaketRX[4])<<8)|(PaketRX[5])));
      //
      for(int i=0;i<8;i++) ModBusPUT(PaketRX[i]);//   
      ModBus2PrgOutReg();//   (ModBus->GlobalDate)
      //
      CRCmodbus=0xFFFF; //   CRC
      return;//   
      }
#endif     
    /////////////////////////////////////////////////////////////////////////////
    //  0x0F -   / . 
    /*     ,    ,     . 
    15 (0F Hex) Force Multiple Coils 
           
             ( 0)       ON  OFF. 
                   . 
                     . 
           
              .     0.
                    20 (  19) 
             17.
              2 : CD 01 Hex (1100 1101 0000 0001 ). 
               : 
          :    1  1  0  0  1  1  0  1		0  0  0  0  0  0   0  1 
          : 27 26 25 24 23 22 21 20		-  -  -  -  -  -  29 28 
           
           						
                                                                  (Hex) 
           					11	0
          						0F	1
            .					00	2
            .					13	3
          -  .					00	4
          -  .					0A	5
           						02	6
             ( 27-20)			CD	7
             ( 29-28) 			01	8
           					--	9
   
           
              ,  ,  ,    .
                . 
           
           						
                                                                  (Hex) 
           					11	0
          						0F	1
            .					00	2
            .					13	3
          -  .					00	4
          -  .					0A	5
           					--
    */
#if ModBusUseFunc15!=0    
    if(PaketRX[1]==0x0F)
      {
      //   
      unsigned short AdresBit=(((((unsigned short)PaketRX[2])<<8)|(PaketRX[3])));
      //   
      unsigned short KolvoBit=(((((unsigned short)PaketRX[4])<<8)|(PaketRX[5])));
      //    
      if(((AdresBit+KolvoBit)>ModBusMaxOutBit) || (KolvoBit>ModBusMaxOutBitRX))
        {// 
        CRCmodbus=0xFFFF; //   CRC
        return;//,    
        }
      // 
      unsigned char Bit=(AdresBit&7);//   ModBusOutBit[]
      AdresBit=AdresBit>>3;//  ModBusOutBit[]
      //  
      for(int i=0;i<KolvoBit;i++)
        {
        if(PaketRX[7+(i>>3)]&(1<<(i&7)))//   PaketRX  1
          {//   ModBusOutBit[]
          ModBusOutBit[AdresBit].byte=(ModBusOutBit[AdresBit].byte)|((unsigned char)(1<<Bit));
          }
        else
          {//  ModBusOutBit[]
          ModBusOutBit[AdresBit].byte=(ModBusOutBit[AdresBit].byte)&((unsigned char)(~(1<<Bit)));
          }
        //  
        Bit++;if(Bit==8){Bit=0;AdresBit++;}
        }           
      // CRC    
      CRCmodbus=0xFFFF;
      for(int i=0;i<6;i++)
        {
        ModBusPUT(PaketRX[i]);
        CRCmodbus=CRCfunc(CRCmodbus,(PaketRX[i]));
        }
      ModBusPUT(CRCmodbus);
      ModBusPUT(CRCmodbus>>8);
          
      ModBus2PrgOutBit();//   (ModBus->GlobalDate)
      
      //
      CRCmodbus=0xFFFF; //   CRC
      return;//   
      }
#endif     
    //  0x10   / .
    /*16 (10 Hex) Preset Multiple Regs 
           
               ( 4). 
            ,        . 
           
                . 
           
              .     0.
                   . 
           M84  484  10- ,       0. 
              16 .
                    40002  00 0A  01 02 Hex, 
             17: 
           
           						
                                                                  (Hex) 
           					11	0
          						10	1
           					00	2
           					01	3
          -  .					00	4
          -  .					02	5
           						04	6
           .						00	7
           .						0A	8
           .						01	9
           .						02	10
           					--
   
           
              ,  ,  ,   . 
    */
#if ModBusUseFunc16!=0     
    if(PaketRX[1]==0x10)
      {
      //   
      unsigned short b=(((((unsigned short)PaketRX[2])<<8)|(PaketRX[3])));
      //   
      unsigned short c=(((((unsigned short)PaketRX[4])<<8)|(PaketRX[5])));
      //    
      if(((b+c)>ModBusMaxOutReg) || c>ModBusMaxOutRegRX || c==0)
        {// 
        CRCmodbus=0xFFFF;//   CRC
        return;//,    
        }
      //     ModBusOutReg[]
      for(int i=0;i<c;i++)
        {
        ModBusOutReg[b+i]=(((unsigned short)PaketRX[7+(i<<1)])<<8)|(PaketRX[8+(i<<1)]);
        }
      // CRC    
      CRCmodbus=0xFFFF;
      for(int i=0;i<6;i++)
        {
        ModBusPUT(PaketRX[i]);
        CRCmodbus=CRCfunc(CRCmodbus,(PaketRX[i]));
        }
      ModBusPUT(CRCmodbus);
      ModBusPUT(CRCmodbus>>8);
      ModBus2PrgOutReg();//   (ModBus->GlobalDate)
      //
      CRCmodbus=0xFFFF; //   CRC
      return;//    
      }
#endif         
    /////////////////////////////////////////////////////////////////////////////
    // 
    CRCmodbus=0xFFFF; //   CRC
    return;////,  ,    
    }
  return;//    
  }

//     
static inline unsigned char Hex2Dig(unsigned char h)
  {
  if((h>='0')&&(h<='9')) return (h -'0');
  if((h>='A')&&(h<='F')) return (h -'A'+10);
  return 0;
  }
static unsigned char LRCmodbus;// LRC
static unsigned char Simvol0;//  
#define ASCII_CR (0x0D)//  
#define ASCII_LF (0x0A)// 
static const unsigned char BCD[]="0123456789ABCDEF";//     

//    ASCII
void ModBusASCII(void)
  {
  if(Sost==0)
    {// 
    while(!0)
      {//  
      unsigned short Tmp=ModBusGET(); //    
      if(Tmp==0) return; //       
      // 
      Tmp=Tmp&0xFF;//   
      //   
      if(Tmp==':')
        {// 
        LRCmodbus=0;// LRC
        UkPaket=0;//  ,   
        continue;//   
        }
       
      //   
      if(!(
           ((Tmp>='0')&&(Tmp<='9'))||
           ((Tmp>='A')&&(Tmp<='F'))||
           (Tmp==ASCII_CR)||
           (Tmp==ASCII_LF)
           )) 
        {
        return;//,    
        }
        
      //  
      if((UkPaket&1)==0)
        {//    0,2,4,6...
        Simvol0=Tmp; //   
        UkPaket++; //  
        continue;//   
        }
      else 
        {//    1,3,5,7...
        if(Tmp!=ASCII_LF)
          {//  
          PaketRX[UkPaket>>1]=(Hex2Dig(Simvol0)<<4)|(Hex2Dig(Tmp));//   
          LRCmodbus=LRCmodbus-PaketRX[UkPaket>>1];// LRC
          UkPaket++;//  
          if(UkPaket>(ModBusMaxPaketRX<<1))//  
            {//  
            UkPaket=0;//  
            return;//,    
            }
          }
        else break;
        }
      }      
    
    // LCR
    if(LRCmodbus!=0) return;//,    
    
    // 
    if((PaketRX[0]!=ModBusID)&&(PaketRX[0]!=ModBusID_FF))
      {//  
      return;//   
      }
      
    //   
    Sost=!0;
    TimModbus=ModBusSysTimer;// 
#if ModBusMaxPauseResp!=0  
    return;//   
#endif  
    }  
  
  ///////////////////////////////////////////////////////////////////////////// 
  if(Sost!=0 
#if ModBusMaxPauseResp!=0     
     && (ModBusSysTimer-TimModbus)>=ModBusMaxPauseResp
#endif     
     )
    {//  
    Sost=0;
    /////////////////////////////////////////////////////////////////////////////    
    //                                                          //
    /////////////////////////////////////////////////////////////////////////////
#if ModBusUseFunc1!=0     
    //01    
    if(PaketRX[1]==0x01)
      {
      //   
      unsigned short AdresBit=(((((unsigned short)PaketRX[2])<<8)|(PaketRX[3])));
      //   
      unsigned short KolvoBit=((((unsigned short)PaketRX[4])<<8)|(PaketRX[5]));
      //    
      if((AdresBit+KolvoBit)>(ModBusMaxOutBit) || KolvoBit>ModBusMaxOutBitTX || KolvoBit==0)
        {//
        return;//,    
        }
      Prg2ModBusOutBit();//   (GlobalDate->ModBus)
      //  
      ModBusPUT(':');
      //
      ModBusPUT(BCD[PaketRX[0]>>4]);//  
      ModBusPUT(BCD[PaketRX[0]&0x0F]);// 
      LRCmodbus=0-PaketRX[0];// LRC
      //     
      ModBusPUT(BCD[1>>4]);//  
      ModBusPUT(BCD[1&0x0F]);// 
      LRCmodbus=LRCmodbus-1;// LRC
      //  
      ModBusPUT(BCD[((KolvoBit+7)>>3)>>4]);//  
      ModBusPUT(BCD[((KolvoBit+7)>>3)&0x0F]);// 
      LRCmodbus=LRCmodbus-((KolvoBit+7)>>3);// LRC
      //    
      unsigned char TxByte=0;// 
      unsigned char Bit=AdresBit&7;//   ModBusOutBit[]
      AdresBit=AdresBit>>3;//  ModBusOutBit[]
      //   ModBusOutBit[]  
      int i=0;
      while(!0)
        {
        if((ModBusOutBit[AdresBit].byte)&(1<<Bit))//   ModBusOutBit[]  1
          {//   
          TxByte=TxByte|(1<<(i&7));
          }
        //  
        Bit++;
        if(Bit==8){Bit=0;AdresBit++;}
        i++;
        if((i&7)==0)
          {
          ModBusPUT(BCD[TxByte>>4]);//  
          ModBusPUT(BCD[TxByte&0x0F]);// 
          LRCmodbus=LRCmodbus-TxByte;// LRC
          TxByte=0;
          if(i==KolvoBit) break; else continue;
          }
        if(i==KolvoBit) 
          {
          ModBusPUT(BCD[TxByte>>4]);//  
          ModBusPUT(BCD[TxByte&0x0F]);// 
          LRCmodbus=LRCmodbus-TxByte;// LRC
          break;
          }
        }
      ModBusPUT(BCD[LRCmodbus>>4]);
      ModBusPUT(BCD[LRCmodbus&0x0F]);
      ModBusPUT(ASCII_CR);
      ModBusPUT(ASCII_LF);
      //
      return;//   
      }
#endif
#if ModBusUseFunc2!=0     
    //02 Read Input Status 
    if(PaketRX[1]==0x02)
      {
      //   
      unsigned short AdresBit=(((((unsigned short)PaketRX[2])<<8)|(PaketRX[3])));
      //   
      unsigned short KolvoBit=((((unsigned short)PaketRX[4])<<8)|(PaketRX[5]));
      //    
      if((AdresBit+KolvoBit)>(ModBusMaxInBit) || KolvoBit>ModBusMaxInBitTX || KolvoBit==0)
        {//
        return;//,    
        }
      Prg2ModBusInBit();//   (GlobalDate->ModBus)
      //  
      ModBusPUT(':');
      //
      ModBusPUT(BCD[PaketRX[0]>>4]);//  
      ModBusPUT(BCD[PaketRX[0]&0x0F]);// 
      LRCmodbus=0-PaketRX[0];// LRC
      //     
      ModBusPUT(BCD[2>>4]);//  
      ModBusPUT(BCD[2&0x0F]);// 
      LRCmodbus=LRCmodbus-2;// LRC
      //  
      ModBusPUT(BCD[((KolvoBit+7)>>3)>>4]);//  
      ModBusPUT(BCD[((KolvoBit+7)>>3)&0x0F]);// 
      LRCmodbus=LRCmodbus-((KolvoBit+7)>>3);// LRC
      //    
      unsigned char TxByte=0;// 
      unsigned char Bit=AdresBit&7;//   ModBusOutBit[]
      AdresBit=AdresBit>>3;//  ModBusOutBit[]
      //   ModBusOutBit[]  
      int i=0;
      while(!0)
        {
        if((ModBusInBit[AdresBit].byte)&(1<<Bit))//   ModBusOutBit[]  1
          {//   
          TxByte=TxByte|(1<<(i&7));
          }
        //  
        Bit++;
        if(Bit==8){Bit=0;AdresBit++;}
        i++;
        if((i&7)==0)
          {
          ModBusPUT(BCD[TxByte>>4]);//  
          ModBusPUT(BCD[TxByte&0x0F]);// 
          LRCmodbus=LRCmodbus-TxByte;// LRC
          TxByte=0;
          if(i==KolvoBit) break; else continue;
          }
        if(i==KolvoBit) 
          {
          ModBusPUT(BCD[TxByte>>4]);//  
          ModBusPUT(BCD[TxByte&0x0F]);// 
          LRCmodbus=LRCmodbus-TxByte;// LRC
          break;
          }
        }
      ModBusPUT(BCD[LRCmodbus>>4]);
      ModBusPUT(BCD[LRCmodbus&0x0F]);
      ModBusPUT(ASCII_CR);
      ModBusPUT(ASCII_LF);
      //
      return;//   
      }
#endif
#if ModBusUseFunc3!=0     
    //03 Read Holding Registers 
    if(PaketRX[1]==0x03)
      {
      //   
      unsigned short AdresWord=(((((unsigned short)PaketRX[2])<<8)|(PaketRX[3])));
      //    
      unsigned short KolvoWord=((((unsigned short)PaketRX[4])<<8)|(PaketRX[5])); 
      //    
      if(((AdresWord+KolvoWord)>ModBusMaxOutReg) || KolvoWord>ModBusMaxOutRegTX)
        {// 
        return;//,    
        }
      Prg2ModBusOutReg();//   (GlobalDate->ModBus)
      //  
      ModBusPUT(':');
      //
      ModBusPUT(BCD[PaketRX[0]>>4]);//  
      ModBusPUT(BCD[PaketRX[0]&0x0F]);// 
      LRCmodbus=0-PaketRX[0];// LRC
      // 
      ModBusPUT(BCD[3>>4]);//  
      ModBusPUT(BCD[3&0x0F]);// 
      LRCmodbus=LRCmodbus-3;// LRC
      //  
      ModBusPUT(BCD[(KolvoWord<<1)>>4]);//  
      ModBusPUT(BCD[(KolvoWord<<1)&0x0F]);// 
      LRCmodbus=LRCmodbus-(KolvoWord<<1);// LRC
      //   ModBusOutReg[]   
      for(int i=0;i<KolvoWord;i++)
        {
        ModBusPUT(BCD[((ModBusOutReg[AdresWord+i])>>8)>>4]);//  
        ModBusPUT(BCD[((ModBusOutReg[AdresWord+i])>>8)&0x0F]);// 
        LRCmodbus=LRCmodbus-((ModBusOutReg[AdresWord+i])>>8);// LRC
        ModBusPUT(BCD[(((ModBusOutReg[AdresWord+i])>>0)>>4)&0x0F]);//  
        ModBusPUT(BCD[(((ModBusOutReg[AdresWord+i])>>0)>>0)&0x0F]);// 
        LRCmodbus=LRCmodbus-((ModBusOutReg[AdresWord+i])>>0);// LRC
        }
      ModBusPUT(BCD[LRCmodbus>>4]);
      ModBusPUT(BCD[LRCmodbus&0x0F]);
      ModBusPUT(ASCII_CR);
      ModBusPUT(ASCII_LF);
      //
      return;//   
      }
#endif
#if ModBusUseFunc4!=0     
    //04 Read Input Registers 
    if(PaketRX[1]==0x04)
      {
      //   
      unsigned short AdresWord=(((((unsigned short)PaketRX[2])<<8)|(PaketRX[3])));
      //    
      unsigned short KolvoWord=((((unsigned short)PaketRX[4])<<8)|(PaketRX[5])); 
      //    
      if(((AdresWord+KolvoWord)>ModBusMaxOutReg) || KolvoWord>ModBusMaxOutRegTX)
        {// 
        return;//,    
        }
      Prg2ModBusInReg();//   (GlobalDate->ModBus)
      //  
      ModBusPUT(':');
      //
      ModBusPUT(BCD[PaketRX[0]>>4]);//  
      ModBusPUT(BCD[PaketRX[0]&0x0F]);// 
      LRCmodbus=0-PaketRX[0];// LRC
      // 
      ModBusPUT(BCD[4>>4]);//  
      ModBusPUT(BCD[4&0x0F]);// 
      LRCmodbus=LRCmodbus-4;// LRC
      //  
      ModBusPUT(BCD[(KolvoWord<<1)>>4]);//  
      ModBusPUT(BCD[(KolvoWord<<1)&0x0F]);// 
      LRCmodbus=LRCmodbus-(KolvoWord<<1);// LRC
      //   ModBusOutReg[]   
      for(int i=0;i<KolvoWord;i++)
        {
        ModBusPUT(BCD[((ModBusInReg[AdresWord+i])>>8)>>4]);//  
        ModBusPUT(BCD[((ModBusInReg[AdresWord+i])>>8)&0x0F]);// 
        LRCmodbus=LRCmodbus-((ModBusInReg[AdresWord+i])>>8);// LRC
        ModBusPUT(BCD[(((ModBusInReg[AdresWord+i])>>0)>>4)&0x0F]);//  
        ModBusPUT(BCD[(((ModBusInReg[AdresWord+i])>>0)>>0)&0x0F]);// 
        LRCmodbus=LRCmodbus-((ModBusInReg[AdresWord+i])>>0);// LRC
        }
      ModBusPUT(BCD[LRCmodbus>>4]);
      ModBusPUT(BCD[LRCmodbus&0x0F]);
      ModBusPUT(ASCII_CR);
      ModBusPUT(ASCII_LF);
      //
      return;//   
      }
#endif
#if ModBusUseFunc5!=0     
    //05 Force Single Coil 
    if(PaketRX[1]==0x05)
      {
      //   
      unsigned short AdresBit=(((((unsigned short)PaketRX[2])<<8)|(PaketRX[3])));
      //     
      if(AdresBit>=ModBusMaxOutBit)//  
        {// 
        return;//,    
        }
      //  
      switch (((((unsigned short)PaketRX[4])<<8)|(PaketRX[5])))
        {
        case 0xFF00:
        // 
        ModBusOutBit[(AdresBit>>3)].byte|=(1<<(AdresBit&7));
        break;
        case 0x0000:
        // 
        ModBusOutBit[(AdresBit>>3)].byte&=(~(1<<(AdresBit&7)));
        break;
        default:
          { //
          return;//,    
          } 
        }
              
      //
      ModBusPUT(':');
      for(int i=0;i<7;i++)
        {
        ModBusPUT(BCD[PaketRX[i]>>4]);//  
        ModBusPUT(BCD[PaketRX[i]&0x0F]);// 
        }
      ModBusPUT(ASCII_CR);
      ModBusPUT(ASCII_LF);
         
      ModBus2PrgOutBit();//   (ModBus->GlobalDate)
      
      //
      return;//    
      }
#endif
#if ModBusUseFunc6!=0     
    //06 Preset Single Register 
    if(PaketRX[1]==0x06)
      {
      //   
      unsigned short AdresWord=(((((unsigned short)PaketRX[2])<<8)|(PaketRX[3])));
      
      //     
      if(AdresWord>=(ModBusMaxOutReg))//  
        {// 
        return;//,    
        }
      // 
      ModBusOutReg[AdresWord]=(((((unsigned short)PaketRX[4])<<8)|(PaketRX[5])));
      
      //
      ModBusPUT(':');
      for(int i=0;i<7;i++)
        {
        ModBusPUT(BCD[PaketRX[i]>>4]);//  
        ModBusPUT(BCD[PaketRX[i]&0x0F]);// 
        }
      ModBusPUT(ASCII_CR);
      ModBusPUT(ASCII_LF);
      
      ModBus2PrgOutReg();//   (ModBus->GlobalDate)
        
      //
      return;//   
      }
#endif
#if ModBusUseFunc15!=0      
    //15 (0F Hex) Force Multiple Coils 
    if(PaketRX[1]==0x0F)
      {
      //   
      unsigned short AdresBit=(((((unsigned short)PaketRX[2])<<8)|(PaketRX[3])));
      //   
      unsigned short KolvoBit=(((((unsigned short)PaketRX[4])<<8)|(PaketRX[5])));
      //    
      if(((AdresBit+KolvoBit)>ModBusMaxOutBit) || (KolvoBit>ModBusMaxOutBitRX))
        {// 
        return;//,    
        }
      // 
      unsigned char Bit=(AdresBit&7);//   ModBusOutBit[]
      AdresBit=AdresBit>>3;//  ModBusOutBit[]
      //  
      for(int i=0;i<KolvoBit;i++)
        {
        if(PaketRX[7+(i>>3)]&(1<<(i&7)))//   PaketRX  1
          {//   ModBusOutBit[]
          ModBusOutBit[AdresBit].byte=(ModBusOutBit[AdresBit].byte)|((unsigned char)(1<<Bit));
          }
        else
          {//  ModBusOutBit[]
          ModBusOutBit[AdresBit].byte=(ModBusOutBit[AdresBit].byte)&((unsigned char)(~(1<<Bit)));
          }
        //  
        Bit++;if(Bit==8){Bit=0;AdresBit++;}
        }           
      
      // LRC    
      LRCmodbus=0;
      ModBusPUT(':');
      for(int i=0;i<6;i++)
        {
        ModBusPUT(BCD[PaketRX[i]>>4]);//  
        ModBusPUT(BCD[PaketRX[i]&0x0F]);// 
        LRCmodbus=LRCmodbus-PaketRX[i];// LRC
        }
      ModBusPUT(BCD[LRCmodbus>>4]);
      ModBusPUT(BCD[LRCmodbus&0x0F]);
      ModBusPUT(ASCII_CR);
      ModBusPUT(ASCII_LF);
      
      ModBus2PrgOutBit();//   (ModBus->GlobalDate)
      
      //
      return;//   
      }
#endif
#if ModBusUseFunc16!=0        
    //16 (10 Hex) Preset Multiple Regs 
    if(PaketRX[1]==0x10)
      {
      //   
      unsigned short b=(((((unsigned short)PaketRX[2])<<8)|(PaketRX[3])));
      //   
      unsigned short c=(((((unsigned short)PaketRX[4])<<8)|(PaketRX[5])));
      
      //    
      if(((b+c)>ModBusMaxOutReg) || c>ModBusMaxOutRegRX)
        {
        // 
        return;//,    
        }
      //     ModBusOutReg[]
      for(int i=0;i<c;i++)
        {
        ModBusOutReg[b+i]=(((unsigned short)PaketRX[7+(i<<1)])<<8)|(PaketRX[8+(i<<1)]);
        }
      
      // LRC    
      LRCmodbus=0;
      ModBusPUT(':');
      for(int i=0;i<6;i++)
        {
        ModBusPUT(BCD[PaketRX[i]>>4]);//  
        ModBusPUT(BCD[PaketRX[i]&0x0F]);// 
        LRCmodbus=LRCmodbus-PaketRX[i];// LRC
        }
      ModBusPUT(BCD[LRCmodbus>>4]);
      ModBusPUT(BCD[LRCmodbus&0x0F]);
      ModBusPUT(ASCII_CR);
      ModBusPUT(ASCII_LF);
      
      ModBus2PrgOutReg();//   (ModBus->GlobalDate)
      
      //
      return;//    
      }
#endif    
    } 
  //
  return;//,  ,    
  }




ModBus2Prg.c
#define __MODBUS2PRG_C
#include "modbus.h"

//  
//       
void Prg2ModBusOutBit(void)
  {//   
  
  return;
  }

void Prg2ModBusInBit(void)
  {//   
  //ModBusInBit[0].bit0=1;
  
  return;
  }

void Prg2ModBusOutReg(void)
  {//  4   /
  
  return;
  }

void Prg2ModBusInReg(void)
  {//  3   
  
  return;
  }

//  
//        
void ModBus2PrgOutBit(void)
  {//   
  
  return;
  }

void ModBus2PrgOutReg(void)
  {//  4   /
  
  return;
  }




modbus.h文件包含必需的声明,编译选项和调整常量。让我们简要描述主要选项和调整参数。



ModBusUseFunc1-ModBusUseFunc15-编译选项,用于确定ModBus协议功能的使用。 ModBus设备的实际实现只能使用一组有限的协议功能,大多数情况下是功能3,6和16。无需在项目中包括额外的代码。



ModBusID,ModBusID_FF -ModBus总线上的地址。协议的这种实现支持两个地址。这对于调试设备很有用,ModBusID地址是可配置的设备地址,而ModBusID_FF地址是用于自定义设备的地址。



ModBusMaxPause-在ModBusSysTimer量子中设置字符之间的停顿,以确定数据包的开始。通常,ModBusSysTimer量为1ms。对于大多数应用程序,完全不可能遵守协议标准中描述的超时。



例如,在Win-machine上运行的ModBus Master将永远无法提供协议所需的超时。因此,将时间片设置为小于1 mS可能被认为是不切实际的。实际观察表明,ModBusMaxPause值应约为5-10 mS。



ModBusMaxPauseResp-主机请求和从机响应之间的暂停。许多ModBus Master设备在从发送到接收的切换中存在延迟,可以通过此常数来补偿此延迟。



ModBusMaxInBit,ModBusMaxOutBit,ModBusMaxInReg,ModBusMaxOutReg-离散输入,输出,用于读取的寄存器,用于读取/写入的寄存器的数量。该程序为ModBus寄存器保留内存。如果未使用某种类型的寄存器,则该值必须指定为零。



ModBusMaxInBitTX,ModBusMaxOutBitTX,ModBusMaxInRegTX,ModBusMaxOutRegTX-传输的数据包中离散输入,输出,读取寄存器,读取/写入输出寄存器的最大数量。此设置必须与ModBus Master上的相应设置匹配。



要将库移植到任何平台,必须通过宏指定三个函数。



ModBusSysTimer-系统计时器,该变量在单独的执行线程中每毫秒增加一次。此变量可以是STM32 HAL库中的uwTick,也可以是标准C函数clock()



ModBusPUT(无符号字符A) -将字节写入串行流。



无符号的短ModBusGET(无效) -从串行流中读取一个字节。如果串行流中没有数据,则函数返回0,如果有数据,则返回值为高字节0x01,低字节为读取数据。



要使用该库,您需要填写Prg2ModBusOutBit(),Prg2ModBusInBit(),Prg2ModBusOutReg(),Prg2ModBusInReg()函数的主体负责将用户变量复制到ModBus寄存器。另外,有必要填写



ModBus2PrgOutBit()和ModBus2PrgOutReg()函数的主体,这些函数负责将ModBus寄存器复制到用户变量。在这些函数的主体中,您可以执行一些与更改寄存器有关的操作,例如,检查有效值。



例如:



void Prg2ModBusOutReg(void)
  {// , 4   /
  ModBusOutReg[0]=A;
  ModBusOutReg[1]=B;
  ModBusOutReg[2]=C;
  return;
  }
void ModBus2PrgOutReg(void)
  { //  4,   /
  if(ModBusOutReg[0] < MaxA) A= ModBusOutReg[0];
  B=ModBusOutReg[1];
  C=ModBusOutReg[2];
  return;
  }


在使用ModBusUseGlobal选项的同时,可以不填写指定函数的主体,而直接使用寄存器



要初始化ModBus设备,请调用ModBusIni()函数。所述MODBUSRTU()ModBusASCII()函数通过RTU和ASCII协议分别提供所述装置的操作,。必须在程序的主循环中调用它们:



ModBusIni();
while(!0)
  {
  if(ModBusTip==RTU) ModBusRTU(); else ModBusASCII();
  }


不要忘记,在初始化和调用确保ModBus设备操作的函数之前,您需要注意初始化串行流(UART)。与流I / O的组织有关的软件决策取决于硬件平台,其考虑不在本文的讨论范围之内。



该库已在各种基于PIC和STM32微控制器的设备中与Kepware OPC服务器,SIMATIC和Wientek面板以及其他ModBus Masters进行了测试,显示出142%的性能。易于移植该库将使其易于适应其他类型的8-16-32位微控制器。



All Articles