这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » FPGA » dsp 做的modbus rtu 主从站协议

共3条 1/1 1 跳转至

dsp 做的modbus rtu 主从站协议

助工
2014-12-21 10:19:29     打赏

modbus RTU 协议:先后做1,3,15,16四个命令码,有主从站协议解析。


 


//---------------------------------------------------------------------------
// FILE: ModbusRTU.c
// 程序分两部分:串口操作:中断接收和发送,采用缓冲区发送
//    协议处理:分主战和从站两部分,具体的站需要宏定义指定。
//---------------------------------------------------------------------------
//  Ver | dd mmm yyyy | Who  | Description of changes
// =====|=============|======|===============================================
//  1.00| 2 Nov 2007 | WXJ  |  start version--03,16两命令分别读写内部寄存器
//
//
//
//---------------------------------------------------------------------------
// Load DSP lib
#include "DSP281x_Device.h"
#include "DSP281x_Examples.h"  
// Load system lib
#include "EBC_Universal.H"
//------------MODBUS CMD-----------------------
#define READ_N_COIL      01 
#define READ_N_DI        02 
#define READ_HLD_REG    03 
#define READ_AI         04 
#define SET_1_COIL       05 
#define SET_1_HLD_REG    06 
#define SET_N_COIL       15
#define SET_N_HLD_REG  16
//------------UART_MODULE.Status---------------
#define IDLE_WAIT       0x00        // 空闲态,等待起始位
#define RECE_START       0x01        // 收到起始位,等待结束位
#define RECE_END         0x02        // 收到结束位,等待发送
#define SEND_START       0x03        // 发送起始位
#define SEND_END        0x04        // 发送完毕
#define SEND_EXCHANGE  0x05  // 发送内容切换(读/写,站1/站2)
//------------主从站协议选择-------------------
#ifdef DSP_EXT
#define MODBUS_SLAVE 
#else
#define MODBUS_MASTER
#endif
//---------------------------------------------
//[j]:i--(从站号-1);j--对应从站号通讯起始地址的偏移量
Uint16 WRData[2][100];     //从站1(HMI):500-599; 从站2(DSP2):600-699  
Uint16 REData[2][100];     //从站1(HMI):700-799; 从站2(DSP2):800-899 
Uint16 REDate[2][100];     //从站1(HMI):700-799; 从站2(DSP2):800-899 
Uint16 WRBit[2][20];     //从站1(HMI):000-320; 从站2
Uint16 REBit[2][20];     //从站1(HMI):400-720; 从站2
volatile struct MODBUS_MODULE ModbusModule;
//---------------------------------------------
void ConfigureModbus(void);
Uint16 RTUFrameAnalyse(Uint16  *dest_p);
void  ConstructFrame_RTUReadHldReg( Uint16 board_adr,Uint16 start_address,Uint16 lenth);
void  ConstructFrame_RTUReadNCoil( Uint16 board_adr,Uint16 start_address,Uint16 lenth); 
void  ConstructFrame_RTUSetNHldReg( Uint16 board_adr,Uint16 *com_buf,Uint16 start_address,Uint16 lenth);
void  ConstructFrame_RTUSetNCoil( Uint16 board_adr,Uint16 *com_buf,Uint16 start_address,Uint16 lenth);  
//---------------------------------------------
//  程序第一部分:串口程序
// 串口初始化
// 串口收发数据
//---------------------------------------------
#pragma CODE_SECTION(ScibRxInt, "ramfuncs");
#pragma CODE_SECTION(ScibTxInt, "ramfuncs");
//---------------------------------------------
//---------------------------------------------
void ConfigureModbus (void)
{
 Uint16 i;


 for(i=0;i<100;i++){
  WRData[0]=0;
  WRData[1]=0;
  REData[0]=0;
  REData[1]=0;
  REDate[0]=0;
  REDate[1]=0;
 }
 for(i=0;i<20;i++){
  WRBit[0]=0;
  REBit[0]=0;
  WRBit[1]=0;
  REBit[1]=0;
 }
    for( i = 0;i < 256 ;i++ )
    {
        ModbusModule.Buf = 0;
    }
    ModbusModule.TxLen  = 0;
    ModbusModule.RxLen  = 0; 
    ModbusModule.Point  = 0;
 ModbusModule.ReTryTime =0;
 ModbusModule.TimeoutReg =0;
 ModbusModule.Tbl_SET1 =0;
 ModbusModule.Tbl_READ1 =0;
 ModbusModule.Tbl_SET2 =0;
 ModbusModule.Tbl_READ2 =0;
 ModbusModule.Tbl_COIL_SET1=0;
 ModbusModule.Tbl_COIL_READ1=0;
 #ifdef MODBUS_MASTER
 ModbusModule.ID  = 1;
 ModbusModule.FunCode= SET_N_COIL;
 ModbusModule.RegAddr= 400;
 ModbusModule.RegNum = 320;
    ModbusModule.Status = IDLE_WAIT;
 #endif
 #ifdef MODBUS_SLAVE
 ModbusModule.ID  = 2;
 ModbusModule.Status = SEND_END;
 #endif


 PieCtrlRegs.PIEIER9.bit.INTx3=1; //SCIRXINTB
    PieCtrlRegs.PIEIER9.bit.INTx4=1; //SCITXINTB
 IER |= M_INT9;


}
//---------------------------------------------
//---------------------------------------------
interrupt void ScibTxInt (void)      // SCI-B
{
 PieCtrlRegs.PIEACK.bit.ACK9 = 1;
 if( ModbusModule.TxLen > 0 ){
            ScibRegs.SCITXBUF= ModbusModule.Buf[ModbusModule.Point++];
            ModbusModule.TxLen--;
//            ModbusModule.Point++;
//            ModbusModule.Point %= 128; //
 }else{  //发送完毕
            ModbusModule.Status = SEND_END;   //状态切换
   ModbusModule.Point=0;
   ModbusModule.TimeoutReg=0;
    }
}


//---------------------------------------------
// ScibRxInt MODBUS RTU
// 以两字符时间停顿为3.5个字符时间
// 程序用5ms时间判断 对应9600--5个字符时间
// 程序帧结束数据在主程序里面处理
//---------------------------------------------
interrupt void ScibRxInt (void)      // SCI-B
{
 Uint16  temp;
 PieCtrlRegs.PIEACK.bit.ACK9 = 1; //ACK复位
 temp=ScibRegs.SCIRXBUF.all;
 
 switch( ModbusModule.Status ){
  case SEND_END:      //4
   ModbusModule.Status = RECE_START;
   ModbusModule.Point=0;
  case RECE_START:     //1
   ModbusModule.Buf[ModbusModule.Point] = temp;
   ModbusModule.Point++;
   ModbusModule.RxLen = ModbusModule.Point;
   break;
 }
 ModbusModule.TimeoutReg=0;
}
//---------------------------------------------
//  程序第二部分:MODBUS 协议解析与构造
// CRC16
// 协议帧构造
// 协议帧解析
//---------------------------------------------
//---------------------------------------------
// CRC16 calculate
// <-Modbus Protocol English pdf 
// ptr calculate start point
// len calculate data length
//---------------------------------------------
Uint16 GetCRC16 (Uint16 volatile * ptr,Uint16 len) 

 Uint16 i; 
    Uint16 crc=0xFFFF; 
    if(len==0){ 
     len=1; 
    }
    while(len--){   
  crc^=(*ptr); 
        for(i=0; i<8; i++){ 
            if(crc&1){ 
    crc>>=1;  
    crc^=0xA001; 
   }else{ 
    crc>>=1;
   }                            
     } 
        ptr++; 
    } 
    return(crc);
}
#ifdef MODBUS_MASTER
//---------------------------------------------
// RTU Read Hold Register
// CMD=03 READ_HLD_REG
// Constructe Frame 
//---------------------------------------------
void  ConstructFrame_RTUReadHldReg ( Uint16 board_adr,Uint16 start_address,Uint16 lenth)  

 Uint16 i=0,j=0;
    
    ModbusModule.Buf[i++] = board_adr; 
    ModbusModule.Buf[i++] = READ_HLD_REG; 
    ModbusModule.Buf[i++] = WORD_HI(start_address); 
    ModbusModule.Buf[i++] = WORD_LO(start_address); 
    ModbusModule.Buf[i++] = WORD_HI(lenth); 
    ModbusModule.Buf[i++] = WORD_LO(lenth); 
 j=GetCRC16(ModbusModule.Buf,i);
 ModbusModule.Buf[i++] = WORD_LO(j);
 ModbusModule.Buf[i++] = WORD_HI(j);
 ModbusModule.TxLen    = i;
 ModbusModule.Point   = 0;

//---------------------------------------------
// RTU Read Coil Status
// CMD=01 READ_COIL_STATUS
// Constructe Frame 
//---------------------------------------------
void  ConstructFrame_RTUReadNCoil ( Uint16 board_adr,Uint16 start_address,Uint16 lenth)  
{
 Uint16 i=0,j=0;
 ModbusModule.Buf[i++] = board_adr; 
    ModbusModule.Buf[i++] = READ_N_COIL; 
    ModbusModule.Buf[i++] = WORD_HI(start_address); 
    ModbusModule.Buf[i++] = WORD_LO(start_address); 
    ModbusModule.Buf[i++] = WORD_HI(lenth); 
    ModbusModule.Buf[i++] = WORD_LO(lenth); 
 j=GetCRC16(ModbusModule.Buf,i);
 ModbusModule.Buf[i++] = WORD_LO(j);
 ModbusModule.Buf[i++] = WORD_HI(j);
 ModbusModule.TxLen    = i;
 ModbusModule.Point   = 0;
}
//---------------------------------------------
// RTU Set N Hold Register
// CMD=16 SET_N_HLD_REG
// Constructe Frame 
//---------------------------------------------
void  ConstructFrame_RTUSetNHldReg ( Uint16 board_adr,Uint16 *com_buf,Uint16 start_address,Uint16 lenth) 

 Uint16 i=0,j=0;
 
    ModbusModule.Buf[i++] = board_adr; 
    ModbusModule.Buf[i++] = SET_N_HLD_REG; 
    ModbusModule.Buf[i++] = WORD_HI(start_address); 
    ModbusModule.Buf[i++] = WORD_LO(start_address); 
    ModbusModule.Buf[i++] = WORD_HI(lenth); 
    ModbusModule.Buf[i++] = WORD_LO(lenth); 
 ModbusModule.Buf[i++] = lenth<<1;
 for(j=0;j<lenth;j++){
  ModbusModule.Buf[i++] = WORD_HI( * (com_buf+j) );
  ModbusModule.Buf[i++] = WORD_LO( * (com_buf+j) );
 }
 j=GetCRC16(ModbusModule.Buf,i);
 ModbusModule.Buf[i++] = WORD_LO(j);
 ModbusModule.Buf[i++] = WORD_HI(j);
 ModbusModule.TxLen    = i;
 ModbusModule.Point   = 0;
}
//---------------------------------------------
// RTU Set N Coil Status
// CMD=16 SET_N_COIL_STATUS
// Constructe Frame 
//---------------------------------------------
void  ConstructFrame_RTUSetNCoil ( Uint16 board_adr,Uint16 *com_buf,Uint16 start_address,Uint16 lenth)  

 Uint16 i=0,j=0,byte_num=0,word_num=0;
 
    ModbusModule.Buf[i++] = board_adr; 
    ModbusModule.Buf[i++] = SET_N_COIL; 
    ModbusModule.Buf[i++] = WORD_HI(start_address); 
    ModbusModule.Buf[i++] = WORD_LO(start_address); 
    ModbusModule.Buf[i++] = WORD_HI(lenth); 
    ModbusModule.Buf[i++] = WORD_LO(lenth); 
 byte_num     =(lenth+7)>>3;
 word_num     =byte_num>>1;
 ModbusModule.Buf[i++] = byte_num; 
 for(j=0;j<word_num;j++){
  ModbusModule.Buf[i++] = WORD_LO( * (com_buf+j) );
  ModbusModule.Buf[i++] = WORD_HI( * (com_buf+j) );
 }
 if(byte_num&BIT0){
  ModbusModule.Buf[i++] = WORD_LO( * (com_buf+j) );
 }
 j=GetCRC16(ModbusModule.Buf,i);
 ModbusModule.Buf[i++] = WORD_LO(j);
 ModbusModule.Buf[i++] = WORD_HI(j);
 ModbusModule.TxLen    = i;
 ModbusModule.Point   = 0;
}


//---------------------------------------------
// RTU  主站接收分析  
// 3 READ_HLD_REG
// 16 SET_N_HLD_REG
// 返回值: 0  OK
//    1 CRC校验错误
//    2 站号不匹配 
//    3 功能码不匹配
//    4 16回应地址不匹配
//    5 16回应数据字数不匹配
//---------------------------------------------
Uint16 RTUMasterFrameAnalyse (Uint16  *dest_p) 
{
 Uint16 i;
 Uint16 crc_result, crc_tmp;
 Uint16 RegAddr,RegNum;
 Uint16 rx_byte_num;


 crc_tmp  = ModbusModule.Buf[ModbusModule.RxLen-1]<<8;
    crc_tmp += ModbusModule.Buf[ModbusModule.RxLen-2];
 crc_result=GetCRC16(ModbusModule.Buf,ModbusModule.RxLen-2);
    if ( crc_tmp != crc_result )       // CRC 校验正确 
    { 
        return 1; 
    }
 if ( ModbusModule.ID != ModbusModule.Buf[0] ){
  return 2;
 }
 if ( ModbusModule.FunCode != ModbusModule.Buf[1] ){
  return 3;
 }
 switch (ModbusModule.FunCode){
  case READ_N_COIL: //1
   rx_byte_num=ModbusModule.Buf[2];
   for ( i=0; i<rx_byte_num; i+=2){ 
    *(dest_p + i/2) = ( ModbusModule.Buf[i+4]<<8 ) + ModbusModule.Buf[i+3];
        }
   if(rx_byte_num&BIT0){
    *(dest_p + i/2) &=0xFF00;
    *(dest_p + i/2) |=ModbusModule.Buf[i+3]&0xFF; //low 8 bit renew
   }
   break;      
  case READ_HLD_REG: //3
//   if ( !(SysSta&ComRecept) ){
    for ( i=0; i<ModbusModule.Buf[2]; i+=2){ 
     *(dest_p + i/2) = ( ModbusModule.Buf[i+3]<<8 ) + ModbusModule.Buf[i+4];
         }
//   }
   break;
  case SET_N_COIL: //15
  case SET_N_HLD_REG: //16
   // RegAddr= ((ModbusModule.Buf[2] - (uint8)Uart0.Addr) << 8) + ModbusModule.Buf[3]; // 计算 寄存器首地址
   RegAddr= (ModbusModule.Buf[2]<<8) + ModbusModule.Buf[3];
      RegNum = (ModbusModule.Buf[4]<<8) + ModbusModule.Buf[5];
   if ( RegAddr != ModbusModule.RegAddr ){
    return 4;
   }
   if ( RegNum  != ModbusModule.RegNum ){
    return 5;
   }   
   break;
 }//end switch
 return 0;
}
//---------------------------------------------
// ModbusRTUMasterRun
// 主战先发起通讯,发送16(写),然后接收完毕,解析后发送3(读)然后接收完毕,解析(对从站1操作)
// 对从站2进行类似操作。然后循环。
//
//---------------------------------------------
void ModbusRTUMasterRun ()
{
 switch (ModbusModule.Status){
  case IDLE_WAIT ://0
   if (ModbusModule.TimeoutReg>=5){   //重发延时一结束符以上(3.5字符周期)
     if (!(SysSta&InitSub1) ){
      if(ModbusModule.FunCode ==SET_N_COIL){
        ModbusModule.ID=1;
        ModbusModule.FunCode =SET_N_COIL;
        ModbusModule.RegAddr=400;
        ModbusModule.RegNum=320;
        ConstructFrame_RTUSetNCoil(ModbusModule.ID,&REBit[ModbusModule.ID-1][0],ModbusModule.RegAddr,ModbusModule.RegNum);
//       }
      }else if (ModbusModule.FunCode ==SET_N_HLD_REG){
       ModbusModule.ID=1;
       ModbusModule.FunCode =SET_N_HLD_REG;
       ModbusModule.RegAddr=700;
       ModbusModule.RegNum=100;
       ConstructFrame_RTUSetNHldReg(ModbusModule.ID,&REDate[ModbusModule.ID-1][0],ModbusModule.RegAddr,ModbusModule.RegNum);
      }
     }else if( ModbusModule.FunCode == SET_N_HLD_REG ){ 
      ConstructFrame_RTUSetNHldReg(ModbusModule.ID,&WRData[ModbusModule.ID-1][0],ModbusModule.RegAddr,ModbusModule.RegNum);
     }else if ( ModbusModule.FunCode == READ_HLD_REG ){
      ConstructFrame_RTUReadHldReg(ModbusModule.ID,ModbusModule.RegAddr,ModbusModule.RegNum);
     }else if( ModbusModule.FunCode == SET_N_COIL ){ 
      ConstructFrame_RTUSetNCoil(ModbusModule.ID,&WRBit[ModbusModule.ID-1][0],ModbusModule.RegAddr,ModbusModule.RegNum);
     }else if ( ModbusModule.FunCode == READ_N_COIL ){
      ConstructFrame_RTUReadNCoil(ModbusModule.ID,ModbusModule.RegAddr,ModbusModule.RegNum);
     }
    ScibRegs.SCITXBUF = ModbusModule.Buf[ModbusModule.Point++];
    ModbusModule.TxLen--;
    ModbusModule.Status = SEND_START;  
   }
   break;
  case SEND_START ://3
   asm(" nop");
   break;
  case SEND_END ://4
   if (ModbusModule.TimeoutReg>=10){  //超时500ms(无回应)
    InitSci_B();
    ModbusModule.ReTryTime++;
    ModbusModule.TimeoutReg=0;
    ModbusModule.Status = IDLE_WAIT;
   }
   break;
  case RECE_START ://1
   if (ModbusModule.TimeoutReg>=5){  //接收帧结束
    ModbusModule.Status = RECE_END;
   }
   break;
  case RECE_END ://2
   if( (ModbusModule.FunCode== READ_N_COIL) || (ModbusModule.FunCode== SET_N_COIL)){
    if ( RTUMasterFrameAnalyse(&REBit[ModbusModule.ID-1][0])==0 ){  //接收帧解码正确,清除故障
     if ( (ModbusModule.ID==1) && (ModbusModule.FunCode==SET_N_COIL) ){
      ModbusModule.Tbl_COIL_SET1=0;
     }else if ( (ModbusModule.ID==1) && (ModbusModule.FunCode==READ_N_COIL) ){
      ModbusModule.Tbl_COIL_READ1=0;
     }
     ModbusModule.ReTryTime=0;   //重试次数清0
     ModbusModule.Status = SEND_EXCHANGE;
    }else{         //接收帧解码有误,重试,重试次数加1
     ModbusModule.ReTryTime++;
     ModbusModule.TimeoutReg=0;
     ModbusModule.Status =IDLE_WAIT;
    }
   }else{
    if ( RTUMasterFrameAnalyse(&REDate[ModbusModule.ID-1][0])==0 ){  //接收帧解码正确,清除故障
     SysSta|=InitSub1;
     if ( (ModbusModule.ID==1) && (ModbusModule.FunCode==SET_N_HLD_REG) ){
      ModbusModule.Tbl_SET1=0;
     }else if ( (ModbusModule.ID==1) && (ModbusModule.FunCode==READ_HLD_REG) ){
      ModbusModule.Tbl_READ1=0;
     }else if ( (ModbusModule.ID==2) && (ModbusModule.FunCode==SET_N_HLD_REG) ){
      ModbusModule.Tbl_SET2=0;
     }else if ( (ModbusModule.ID==2) && (ModbusModule.FunCode==READ_HLD_REG) ){
      ModbusModule.Tbl_READ2=0;
     }
     ModbusModule.ReTryTime=0;   //重试次数清0
     ModbusModule.Status = SEND_EXCHANGE;   
    }else{         //接收帧解码有误,重试,重试次数加1
     ModbusModule.ReTryTime++;
     ModbusModule.TimeoutReg=0;
     ModbusModule.Status =IDLE_WAIT;
    }
   }
   break;
  case SEND_EXCHANGE ://5
   if ( (ModbusModule.ID==1) && (ModbusModule.FunCode==SET_N_HLD_REG) ){
    ModbusModule.ID  = 1;
    ModbusModule.FunCode= READ_HLD_REG;
    ModbusModule.RegAddr= 700;
    ModbusModule.RegNum = 100;
   }else if ( (ModbusModule.ID==1) && (ModbusModule.FunCode==READ_HLD_REG) ){
    ModbusModule.ID  = 1;
    ModbusModule.FunCode= SET_N_COIL;
    ModbusModule.RegAddr= 00;
    ModbusModule.RegNum = 320;
   }else if ( (ModbusModule.ID==1) && (ModbusModule.FunCode==SET_N_COIL) ){
    if (!(SysSta&InitSub1) ){
     ModbusModule.FunCode= SET_N_HLD_REG;
    }else{
     ModbusModule.ID  = 1;
     ModbusModule.FunCode= READ_N_COIL;
     ModbusModule.RegAddr= 400;
     ModbusModule.RegNum = 320;
     }
   }else if ( (ModbusModule.ID==1) && (ModbusModule.FunCode==READ_N_COIL) ){
    ModbusModule.ID  = 2;
    ModbusModule.FunCode= SET_N_HLD_REG;
    ModbusModule.RegAddr= 600;
    ModbusModule.RegNum = 100;
   }else if ( (ModbusModule.ID==2) && (ModbusModule.FunCode==SET_N_HLD_REG) ){
    ModbusModule.ID  = 2;
    ModbusModule.FunCode= READ_HLD_REG;
    ModbusModule.RegAddr= 800;
    ModbusModule.RegNum = 100;
   }else if ( (ModbusModule.ID==2) && (ModbusModule.FunCode==READ_HLD_REG) ){
    ModbusModule.ID  = 1;
    ModbusModule.FunCode= SET_N_HLD_REG;
    ModbusModule.RegAddr= 500;
    ModbusModule.RegNum = 100;
   }
   ModbusModule.TimeoutReg=0;  //延时一结束帧判断时间
   ModbusModule.Status = IDLE_WAIT;
   break;
  default :
   break;
 }
 if(ModbusModule.ReTryTime>=5){  //重试次数到达上限,报错,切换发送
  if ( (ModbusModule.ID==1) && (ModbusModule.FunCode==SET_N_HLD_REG) ){
   ModbusModule.Tbl_SET1=1;
  }else if ( (ModbusModule.ID==1) && (ModbusModule.FunCode==READ_HLD_REG) ){
   ModbusModule.Tbl_READ1=1;
  }else if ( (ModbusModule.ID==2) && (ModbusModule.FunCode==SET_N_HLD_REG) ){
   ModbusModule.Tbl_SET2=1;
  }else if ( (ModbusModule.ID==2) && (ModbusModule.FunCode==READ_HLD_REG) ){
   ModbusModule.Tbl_READ2=1;
  }else if ( (ModbusModule.ID==1) && (ModbusModule.FunCode==SET_N_COIL) ){
   ModbusModule.Tbl_COIL_SET1=1;
  }else if ( (ModbusModule.ID==1) && (ModbusModule.FunCode==READ_N_COIL) ){
   ModbusModule.Tbl_COIL_READ1=1;
  }
  if (SysSta&InitSub1){
   ModbusModule.Status = SEND_EXCHANGE;
  }
  ModbusModule.ReTryTime=0;
 }
}
#endif 
#ifdef MODBUS_SLAVE
//---------------------------------------------
// RTU Set N Hold Register
// CMD=16 SET_N_HLD_REG
// Constructe Answer Frame 
//---------------------------------------------
void  ModbusSlaveSetNHldRegAnswer ( Uint16 board_adr,Uint16 start_address,Uint16 lenth)  
{
 Uint16 i=0,j=0;
 
    ModbusModule.Buf[i++] = board_adr; 
    ModbusModule.Buf[i++] = SET_N_HLD_REG; 
    ModbusModule.Buf[i++] = WORD_HI(start_address); 
    ModbusModule.Buf[i++] = WORD_LO(start_address); 
    ModbusModule.Buf[i++] = WORD_HI(lenth); 
    ModbusModule.Buf[i++] = WORD_LO(lenth); 
 j=GetCRC16(ModbusModule.Buf,i);
 ModbusModule.Buf[i++] = WORD_LO(j);
 ModbusModule.Buf[i++] = WORD_HI(j);
 ModbusModule.TxLen    = i;
 ModbusModule.Point   = 0;
}
//---------------------------------------------
// RTU Read Hold Register
// CMD=03 READ_HLD_REG
// Constructe Answer Frame 
//---------------------------------------------
void  ModbusSlaveReadHldRegAnswer ( Uint16 board_adr,Uint16 *com_buf,Uint16 lenth)
{
 Uint16 i=0,j=0;
 
    ModbusModule.Buf[i++] = board_adr; 
    ModbusModule.Buf[i++] = READ_HLD_REG; 
 ModbusModule.Buf[i++] = lenth<<1;
 for(j=0;j<lenth;j++){
  ModbusModule.Buf[i++] = WORD_HI( * (com_buf+j) );
  ModbusModule.Buf[i++] = WORD_LO( * (com_buf+j) );
 }
 j=GetCRC16(ModbusModule.Buf,i);
 ModbusModule.Buf[i++] = WORD_LO(j);
 ModbusModule.Buf[i++] = WORD_HI(j);
 ModbusModule.TxLen    = i;
 ModbusModule.Point   = 0;
}
//---------------------------------------------
// RTU  从站接收分析  
// 3 READ_HLD_REG
// 16 SET_N_HLD_REG
// 返回值: 0  OK
//    1 CRC校验错误
//    2 站号不匹配 
//    4 16写地址不匹配
//    5 16写数据字数不匹配
//---------------------------------------------
Uint16 RTUSlaveFrameAnalyse (Uint16  *dest_p) 
{
 Uint16 i;
 Uint16 crc_result, crc_tmp;
 Uint16 RegAddr,RegNum;


 crc_tmp  = ModbusModule.Buf[ModbusModule.RxLen-1]<<8;
    crc_tmp += ModbusModule.Buf[ModbusModule.RxLen-2];
 crc_result=GetCRC16(ModbusModule.Buf,ModbusModule.RxLen-2);
    if ( crc_tmp != crc_result )       // CRC 校验正确 
    { 
        return 1; 
    }
 if ( ModbusModule.ID != ModbusModule.Buf[0] ){
  return 2;
 }
// if ( ModbusModule.FunCode != ModbusModule.Buf[1] ){
//  return 3;
// }
 ModbusModule.FunCode=ModbusModule.Buf[1];
 switch (ModbusModule.FunCode){      
  case READ_HLD_REG: //3
//   for ( i=0; i<ModbusModule.Buf[2]; i+=2){ 
//    *(dest_p + i/2) = ( ModbusModule.Buf[i+3]<<8 ) + ModbusModule.Buf[i+4];
//        }
//   RegAddr= (ModbusModule.Buf[2]<<8) + ModbusModule.Buf[3];
//      RegNum = (ModbusModule.Buf[4]<<8) + ModbusModule.Buf[5];
   ModbusSlaveReadHldRegAnswer(ModbusModule.ID,&WRData[0][0],100);
   break;
  case SET_N_HLD_REG: //16
   // RegAddr= ((ModbusModule.Buf[2] - (uint8)Uart0.Addr) << 8) + ModbusModule.Buf[3]; // 计算 寄存器首地址
   RegAddr= (ModbusModule.Buf[2]<<8) + ModbusModule.Buf[3];
      RegNum = (ModbusModule.Buf[4]<<8) + ModbusModule.Buf[5];
   if ( (RegNum<<1) != ModbusModule.Buf[6] ){ //字节长度是否匹配
    return 4;
   }
   if ( RegAddr != 600 ){      //对应从站2固定的起始地址(自定义)
    return 5; 
   }
   for ( i=0; i<ModbusModule.Buf[6]; i+=2){ 
    *(dest_p + i/2) = ( ModbusModule.Buf[i+7]<<8 ) + ModbusModule.Buf[i+8];
        }
        ModbusSlaveSetNHldRegAnswer(ModbusModule.ID,RegAddr,RegNum);    
   break;
 }//end switch
 return 0;
}


//---------------------------------------------
// ModbusRTUSlaveRun
// 通讯由主站发起,从站初始化为接收,并相应的做出回应。
// 站号在初始化中有设置,以后不再更改。
//---------------------------------------------
void ModbusRTUSlaveRun (void) 
{


 switch (ModbusModule.Status){
  case IDLE_WAIT ://0
   ScibRegs.SCITXBUF = ModbusModule.Buf[ModbusModule.Point++];
   ModbusModule.TxLen--;
   ModbusModule.Status = SEND_START;
   break;
  case SEND_START ://3
   asm(" nop");
   break;
  case SEND_END ://4
   if (ModbusModule.TimeoutReg>=10){  //超时10ms
    ModbusModule.ReTryTime++;
    ModbusModule.TimeoutReg=0;
    InitSci_B();
   }
   break;
  case RECE_START ://1
   if (ModbusModule.TimeoutReg>=5){  //接收帧结束
    ModbusModule.Status = RECE_END;
   }
   break;
  case RECE_END ://2
   if ( RTUSlaveFrameAnalyse(&REDate[0][0])==0 ){//帧解析正确
    ModbusModule.Status =IDLE_WAIT;
   }else{          //帧解析不正确
    ModbusModule.Status =SEND_END;
   }
   break;


 }
}
#endif
//---------------------------------------------------------------------------
//     END
//---------------------------------------------------------------------------


专家
2015-05-09 08:00:27     打赏
2楼
好东西,学习了。

高工
2020-06-02 14:38:19     打赏
3楼

学习学习,感谢楼主分享


共3条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]