📄 modbus.c
字号:
#define MODBUS_GLOBAL
#include "MODBUS.H"
void InitTime0(void)
{
TCCR0 = DIVIDED; //分频
TCNT0 = T0_COUNT;
TIMSK |= T0_TIMSK_VAL; //开放T0溢出中断;不同芯片配置不同
}
/*初始化串口通讯包括频率*/
void InitUSART(uint baud)
{
CLI();
/*区别两种芯片下不同串口的配置 分别是162和16L的芯片配置*/
#ifdef __iom162v_h
UBRR0 = (uchar)baud;
/* Enable receiver and transmitter */
UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);
/*UPM1 UPM0 10 偶校验
UCSZ2 UCSZ1 UCSZ0 011 8字符长度*/
UCSR0C = (1<<URSEL0)|(3<<UCSZ00)|(1<<USBS0);
#else
UBRR = (uchar)baud;
/* Enable receiver and transmitter */
UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE);
/*UPM1 UPM0 10 偶校验
UCSZ2 UCSZ1 UCSZ0 011 8字符长度*/
UCSRC = (1<<URSEL)|(3<<UCSZ0)|(1<<USBS);
#endif
}
void InitModbus(uchar connectMod )
{
selConnectMod = connectMod;
connectState = STATE_NULL;
sendSp = 0;
sendNum = 0;
canSendNext = 1;
receiveNum = 0;
stopCount = 0;
errorCount = 0;
requestTimeOut = 0;
requestFunCode = FUN_NULL;
/*通信模式主从其通信地址不同*/
if( connectMod == MASTER )
{
connectAddress = TARGET_ADDRESS;
}
else
{
connectAddress = LOCAL_ADDRESS;
}
InitTime0();
InitUSART( BAUD_RATE );
}
/*获得CRC校验码 */
uint GetCRCCode(uchar * pSendBuf, uint nLen)
{
register uchar i,j;
uint wCrc = 0xFFFF;
for(i=0; i<nLen; i++)
{
wCrc ^= (uint)(pSendBuf[i]);
for(j=0; j<8; j++)
{
if( (wCrc&0x0001) == 1 )
{
wCrc >>= 1;
wCrc ^= 0xA001;
}
else
wCrc >>= 1;
}
}
return wCrc;
}
/*数据拼接,将两个数据拼接成一个数据*/
uint Merge(uchar high, uchar low)
{
uint mergeData;
mergeData = high;
mergeData = ( mergeData<<8 ) + low;
return mergeData;
}
/*数据分离,将一个数据分离成两个数据*/
void Divide(uchar * array, uint highPos, uint lowPos, uint data)
{
array[lowPos] = (uchar)data;
array[highPos] = (uchar)(data>>8);
}
/*发送一个数据*/
void sendOneData(void)
{
if( sendSp > (sendNum -1) )
{
sendSp = 0;
connectState = STATE_NULL;
/*为MASTER模式时,发送完成后进行超时计数*/
if( selConnectMod == MASTER )
{
requestTimeOut = TIME_OUT_MAX;
}
else
{
requestTimeOut = 0;
}
sendLED( 0 ); /*发送结束时发送LED灭*/
}
else
{
if( sendSp == 0)/*发送开始时发送LED亮*/
{
sendLED( 1 );
}
MODBUS_UDR = sendData[sendSp];
sendSp ++;
}
stopCount = 0;
}
/*crc校验*/
uint crcReceive(void)
{
uint crcReceive,crcOperate;
if(receiveNum < 5)
{
return 0;
}
crcOperate = GetCRCCode( receiveData, receiveNum - 2 );
crcReceive = Merge( receiveData[receiveNum - 1], receiveData[receiveNum - 2] );
if(crcOperate == crcReceive)
{
return 1;
}
else
{
return 0;
}
}
/*生成error数据包*/
void errorPackage(uchar code)
{
uint crc;
sendData[0] = connectAddress;
sendData[1] |= MOD_ERROR;
sendData[2] = code;
crc = GetCRCCode( sendData, 3 );
Divide( sendData, 4, 3, crc );
sendNum = 5;
}
/*MASTER模式时:发送数据通信程序
*参数说明: funcode是功能码.8Bit;addr为操作的对方内存地址16Bit;
* count为操作的数据个数16Bit;
* regAddr为本机通信缓存下标
*/
void sendDataPackage(uchar funCode, uint addr, uint count, uint regAddr)
{
uint crc,temp = 0;
register uchar i;
if( selConnectMod != MASTER )
{
errorMessage = ERR_SLAVEMOD;
return;
}
/*当前还有未发送数据时,要等到数据发送完成后才能发送下一个*/
while( canSendNext == 0);
canSendNext = 0;
requestFunCode = funCode;
requestDataCount = count;
sendData[0] = connectAddress;
sendData[1] = funCode;
/*
*功能03与04操作相同 读取寄存器或输入的值
*通信格式:|设备地址8Bit|功能码8Bit|读寄存器地址16Bit|读取寄存器个数16Bit|
*/
if( (funCode == FUN_READ_REG) || (funCode == FUN_READ_INPUT) )
{
requestDataAddr = regAddr;
sendNum = 8;
Divide( sendData, 2, 3, addr );
Divide( sendData, 4, 5, count );
crc = GetCRCCode( sendData, sendNum - 2);
Divide( sendData, 7, 6, crc );
connectState = STATE_SEND;
}
/*
*功能0x06 :写单个寄存器
*通信格式:|设备地址8Bit|功能码8Bit|写寄存器地址16Bit|写入的值16Bit
*/
else if( funCode == FUN_WRITE_REG )
{
sendNum = 8;
Divide( sendData, 2, 3, addr );
Divide( sendData, 4, 5, registerData[regAddr] );
crc = GetCRCCode( sendData, sendNum - 2);
Divide( sendData, 7, 6, crc );
/*保存发送数据,以便接收信息时进行校检*/
for(i = 0 ; i < CHECK_BUFF; i ++)
{
checkBuff[i] = sendData[i + 2];
}
connectState = STATE_SEND;
}
/*
*功能0x10:写多个寄存器
*通信格式:|设备地址8Bit|功能码8Bit|写寄存器地址16Bit|写入寄存器个数16Bit|字节数8Bit|数据16Bit*N
*/
else if( funCode == FUN_WRITE_MULTI )
{
temp = count * 2;
sendNum = 9 + temp;
Divide( sendData, 2, 3, addr );
Divide( sendData, 4, 5, count );
sendData[6] = (uchar)temp;
for( i = 0; i < count; i ++ )
{
temp = i * 2 + 7;
Divide( sendData, temp, temp + 1, registerData[regAddr + i] );
}
crc = GetCRCCode( sendData, sendNum - 2);
Divide( sendData, sendNum - 1, sendNum - 2, crc );
/*保存发送数据,以便接收信息时进行校检*/
for(i = 0 ; i < CHECK_BUFF; i ++)
{
checkBuff[i] = sendData[i + 2];
}
connectState = STATE_SEND;
}
else
{
errorMessage = ERR_FUN;
connectState = STATE_NULL;
}
}
/*校检回复的信息是否正确*/
uint checkRecPackage(void)
{
uint temp = 0;
register uchar i;
if( requestFunCode == receiveData[1] )
{
/*通信码为0x03/0x04时,将回复的值写入对应内存中*/
if( (requestFunCode == FUN_READ_REG) || (requestFunCode == FUN_READ_INPUT) )
{
if( receiveData[2] == (requestDataCount*2) )
{
for( i = 0; i < requestDataCount; i ++ )
{
temp = i * 2 + 3;
registerData[requestDataAddr + i] = Merge( receiveData[temp],receiveData[temp + 1] );
}
errorMessage = ERR_NULL;
return 1;
}
else
{
return 0;
}
}
/*通信码为0x06/0x10时,将回复信息与发送的信息比较*/
else if( (requestFunCode == FUN_WRITE_REG) || (requestFunCode == FUN_WRITE_MULTI) )
{
for( i = 0; i < CHECK_BUFF; i ++ )
{
if( receiveData[i + 2] != checkBuff[i] )
{
break;
}
}
if( i == CHECK_BUFF )
{
errorMessage = ERR_NULL;
return 1;
}
else
{
return 0;
}
}
}
/*回复错误码的时*/
else if( (requestFunCode|MOD_ERROR) == receiveData[1] )
{
errorMessage = receiveData[2];
return 1;
}
return 0;
}
/*生成一般数据包*/
void backDataPackage(void)
{
register uint i;
uint addr,len,crc;
sendData[0] = connectAddress;
addr = Merge( receiveData[2], receiveData[3] );
/*地址合法时,对应操作*/
if( (addr >= MOD_REG_MIN) && (addr < MOD_REG_MAX) )
{
/*为读数据时的数据包 0x03 0x04*/
if( (receiveData[1] == FUN_READ_REG) || (receiveData[1] == FUN_READ_INPUT) )
{
len = Merge( receiveData[4], receiveData[5] );
len <<= 1;
sendNum = len + 5;/*回复数据长度为请求数据长度加固定格式数据长度6*/
sendData[1] = receiveData[1];
sendData[2] = (uchar)len;
for( i = 0 ; i < len; i += 2 )
{
Divide(sendData, i + 3, i + 4,registerData[addr + (i>>1)] );
}
crc = GetCRCCode( sendData, len + 3 );
Divide( sendData, len + 4, len + 3 , crc );
}
/*为写数据时的数据包 0x06*/
else if( receiveData[1] == FUN_WRITE_REG )
{
/*把数据放入指定寄存器*/
registerData[addr] = Merge( receiveData[4], receiveData[5] );
sendNum = receiveNum;
for( i = 1; i < receiveNum; i ++ )
{
sendData[i] = receiveData[i];
}
}
/*为写数据时的数据包 0x10*/
else if( receiveData[1] == FUN_WRITE_MULTI )
{
/*把数据放入指定寄存器*/
len = Merge( receiveData[4], receiveData[5] );
for( i = 0; i < len; i ++ )
{
registerData[addr + i] = Merge( receiveData[i*2 + 7], receiveData[i*2 +8] );
}
sendNum = 8;
for( i = 1; i < 6; i ++ )
{
sendData[i] = receiveData[i];
}
crc = GetCRCCode( sendData, sendNum -2 );
Divide( sendData, sendNum - 1, sendNum -2, crc);
}
else
{
errorPackage( ERR_FUN );
}
}
else
{
errorPackage( ERR_OUTRANGE );
}
}
/*串口中断服务程序*/
void usrtReceive(void)
{
/*当串口发送时不接收数据,警告发送时有接收数据*/
if( connectState == STATE_SEND )
{
errorMessage = ERR_SEND_REC;
return;
}
if( receiveNum == 0 )/*接收数据过程中接收灯亮*/
{
receiveLED( 1 );
}
receiveData[receiveNum] = MODBUS_UDR;
receiveNum ++;
stopCount = 0;
connectState = STATE_REC;
}
/*定时器中断服务程序*/
void time0INT(void)
{
TCNT0 = T0_COUNT;
/*有数据要发送时.发数据*/
if( connectState == STATE_SEND )
{
sendOneData();
}
/*在发送结束时会有一个超时计数器开始定时*/
if( requestTimeOut > 0 )
{
requestTimeOut --;
}
/*出现间隔符时,即一个串传送完成时*/
stopCount ++;
if( stopCount > STOP_TIMES )
{
if( connectState == STATE_REC )/*接收完数据时,提示灯灭*/
{
receiveLED( 0 );
}
/*Master模式时*/
if( selConnectMod == MASTER )
{
/*收到正确回复数据时*/
if( (connectState == STATE_REC) && (receiveData[0] == connectAddress) &&
crcReceive() && (receiveNum > 4) && checkRecPackage() )
{
connectState = STATE_NULL;
canSendNext = 1;
errorCount = 0;
requestTimeOut = 0;
}
/*发送数据后,未收到正确回复信息且超时时*/
else if( (canSendNext == 0) && (requestTimeOut == 0) )
{
errorCount ++;
if( errorCount > CAN_ERR_TIMES )/*超时三次则取消发送*/
{
errorMessage = ERR_STOP;
canSendNext = 1;
errorCount = 0;
requestTimeOut = 0;
connectState = STATE_NULL;
}
else/*重发数据*/
{
requestTimeOut = TIME_OUT_MAX;
errorMessage = ERR_UNKOWN;
connectState = STATE_SEND;
}
}
}
/*SLAVE模式时*/
else
{
if( (connectState == STATE_REC) && (receiveData[0] == connectAddress) )
{
if( crcReceive() && (receiveNum > 4) )
{
backDataPackage();
}
else
{
errorPackage( ERR_TRAN );
}
errorMessage = ERR_NULL;
connectState = STATE_SEND;
}
}
receiveNum = 0;
stopCount = 0;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -