现在的位置: 首页 > 综合 > 正文

MODBUS RTU简例

2013年10月21日 ⁄ 综合 ⁄ 共 7265字 ⁄ 字号 评论关闭

#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,4读AIAO
       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();
       ModbusModule.Status=IDLE_WAIT;
       
       /*
       if (ModbusModule.TimeoutReg>=10){ //超过10ms
          ModbusModule.TimeoutReg=0;
          //超过10个毫秒重置等待
          ModbusModule.Status=IDLE_WAIT;
       }
       */

    break;

   
}
}

抱歉!评论已关闭.