📄 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 + -