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