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

📄 modbus.c

📁 modbus modbus modbus
💻 C
字号:
#include "reg52.h"
#include<modbus.h>
//类型定义
typedef unsigned char	uchar;
typedef unsigned int	uint;
typedef unsigned long	ulong;
sbit E485=P3^2;       //max485发送允许
uchar *pushMsg;       /*要进行CRC校验的消息*/
uchar idata Rxbuf_com[16]=0;      //接收数据缓冲区
uchar idata Rxbuf[16]=0;  		//接收命令数据缓冲区
uchar idata MBFrame_Len=0;      //待处理命令消息字节长度
extern uchar idata MBFrame_OK;  //接收到一个命令结束,等待处理时为1;否则为0.
uchar idata Txbuf[16]=0;       //发送数据缓冲区
uchar idata Send_Count=1;         //发送数据长度
uchar idata Receive_Count=0;     //接收数据长度
uint  idata crc_temp;             //crc校验结果
uchar idata MBtimerT15=0;
uchar MBSlaveAdrress = 0x02;

extern int Parameter_Table[10];
#define Parameter_Num 10 

unsigned int usMBCRC16( unsigned char * pucFrame, unsigned char usLen );//modbus crc 函数



extern void MBSerialInit(void);       //串口配置函数

extern void ModBusProtocolProcess(void);      //接收到的消息命令处理函数
void MBSerialSendTxbuf(void); //数据上传函数
void ReadHoldingRegister(void);//03读取保持寄存器命令处理
void WriteSingleHoldingRegister(void);//写单个保持寄存器处理
void WriteMultiHoldingRegister(void);//写多个保持寄存器处理
void Cmd08loopbackTesting(void);


/*===========================*/
/*=====下位机发送数据函数====*/
/*===========================*/
void MBSerialSendTxbuf(void)
     {
	  uchar i;
      uint k;
	  E485=1;
      pushMsg=&Txbuf[0];
	  crc_temp=usMBCRC16(pushMsg,Send_Count);
      k=crc_temp;
      Txbuf[Send_Count]=(uchar)k;   //+CRC_Li
      Send_Count++;
      Txbuf[Send_Count]=(uchar)(crc_temp>>8); //+CRC_Hi
	  ES=0;REN=0;
      for(i=0;i<=Send_Count;i++)
	       {
		   SBUF=Txbuf[i];while(!TI);TI=0;
		   }
	  ES=1;REN=1;
      Send_Count=Send_Count-2; //恢复
	  E485=0;//恢复
     }

void ModBusProtocolProcess(void)
{

	 pushMsg=&Rxbuf[0];
	 crc_temp=usMBCRC16(pushMsg,MBFrame_Len);
	 if((Rxbuf[0]==MBSlaveAdrress)&&(crc_temp==0))//是否发给本机,并CRC正确?
	   {

	   switch (Rxbuf[1])
	         {
			 case 0x03:    //读取保持寄存器
		        {
				  ReadHoldingRegister();
				  break;
				}//03命令处理结束
			 case 0x06:    //写单个保持寄存器
		        {
				  WriteSingleHoldingRegister();
				  break;
				}//06命令处理结束
			 case 0x08:    //回路测试
		        {
				  Cmd08loopbackTesting();
				  break;
				}//08命令处理结束
			 case 0x10:    //写多个保持寄存器
			    {
				  WriteMultiHoldingRegister();
				  break;
				}//10命令处理结束
             default:
			    {
			      Txbuf[0]=MBSlaveAdrress;             //取地址
	              Txbuf[1]=0xff;             //命令号
				  Send_Count=2;                  //发送数据长度
				  MBSerialSendTxbuf();
                  break;
				}
			 }// Swith Rxbuf[1] 结束
	   }//if 判断结束
     else
	   {
           //CRC较验出错或者不是发到本地址不做任何响应
	   }
	 MBFrame_OK=0;    //消息处理完
}


void ReadHoldingRegister(void)  //03命令处理
     {
       uint StratingAddress;
       uint Numbers;
       int temp;
       uchar i,j,BytesCount;	         
	   StratingAddress=Rxbuf[2];
	   StratingAddress=(StratingAddress<<8)|Rxbuf[3];//取开始地址
       Numbers=Rxbuf[4];
	   Numbers=(Numbers<<8)|(Rxbuf[5]);  //读取的数量
	   BytesCount=(uchar)(Numbers*2);
	   if((Numbers + StratingAddress)<=Parameter_Num)
	  	{
	 	  Txbuf[0]=MBSlaveAdrress;    //取地址
	 	  Txbuf[1]=0x03;             //命令号
		  Txbuf[2]=BytesCount;////返回字节数
          j=0;
		  for(i=0;i<BytesCount;)
		     {
			 	temp = Parameter_Table[(uchar)StratingAddress+j];
                Txbuf[3+i]=(uchar)(temp>>8);     //返回测试数据高字节
                i++;
				Txbuf[3+i]=(uchar)temp;//返回测试数据低字节
                i++;
                j++;
			 }
	      Send_Count=(BytesCount+3);        //发送数据长度(01+ 03 + BytesCount + 返回数据)
		  MBSerialSendTxbuf();
		}
	  else
	    {
			//返回错误信息
	   	  Txbuf[0]=MBSlaveAdrress;             //取地址
	      Txbuf[1]=0x83;             //命令号&0x80
		  Txbuf[2]=Rxbuf[2];
          Txbuf[3]=Rxbuf[3];
          Txbuf[4]=Rxbuf[5];
          Txbuf[5]=Rxbuf[5];
          Send_Count=6;                  //发送数据长度
		  MBSerialSendTxbuf();
		}
	 }

void WriteSingleHoldingRegister(void) //06命令处理
    {
 	   uint StratingAddress;
       uint Numbers;
	   int temp;
       StratingAddress=Rxbuf[2];
	   StratingAddress=(StratingAddress<<8)|Rxbuf[3];//取开始地址
       Numbers=1;//写寄存器的数量
   	   if((Numbers + StratingAddress)<=Parameter_Num)
		 {
		   Txbuf[0]=MBSlaveAdrress;     //取地址
		   Txbuf[1]=0x06;             //命令号
		   Txbuf[2]=Rxbuf[2];
           Txbuf[3]=Rxbuf[3];
           Txbuf[4]=Rxbuf[4];
           Txbuf[5]=Rxbuf[5];
    	   Send_Count=6;                  //发送数据长度
  	       temp=Rxbuf[4];//测试数据高位
		   temp=(temp<<8)|Rxbuf[5];//测试数据高低位合并
		   Parameter_Table[(uchar)StratingAddress]=temp;
		   MBSerialSendTxbuf();
		 }
	   else
	    {
			//返回错误信息
		  Txbuf[0]=MBSlaveAdrress;             //取地址
	      Txbuf[1]=0x86;             //命令号&0x80
          Txbuf[2]=Rxbuf[2];
          Txbuf[3]=Rxbuf[3];
          Txbuf[4]=Rxbuf[4];
          Txbuf[5]=Rxbuf[5];
		  Send_Count=6;                  //发送数据长度
		  MBSerialSendTxbuf();
		}
	}
void Cmd08loopbackTesting(void)
    {
	   Txbuf[0]=MBSlaveAdrress;    //取地址
	   Txbuf[1]=0x08;             //命令号
       Txbuf[2]=Rxbuf[2];
       Txbuf[3]=Rxbuf[3];
       Txbuf[4]=Rxbuf[4];
       Txbuf[5]=Rxbuf[5];
	   Send_Count=6;                  //发送数据长度
	   MBSerialSendTxbuf();


	}
void WriteMultiHoldingRegister(void)  //10命令处理
     {
       uint StratingAddress;
	   uint Numbers;
 	   int temp;
       uchar i,BytesCount;	  
       StratingAddress=Rxbuf[2];
	   StratingAddress=(StratingAddress<<8)|Rxbuf[3];//取开始地址
       Numbers=Rxbuf[4];
   	   Numbers=(Numbers<<8)|(Rxbuf[5]);  //写寄存器的数量
 	   BytesCount=(uchar)(Numbers*2);
	   if((BytesCount + (uchar)StratingAddress)<=Parameter_Num)
		 {
		   Txbuf[0]=MBSlaveAdrress;     //取地址
		   Txbuf[1]=0x10;             //命令号
		   Txbuf[2]=Rxbuf[2];
           Txbuf[3]=Rxbuf[3];
           Txbuf[4]=Rxbuf[4];
           Txbuf[5]=Rxbuf[5];
    	   Send_Count=6;                  //发送数据长度
	  	   for(i=0;i<BytesCount;i++)
		     {
			    temp=Rxbuf[7+i];//测试数据高位
				temp=(temp<<8)|Rxbuf[8+i];//测试数据高低位合并
			    Parameter_Table[(uchar)StratingAddress+i]=temp;
			 }
		   MBSerialSendTxbuf();
		 }
	   else
	    {
			//返回错误信息
		  Txbuf[0]=MBSlaveAdrress;             //取地址
	      Txbuf[1]=0x90;             //命令号&0x80
		  Txbuf[2]=Rxbuf[2];
          Txbuf[3]=Rxbuf[3];
          Txbuf[4]=Rxbuf[4];
          Txbuf[5]=Rxbuf[5];
		  Send_Count=6;                  //发送数据长度
		  MBSerialSendTxbuf();
		}

	 }

/*=================================*/
/*=======定时器0中断处理函数=======*/
/*          中断计时1ms            */
/*=================================*/
void Timer0Service(void) interrupt 1
     {
	 TH0  = 0xdc;
     TL0  = 0x00;
	 if(MBtimerT15<2)
	   {MBtimerT15++;}
	 else
	   {
	   TR0=0;
	   Receive_Count=0;
	   MBFrame_OK=1; //一个消息接收完成!等待处理 
       }  
	 }
/*===========================*/
/*======串口配置函数函数=====*/
/*  bruad:波特率            */
/*===========================*/
void MBSerialInit(void)
    {
// 	SCON   = 0xDC;// SM0/PE SM1 SM2 REN TB8 RB8 TI RI
				  //	1    1   0   1   1   1   0  0   串口工作在模式3/多机通讯SM2无效/允许接收/

//  TH1    = 0xFD;//波特率为9600,11。0592 /当PCON的第8为SMOD1为1时波特率加倍
//  TL1    = 0xFD;
    SCON=0x50;        // 串口模式1,10bit,1 Start,8 data ,1 stop
    TH1=0xfa;
    TL1=0xfa;         // 设定波特率9600 *2=19200   
    PCON|=0x80; // 两倍波特率
//  PCON  &= 0x7F;//波特率不加倍
    TMOD   = 0x21;//定时间器0工作在模式1,16bit timer;定时器1工作在模式2,波特率发生器
    TR1    = 1;
	ES=1;             // 串口中断允许
    ET0=1;			//定时器0允许
    EA=1;             // 全局中断允许
	E485=0;
	}



/*=================================*/
/*=========中断接收数据函数========*/
/*=================================*/
void MBSerialService(void) interrupt 4
    {
    ES=0;
     if (RI)
       {
	   RI=0;
	   TR0=0;

	   if(MBtimerT15>1) //>1.5个字符停顿,刷新不完整消息   1x2ms
		  {
		  Receive_Count=0;	//MBFrame_OK=0;
		  TH0=0xdc;TL0=0x00;MBtimerT15=0;TR0=1;
		  }
	   Rxbuf_com[Receive_Count]=SBUF;         //接收数据
	   Rxbuf[Receive_Count]=Rxbuf_com[Receive_Count];
	   Receive_Count++;
	   MBFrame_Len=Receive_Count;  //消息长度
       Receive_Count&=0x0f;//最大接收16个
	   MBtimerT15=0;
       TH0=0xdc;TL0=0x00;	   
	   TR0=1;//接收完数据,启动接收计时,检测是否停顿超过1.5个字符时间停顿!
	   }
     ES=1;
	}

unsigned char code aucCRCHi[] = {
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81,
    0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
        0x40, 0x01, 0xC0,
    0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1,
        0x81, 0x40, 0x01,
    0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
        0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81,
    0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80,
        0x41, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
        0x80, 0x41, 0x01,
    0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00,
        0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81,
    0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
        0x40, 0x01, 0xC0,
    0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1,
        0x81, 0x40, 0x01,
    0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01,
        0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81,
    0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
        0x40, 0x01, 0xC0,
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
        0x80, 0x41, 0x01,
    0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
        0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81,
    0x40
};

unsigned char code aucCRCLo[] = {
    0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
        0x05, 0xC5, 0xC4,
    0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB,
        0x0B, 0xC9, 0x09,
    0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE,
        0xDF, 0x1F, 0xDD,
    0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2,
        0x12, 0x13, 0xD3,
    0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
        0x36, 0xF6, 0xF7,
    0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E,
        0xFE, 0xFA, 0x3A,
    0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B,
        0x2A, 0xEA, 0xEE,
    0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27,
        0xE7, 0xE6, 0x26,
    0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
        0x63, 0xA3, 0xA2,
    0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD,
        0x6D, 0xAF, 0x6F,
    0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8,
        0xB9, 0x79, 0xBB,
    0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4,
        0x74, 0x75, 0xB5,
    0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
        0x50, 0x90, 0x91,
    0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94,
        0x54, 0x9C, 0x5C,
    0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59,
        0x58, 0x98, 0x88,
    0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D,
        0x4D, 0x4C, 0x8C,
    0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
        0x41, 0x81, 0x80,
    0x40
};

unsigned int
usMBCRC16( unsigned char * pucFrame, unsigned char usLen )
{
 	unsigned char           ucCRCHi = 0xFF;
    unsigned char          ucCRCLo = 0xFF;
    unsigned int             iIndex;

    while( usLen-- )
    {
        iIndex = ucCRCLo ^ *( pucFrame++ );
        ucCRCLo = ucCRCHi ^ aucCRCHi[iIndex];
        ucCRCHi = aucCRCLo[iIndex];
    }
    return ucCRCHi << 8 | ucCRCLo;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -