MODBUS RTU简例
#include "DSP281x_Device.h"
#include "DSP281x_Examples.h" 
#include "ModbusRTU.h"
#include "DSP_CRC.h"


//------------MODBUS FUNCODE-----------------------
#define READ_N_DO 01
#define READ_N_DI 02
#define READ_AO    03
#define READ_AI    04
#define SET_1_DO  05
#define SET_1_AO  06
#define SET_N_DO  15
#define SET_N_AO  16

//定义错误码
#define ERROR_FUNCODE    1    //错误功能码
#define ERROR_ADDR        2    //错误地址
#define ERROR_DATA        3    //错误数据
#define ERROR_FAILURE    4    //从机故障

//------------UART_MODULE.Status---------------
#define IDLE_WAIT        0x00        // 空闲态,等待起始位
#define RECE_START      0x01        // 收到起始位,等待结束位
#define RECE_END        0x02        // 收到结束位,等待发送
#define SEND_START      0x03        // 发送起始位
#define SEND_END        0x04        // 发送完毕

/
/---------------------------------------------
volatile struct MODBUS_MODULE ModbusModule;
//---------------------------------------------
Uint16 RTUFrameAnalyse(Uint16 *dest_p);
void ModbusDefaultInitSci();
void ConstructFrame_RTUReadReg( Uint16 type,Uint16 start_address,Uint16 lenth);
void ConstructFrame_RTUSetNReg( Uint16 type,Uint16 *com_buf,Uint16 start_address,Uint16 lenth);

void ReadSci(volatile Uint16 * buf ,volatile Uint16 * inx);

//---------------------------------------------
//---------------------------------------------

void ConfigureModbus (Uint16 ID,Uint16 SCI)
{
Uint16 i;

    for( i = 0;i < 256 ;i++ )
    {
        ModbusModule.Buf[i] = 0;
    }
    ModbusModule.TxLen = 0;
    ModbusModule.RxLen = 0;
    ModbusModule.TimeoutReg =0;
//现在开始只作为从站使用
ModbusModule.ID = ID;
ModbusModule.Status = IDLE_WAIT;
ModbusModule.SCI = SCI;
ModbusDefaultInitSci(); 
}
//---------------------------------------------

//复位SCI_A
void ModbusDefaultInitSci()
{
    EALLOW;
    GpioMuxRegs.GPGMUX.all |= 0x0030;
    EDIS;
    
    EALLOW;
    GpioMuxRegs.GPFMUX.all |= 0x0030;
    EDIS;
    if(ModbusModule.SCI==0)
    {
      SciaRegs.SCICCR.all = 0x07;
        
      SciaRegs.SCICTL1.all = 0x03;
      SciaRegs.SCICTL2.all = 0x00;
        
        //初始的时候不启动发送中断
      SciaRegs.SCICTL2.bit.TXINTENA =0;
      SciaRegs.SCICTL2.bit.RXBKINTENA =1;
       
      SciaRegs.SCIHBAUD = 0x01;
      SciaRegs.SCILBAUD = 0xe7;
      SciaRegs.SCICCR.all = 0x07;

      SciaRegs.SCIFFTX.all=0xE040;//0xC028;
      SciaRegs.SCIFFRX.all=0x0028;
      SciaRegs.SCIFFCT.all=0x00;

      SciaRegs.SCICTL1.all =0x0023;    // Relinquish SCI from Reset
       
      SciaRegs.SCIFFTX.bit.TXFIFOXRESET=1;
      SciaRegs.SCIFFRX.bit.RXFIFORESET=1;
  }else
  {
    
  }


}
void ResetSci()
{
if(ModbusModule.SCI==0){
  SciaRegs.SCIFFRX.bit.RXFIFORESET=0;
  SciaRegs.SCIFFRX.bit.RXFIFORESET=1;
}else{
  ScibRegs.SCIFFRX.bit.RXFIFORESET=0;
  ScibRegs.SCIFFRX.bit.RXFIFORESET=1;
}

}
void ReadSci(volatile Uint16 * buf ,volatile Uint16 * inx)
  {
if(ModbusModule.SCI==0){
    if(SciaRegs.SCIFFRX.bit.RXFIFST!=0){
    while(SciaRegs.SCIFFRX.bit.RXFIFST!=0)
        {
        buf[(*inx)++]=SciaRegs.SCIRXBUF.all;
        }
        //读到字符
        ModbusModule.TimeoutReg=0;
    }
    }else{
    if(ScibRegs.SCIFFRX.bit.RXFIFST!=0){
    while(ScibRegs.SCIFFRX.bit.RXFIFST!=0)
        {
        buf[(*inx)++]=ScibRegs.SCIRXBUF.all;
        }
        //读到字符
        ModbusModule.TimeoutReg=0;
    }
    }


  }
  void WriteSci()
  {
    int i;
if(ModbusModule.SCI==0){
    for(i = 0;i<ModbusModule.TxLen;i++)
    {
        SciaRegs.SCITXBUF=ModbusModule.Buf[i];
        while(SciaRegs.SCIFFTX.bit.TXFFST==0x10){};
    }
}else{
    for(i = 0;i<ModbusModule.TxLen;i++)
    {
        ScibRegs.SCITXBUF=ModbusModule.Buf[i];
        while(ScibRegs.SCIFFTX.bit.TXFFST==0x10){};
    }
  }

}

//---------------------------------------------
// RTU Set N Hold Register
// CMD=16 SET_N_HLD_REG
// Constructe Answer Frame
//---------------------------------------------

char ModbusSlaveSetNRegAnswer ( Uint16 type,Uint16 start_address,volatile Uint16 * buf,Uint16 lenth) 
{
Uint16 crc=0;

if(ModbusModule.WriteData(type,start_address,lenth,buf)) return ERROR_ADDR;
//多路更改
if(type==SET_N_AO){
    crc=GetCRC16(ModbusModule.Buf,6);
    ModbusModule.Buf[6] = WORD_HI(crc);
    ModbusModule.Buf[7] = WORD_LO(crc);
    ModbusModule.TxLen    = 8;
}else{
    //如果是单个更改,原样返回
    ModbusModule.TxLen    = 8;
}//i+=lenth*2;
return 0;
}
/
/---------------------------------------------
// RTU Read Hold Register
// CMD=03 READ_HLD_REG
// Constructe Answer Frame
//---------------------------------------------
char ModbusSlaveReadRegAnswer ( Uint16 type,Uint16 addr,Uint16 lenth)
{
Uint16 i=0,j=0;

ModbusModule.Buf[i++] = ModbusModule.ID;
ModbusModule.Buf[i++] = type;
ModbusModule.Buf[i++] = lenth<<1;
if(ModbusModule.ReadData(type,addr,lenth,&ModbusModule.Buf[i])) return ERROR_ADDR;
i+=lenth*2;
j=GetCRC16(ModbusModule.Buf,i);
ModbusModule.Buf[i++] = WORD_HI(j);
ModbusModule.Buf[i++] = WORD_LO(j);
ModbusModule.Buf[i] = 0;
ModbusModule.TxLen    = i;
return 0;
}
//---------------------------------------------
// RTU 从站接收分析 
// 3 READ_HLD_REG
// 16 SET_N_HLD_REG
// 返回值: 0 OK
//    1 CRC校验错误
//    2 站号不匹配 
//    4 16写地址不匹配
/
/    5 16写数据字数不匹配
//---------------------------------------------
Uint16 RTUSlaveFrameAnalyse ()
{
Uint16 ErrorFlag=0;
Uint16 crc_result, crc_tmp;
Uint16 RegAddr,RegNum;

crc_tmp = ModbusModule.Buf[ModbusModule.RxLen-2]<<8;
crc_tmp += ModbusModule.Buf[ModbusModule.RxLen-1];
crc_result=GetCRC16(ModbusModule.Buf,ModbusModule.RxLen-2);
//校验错误和站号不对不返回
    if ( crc_tmp != crc_result )      // CRC 校验正确
    {
        return 1;
    }

if ( ModbusModule.ID != ModbusModule.Buf[0] ){
return 2;
}

ModbusModule.FunCode=ModbusModule.Buf[1];
RegAddr= (ModbusModule.Buf[2]<<8) + ModbusModule.Buf[3];
switch (ModbusModule.FunCode){      
case READ_AI:
case READ_AO: //3,4AIAO
      RegNum = (ModbusModule.Buf[4]<<8) + ModbusModule.Buf[5];
      ErrorFlag=ModbusSlaveReadRegAnswer(ModbusModule.FunCode,RegAddr,RegNum);
      //ModbusModule.TxLen=0;
      break;
case SET_1_AO: //0x06 写单个数据
      ErrorFlag=ModbusSlaveSetNRegAnswer(ModbusModule.FunCode,RegAddr,&ModbusModule.Buf[5],1);    
      break;       
case SET_N_AO: //0x10 写数据
        //第六个字节代表长度然后依次跟数据和crc
        RegNum = (ModbusModule.Buf[4]<<8) + ModbusModule.Buf[5];
        if ( (RegNum<<1) != ModbusModule.Buf[6] ){ //字节长度是否匹配
            ErrorFlag= ERROR_DATA; 
        }else{
              ErrorFlag=ModbusSlaveSetNRegAnswer(ModbusModule.FunCode,RegAddr,&ModbusModule.Buf[7],RegNum);    
        }
      break;
    default:
        ErrorFlag=ERROR_FUNCODE;//不支持的命令
  }//end switch
  //这些错误可以返回
  if(ErrorFlag)
  {
      //出现错误,将功能码最高位值1
      ModbusModule.Buf[1] = ModbusModule.Buf[1]|0x80;
    ModbusModule.Buf[2] = ErrorFlag;
    ModbusModule.TxLen=3;
      
  }
return 0;
}

//---------------------------------------------
// ModbusRTUSlaveRun
// 通讯由主站发起,从站初始化为接收,并相应的做出回应。
// 站号在初始化中有设置,以后不再更改。
//---------------------------------------------
void ModbusRTUSlaveRun (void)
{
switch(ModbusModule.Status){
    case IDLE_WAIT: //空闲
    //如果在空闲状态有数据,开始接收
    if(SciaRegs.SCIFFRX.bit.RXFIFST)
        {
        //ResetSci();
          ModbusModule.Status = RECE_START;
        //ModbusModule.TimeoutReg=0;
        }
    break;
    case RECE_START: //正在接收
    //停止时间超过5个毫秒结束
    ReadSci(&ModbusModule.Buf[0],&ModbusModule.RxLen);
    if (ModbusModule.TimeoutReg>=5){ //接收帧结束
         
        ModbusModule.Status = RECE_END;
      }
    break;
    case RECE_END: //接收完毕
      if ( RTUSlaveFrameAnalyse()==0 ){//帧解析正确
            ModbusModule.Status =SEND_START;
        }else{          //帧解析不正确
            ModbusModule.Status =SEND_END;
      }      
      ModbusModule.RxLen = 0;
      break;
    case SEND_START: //开始发送
    WriteSci();
      ModbusModule.Status =SEND_END;
    ModbusModule.TimeoutReg=0;
    break;
    case SEND_END: //发送完毕
      //重置fifo
      ResetSci();
write的返回值      ModbusModule.Status=IDLE_WAIT;
       
      /*
      if (ModbusModule.TimeoutReg>=10){ //超过10ms
          ModbusModule.TimeoutReg=0;
          //超过10个毫秒重置等待
          ModbusModule.Status=IDLE_WAIT;
      }
      */

    break;

   
}
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。