⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 modbus.c

📁 MODBUS协议实现.本程序实现了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 + -