📄 modbus.c
字号:
/*
*********************************************************************************************************
* Modbus Protocol Module
*
* (c) Copyright 2006-08-01, XXXXXXXXXXXXXXXXXXXX Corp., ltd,
* All Rights Reserved
*
* V1.00
*
* File : modbus.c
* By : kevin zhu
*********************************************************************************************************
*/
#define MOD_GLOBALS
#define CRC_TBL
#include "modbus.h"
#define ESTST 1
#if ESTST
INT16U cnt=0;
sbit RUNFLG = P1^1;
sbit DO1 = P1^0;
#endif
/*
*********************************************************************************************************
* hardware layer functions
*********************************************************************************************************
*/
//串口寄存器初始化
void InitUart()
{
RCAP2H=BAUDH;
RCAP2L=BAUDL;
T2CON=0x34; /*启动T2,选择T2作波特率发生器*/
T2MOD=0;
SCON=0x50;//0x52
PCON=0x00;
PS = 1;
ES = 1; /*the interrupt enable*/
}
//定时器0寄存器初始化
void InitTimer0()
{
TMOD |= 0x01; /*set timer 1ms when cpu at 11.0592MHz*/
TH0 = Timer0H;
TL0 = Timer0L;
TR0 = 1; /*TR0 is set*/
ET0 = 1; /*the interrupt enable*/
}
//串口中断服务函数
ComIntISR() interrupt 4 using 1
{
EA = 0;
ModBusComDrv();
EA = 1;
}
//定时器0中断服务函数
Timer0IntISR() interrupt 1 using 2
{
ModBusTimer0Drv();
#if ESTST
if(cnt > 0)cnt--;
#endif
}
/*
*********************************************************************************************************
* Communication control layer functions
*********************************************************************************************************
*/
//通信中断处理函数
void ModBusComDrv(void)using 1
{
COM xdata *pCOM;
pCOM = &COM1;
if(TI)
{
TI = 0;
if(pCOM->TrCnt >= pCOM->TrLen)
{
pCOM->TrCnt = 0;
pCOM->TrOk = 1;
}
else
{
SBUF = pCOM->pTrBuf[pCOM->TrCnt++]; /*发送下一个字节*/
}
}
#if REC_TIMEOUT_MOD
if(RI)
{
RI = 0;
pCOM->pRecBuf[pCOM->RecCnt++] = SBUF;
pCOM->RecTimeOutCnt = 0; /*清超时计数器*/
pCOM->RecFstFlg = 1; /*接收到起始字符时,开始计数超时时间*/
}
#else
if(RI)
{
RI = 0;
switch (pCOM->RecStateMachine)
{
case 0:
if(SBUF == PtcData.Dev)
{
pCOM->pRecBuf[0] = SBUF;
pCOM->RecCnt = 0;
pCOM->RecFstFlg = 1; /*启动接收超时计数器*/
pCOM->RecStateMachine = 1;
}
break;
case 1:
pCOM->pRecBuf[1 + pCOM->RecCnt++] = SBUF;
if(7 == pCOM->RecCnt)
{
if(pCOM->pRecBuf[1] != 0x10)
{
pCOM->RecFstFlg = 0; /*清接收超时计数器*/
pCOM->RecTimeOutCnt = 0;
pCOM->RecLen = pCOM->RecCnt + 1;
pCOM->RecOk = 1; /*收到一个完整帧*/
pCOM->RecStateMachine = 0; /*接收状态归零*/
}
else
{ /*如果为0x10命令则继续收*/
pCOM->RecCnt = 0;
pCOM->RecStateMachine = 2;
}
}
break;
case 2:
pCOM->pRecBuf[8 + pCOM->RecCnt++] = SBUF;
if(pCOM->RecCnt == pCOM->pRecBuf[6] + 1)
{
pCOM->RecFstFlg = 0; /*清接收超时计数器*/
pCOM->RecTimeOutCnt = 0;
pCOM->RecLen = pCOM->RecCnt + 8;
pCOM->RecOk = 1; /*收到一个完整帧*/
pCOM->RecStateMachine = 0; /*接收状态归零*/
}
break;
default:
break;
}
}
#endif
}
//定时器0中断处理函数
void ModBusTimer0Drv(void) using 2
{
COM xdata *pCOM;;
TH0=Timer0H;
TL0=Timer0L; /*重置定时器*/
pCOM = &COM1;
#if REC_TIMEOUT_MOD
if(pCOM->RecFstFlg) /*COM1 口接收超时处理*/
{
if(++pCOM->RecTimeOutCnt >= TMROUT_9600BPS) /*此处取接收超时为6ms,在波特率为9600bps时*/
{
pCOM->RecTimeOutCnt = 0;
pCOM->RecFstFlg = 0;
pCOM->RecLen = pCOM->RecCnt;
pCOM->RecCnt = 0;
pCOM->RecOk = 1;
}
}
#else
if(pCOM->RecFstFlg)
{
if(++pCOM->RecTimeOutCnt >= REC_MAX_TMROUT)
{
pCOM->RecTimeOutCnt = 0;
pCOM->RecFstFlg = 0;
pCOM->RecStateMachine = 0; /*接收状态归零*/
}
}
#endif
}
//串口缓冲区初始化
void InitCom(void)
{
COM xdata *pCOM;
pCOM = &COM1;
pCOM->pRecBuf = RecBuf;
pCOM->RecCnt = 0;
pCOM->RecLen = 0;
pCOM->RecFstFlg = 0;
pCOM->RecTimeOutCnt = 0;
pCOM->pTrBuf = TrBuf;
pCOM->TrLen = 0;
pCOM->TrCnt = 0;
pCOM->RecOk = 0;
pCOM->RecStateMachine = 0;
memset(&pCOM->pRecBuf[0],0,MAX_REC_LEN);
memset(&pCOM->pTrBuf[0],0,MAX_SEND_LEN);
pCOM->RecOk = 0;
pCOM->TrOk = 0;
}
//从串口获取数据
INT8S RdCom(COM xdata *pCOM,INT8U xdata* RBuf,INT8U* NumOfDataRecv)
{
if((pCOM->RecOk == 1) && (pCOM->TrCnt == 0))
{
pCOM->RecOk = 0;
*NumOfDataRecv=0;
*NumOfDataRecv=pCOM->RecLen;
memcpy(RBuf,&RecBuf[0],pCOM->RecLen);
return 0;
}
else return -1;
}
//写数据到串口
void WrCom(COM *pCOM,INT8U xdata* WBuf,INT8U NumOfDataTrans)
{
while(pCOM->TrCnt != 0); //等待上一次发送完
memcpy(pCOM->pTrBuf,WBuf,NumOfDataTrans);
pCOM->TrLen = NumOfDataTrans;
pCOM->TrCnt = 1;
SBUF = pCOM->pTrBuf[0];
}
/*
*********************************************************************************************************
* Protocol layer functions
*********************************************************************************************************
*/
/*
* [MODBUS协议数据格式]
* +----------------------------------------+
* | 地址码 | 功能码 | 数据区 | CRC错误校检 |
* +----------------------------------------+
*/
//初始化协议控制层
/*
*********************************************************************************************************
* INIT MODBUS PROTOCOL CONTROL LAYER
*
* Description : This function is used to initialize Modbus protocol control layer data
* Arguments : DevAddr, device address
* : pDO, DO table start address
* : pDI, DI table start address
* : pAI, AI table start address
* : nSizeOfDOTbl, the size of DO table
* : nSizeOfDITbl, the size of DI table
* : nSizeOfAITbl, the size of AI table
* : void (code *DOSet)(INT8U n,BOOLEAN State), DO channal control function defined by user
* : void (code *AOSet)(INT8U n,INT16U Data), AO channal control function defined by user
* : void (code *MultAOSet)(INT8U n,INT16U len), MAO channal control function defined by user
* Returns : None.
*********************************************************************************************************
*/
void ModBusPtcInit(INT8U DevAddr, /*设备地址*/
INT8U xdata *pDO, /*DO表首地址*/
INT8U xdata *pDI, /*DI表首地址*/
INT8U xdata *pAI, /*AI表首地址*/
INT16U nSizeOfDOTbl, /*DO表大小*/
INT16U nSizeOfDITbl, /*DI表大小*/
INT16U nSizeOfAITbl, /*AI表大小*/
/*用户自定义的DO控制函数*/
void (code *DOSet)(INT8U n,BOOLEAN State),
/*用户自定义的AO控制函数*/
void (code *AOSet)(INT8U n,INT16U Data),
/*用户自定义的多路AO控制函数*/
void (code *MultAOCtrl)(INT16U *p,INT16U len)
)
{
DTBL xdata *pDTbl;
InitCom();
pDTbl = &PtcData;
pDTbl->Dev = DevAddr;
pDTbl->pDOTbl = pDO;
pDTbl->pDITbl = pDI;
pDTbl->pAITbl = pAI;
pDTbl->nSizeOfDOTbl = nSizeOfDOTbl;
pDTbl->nSizeOfDITbl = nSizeOfDITbl;
pDTbl->nSizeOfAITbl = nSizeOfAITbl;
DOCfgFnct(DOSet);
AOCfgFnct(AOSet);
MultAOCfgFnct(MultAOCtrl);
}
//计算CRC校验和
INT16U CRC16(INT8U xdata * puchMsg,INT16U usDataLen)
{
INT8U uchCRCHi = 0xff;
INT8U uchCRCLo = 0xff;
INT8U uIndex;
while(usDataLen--)
{
uIndex = uchCRCHi ^ *puchMsg++;
uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex];
uchCRCLo = auchCRCLo[uIndex];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -