#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; } } |
|