📄 modbus.c
字号:
}
return(uchCRCHi << 8 | uchCRCLo);
}
//接收数据报校验
INT8S RecPakChk(INT8U xdata *buf,INT8U LenOfRecPak)
{
INT16U ChkSum;
ChkSum = (INT16U)buf[LenOfRecPak-2] * 256 + (INT16U)buf[LenOfRecPak - 1];
if(CRC16(buf,LenOfRecPak-2) == ChkSum)return 0;
else return -1;
}
//发送数据报校验
void TrPakChk(INT8U xdata *buf,INT8U LenOfTrPak)
{
buf[LenOfTrPak-2] = (CRC16(buf,(LenOfTrPak-2))) >> 8;
buf[LenOfTrPak-1] = CRC16(buf,(LenOfTrPak-2));
}
//返回异常数据报
void RetExpPak(INT8U FntCode,INT8U ExpCode)
{
INT8U xdata buf[5];
buf[0] = PtcData.Dev; /*设备地址*/
buf[1] = 0x80|FntCode; /*功能码*/
buf[2] = ExpCode; /*异常码*/
TrPakChk(buf,5);
WrCom(&COM1,buf,5);
}
//写数据到MODBUS协议控制层
/*
*********************************************************************************************************
* SEND PROTOCOL DATA
*
* Description : This function write data to protocol control layer
* Arguments : FncCode, set function code
* : pData, set protocol data
* : DataByteLen,set the sizeof data
* Returns : None.
*********************************************************************************************************
*/
void WriteDataToPtcLayer(INT8U FncCode, /*设置功能码*/
INT8U xdata *pData, /*设置数据项*/
INT8U DataByteLen) /*设置数据项大小*/
{
INT8U xdata tbuf[512];
tbuf[0] = PtcData.Dev; /*设备地址*/
tbuf[1] = FncCode; /*功能码*/
tbuf[2] = DataByteLen; /*数据字节长度*/
memcpy(&tbuf[3],pData,DataByteLen);
TrPakChk(tbuf,5 + DataByteLen);
WrCom(&COM1,tbuf,5 + DataByteLen);
}
//从MODBUS协议控制层读取数据
/*
*********************************************************************************************************
* RECEIVE PROTOCOL DATA
*
* Description : This function write data to protocol control layer
* Arguments : FncCode, return function code
* : pDataStartAddr, return protocol data address
* : pData, return protocol data
* Returns : return the result of operate.
*********************************************************************************************************
*/
INT8S ReadDataFromPtcLayer(INT8U *pFncCode, /*返回功能码*/
INT16U *pDataStartAddr, /*返回数据地址*/
INT16U *pData) /*返回数据项*/
{
INT8U xdata rbuf[10];
INT8U rlen;
if(RdCom(&COM1,rbuf,&rlen) == 0) /*从串口获取数据*/
{
if(rbuf[0] == PtcData.Dev) /*校验设备地址*/
{
if(RecPakChk(rbuf,rlen) == 0) /*CRC校验*/
{
INT16U i = (INT16U)rbuf[2] * 256 + rbuf[3];
INT16U j = (INT16U)rbuf[4] * 256 + rbuf[5];
*pFncCode = rbuf[1]; /*返回功能码*/
*pDataStartAddr = i;
*pData = j;
switch (rbuf[1])
{
case READ_COIL_STATUS: /*读线圈状态*/
if(i > 3/*遥控通道数18*/) /*返回地址异常码*/
RetExpPak(READ_COIL_STATUS,ILLEGAL_DATA_ADDRESS);
/*返回数据异常码*/
if((j == 0) || ((i + (j - 1) / 8 + 1) > PtcData.nSizeOfDOTbl))
RetExpPak(READ_COIL_STATUS,ILLEGAL_DATA_VALUE);
break;
case READ_INPUT_STATUS: /*读开关输入状态量*/
if(i > 3/*DI通道数24*/) /*返回地址异常码*/
RetExpPak(READ_COIL_STATUS,ILLEGAL_DATA_ADDRESS);
/*返回数据异常码*/
if((j == 0) || ((i + (j - 1) / 8 + 1) > PtcData.nSizeOfDITbl))
RetExpPak(READ_COIL_STATUS,ILLEGAL_DATA_VALUE);
break;
case READ_HOLDING_REGISTERS: /*读保持寄存器*/
if(i > 48/*AI通道数24*/) /*返回地址异常码*/
RetExpPak(READ_COIL_STATUS,ILLEGAL_DATA_ADDRESS);
/*返回数据异常码*/
if((j == 0) || ((i + j * 2) > PtcData.nSizeOfAITbl))
RetExpPak(READ_COIL_STATUS,ILLEGAL_DATA_VALUE);
break;
case READ_INPUT_REGISTERS: /*读输入寄存器*/
if(i > 48/*AI通道数24*/) /*返回地址异常码*/
RetExpPak(READ_COIL_STATUS,ILLEGAL_DATA_ADDRESS);
/*返回数据异常码*/
if((j == 0) || ((i + j * 2) > PtcData.nSizeOfAITbl))
RetExpPak(READ_COIL_STATUS,ILLEGAL_DATA_VALUE);
break;
case FORCE_SINGLE_COIL: /*写单路开关量输出*/
if(i > 18/*DO通道数18*/) /*返回地址异常码*/
RetExpPak(READ_COIL_STATUS,ILLEGAL_DATA_ADDRESS);
else if((j != 0)&&(j != 0xff00)) /*返回数据异常码*/
RetExpPak(READ_COIL_STATUS,ILLEGAL_DATA_VALUE);
else
{
if(j == 0xff00)j = 0xff;
else j = 0;
PtcData.DOCtrl((INT8U)i,(BOOLEAN)j);
WrCom(&COM1,rbuf,rlen);
}
break;
case PRESET_SINGLE_REGISTER: /*写单路寄存器*/
if(i > 18/*AO通道数18*/) /*返回地址异常码*/
RetExpPak(READ_COIL_STATUS,ILLEGAL_DATA_ADDRESS);
else
{
PtcData.AOCtrl((INT8U)i,(INT16U)j);
WrCom(&COM1,rbuf,rlen);
}
break;
case PRESET_MULTIPLE_REGISTERS: /*写多路寄存器*/
if(i > 0x8000/*AO通道数*/) /*返回地址异常码*/
RetExpPak(READ_COIL_STATUS,ILLEGAL_DATA_ADDRESS);
else
{
INT16U xdata buf[100];
memcpy(buf,&rbuf[7],rbuf[6]);
PtcData.MultAOCtrl(buf,rbuf[6]);
TrPakChk(rbuf,8);
WrCom(&COM1,rbuf,8);
}
break;
default:
RetExpPak(READ_COIL_STATUS,ILLEGAL_FUNCTION);
break;
}
return 0;
}
}
}
return -1;
}
//配置DO通道事件触发函数(当DO触发事件发生时,执行此函数关联的用户定义函数)
void DOCfgFnct(void (code *DOSet)(INT8U n,BOOLEAN State))
{
PtcData.DOCtrl = DOSet;
}
//配置寄存器写事件触发函数(当寄存器写事件发生时,执行此函数关联的用户定义函数)
void AOCfgFnct(void (code *AOSet)(INT8U n,INT16U Data))
{
PtcData.AOCtrl = AOSet;
}
//配置多路寄存器写事件触发函数(当寄存器写事件发生时,执行此函数关联的用户定义函数)
void MultAOCfgFnct(void (code *MultAOSet)(INT16U xdata *pBuf,INT16U l))
{
PtcData.MultAOCtrl = MultAOSet;
}
/*
*********************************************************************************************************
* Application layer functions
*********************************************************************************************************
*/
//系统硬件资源初始化
void InitHardWare(void)
{
EA = 0;
InitUart(); /*串口初始化*/
InitTimer0(); /*定时器0初始化*/
EA = 1; /*开中断*/
}
//MODBUS协议处理任务
/*
*********************************************************************************************************
* MODBUS PROTOCOL PROCESS TASK
*
* Description : This function is mainly analyse and process MODBUS protocol command.
* Arguments : None.
* Returns : None
*********************************************************************************************************
*/
void ModBusPtcProcTask()
{
INT8U byFncCode;
INT16U nAddr;
INT16U nData;
if(ReadDataFromPtcLayer(&byFncCode,&nAddr,&nData) == 0)
{
switch (byFncCode)
{
case READ_COIL_STATUS: /*DO*/
WriteDataToPtcLayer(READ_COIL_STATUS,PtcData.pDOTbl,(nData - 1)/8 + 1);
break;
case READ_INPUT_STATUS: /*DI*/
WriteDataToPtcLayer(READ_INPUT_STATUS,PtcData.pDITbl,(nData - 1)/8 + 1);
break;
case READ_HOLDING_REGISTERS: /*AI*/
WriteDataToPtcLayer(READ_HOLDING_REGISTERS,&PtcData.pAITbl[nAddr],nData*2);
break;
case READ_INPUT_REGISTERS: /*AI*/
WriteDataToPtcLayer(READ_INPUT_REGISTERS,&PtcData.pAITbl[nAddr],nData*2);
break;
case FORCE_SINGLE_COIL: /*通道控制功能,驱动层已处理*/
break;
default:
break;
}
}
}
/*
*********************************************************************************************************
* Main Entry
*********************************************************************************************************
*/
#if ESTST
void estst()
{
memset((INT8U volatile xdata *)0x3000,0x55,10);
memset((INT8U volatile xdata *)0x2000,0xAA,3);
memset((INT8U volatile xdata *)0x1000,0x00,3);
if(!cnt)
{
RUNFLG=~RUNFLG;
cnt = 1000;
}
}
#endif
void AR30DOSet(INT8U n,BOOLEAN state)
{
n = n;
if(state == 0xff)DO1 = 1;
else DO1 = 0;
}
void dopusle(INT8U id,INT16U dly) reentrant
{
id = 0x55;;
id = 0x55;;
id = 0x55;;
dly++;
}
void AR30AOSet(INT8U n,INT16U Data)
{
n = n;
XBYTE[0x4000] = Data >> 8;
XBYTE[0x4001] = Data;
dopusle(n,Data);
}
void AR30MultAOSet(INT16U xdata *p,INT16U l)reentrant
{
INT16U v;
l = l;
v = *p++;
v = *p++;
}
void main(void)
{
InitHardWare();
ModBusPtcInit(1, /*设备地址*/
(INT8U volatile xdata *) 0x1000, /*DO表首地址*/
(INT8U volatile xdata *) 0x2000, /*DI表首地址*/
(INT8U volatile xdata *) 0x3000, /*AI表首地址*/
1, /*DO表大小*/
2, /*DI表大小*/
24, /*AI表大小*/
AR30DOSet, /*用户自定义的DO控制函数*/
AR30AOSet, /*用户自定义的AO控制函数*/
AR30MultAOSet /*用户自定义的多路AO控制函数*/
);
for(;;)
{
ModBusPtcProcTask();
#if ESTST
estst();
#endif
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -