ModbusRTU和ModbusTCP协议模板C语言.docx

上传人:b****8 文档编号:9296642 上传时间:2023-02-04 格式:DOCX 页数:32 大小:21.27KB
下载 相关 举报
ModbusRTU和ModbusTCP协议模板C语言.docx_第1页
第1页 / 共32页
ModbusRTU和ModbusTCP协议模板C语言.docx_第2页
第2页 / 共32页
ModbusRTU和ModbusTCP协议模板C语言.docx_第3页
第3页 / 共32页
ModbusRTU和ModbusTCP协议模板C语言.docx_第4页
第4页 / 共32页
ModbusRTU和ModbusTCP协议模板C语言.docx_第5页
第5页 / 共32页
点击查看更多>>
下载资源
资源描述

ModbusRTU和ModbusTCP协议模板C语言.docx

《ModbusRTU和ModbusTCP协议模板C语言.docx》由会员分享,可在线阅读,更多相关《ModbusRTU和ModbusTCP协议模板C语言.docx(32页珍藏版)》请在冰豆网上搜索。

ModbusRTU和ModbusTCP协议模板C语言.docx

ModbusRTU和ModbusTCP协议模板C语言

Modbus-RTU和Modbus-TCP协议模板(C语言)

 

简介:

在单片机内部实现modbus协议,可以简单地将变量的值映射到modbus寄存器地址,这种方法是高效的,但是有以下缺点:

1、通常不支持一条指令操作多个变量(寄存器);2、可移植性较差。

本模板使用8位数组模拟modbus寄存器。

06,10指令均对数组进行写操作,同时记录寄存器的写入操作,在其他地方定时判断“写入标志”,将“写入标志”置位的“模拟寄存器”的值转移到相关变量,或进行其他操作。

03指令读取最新数据,要求定时将变量的值写入“模拟寄存器”。

本模板缺点是占用资源较多、效率较低,优点是完整支持了modbus的03,06,10指令。

Modbus-RTU简介:

1、Modbus读寄存器指令(0x03)

地址(1B)+功能码(1B)+起始地址(2B)+寄存器数量(2B)+CRC(2B)

返回:

地址(1B)+功能码(1B)+字节数(1B)+数据值(2*“寄存器数量”Bytes或者“字节数”)+CRC(2B)

2、Modbus写单个寄存器指令(0x06)

地址(1B)+功能码(1B)+寄存器地址(2B)+数据值(2B)+CRC(2B)

返回:

地址(1B)+功能码(1B)+寄存器地址(2B)+数据值(2B)+CRC(2B)(返回与发送的指令相同)

3、Modbus写多个寄存器指令(0x10)

地址(1B)+功能码(1B)+起始地址(2B)+写寄存器数量(2Bn)+字节计数(1Bn*2)+数据(n*2B)+CRC(2B)

返回:

地址(1B)+功能码(1B)+起始地址(2B)+写寄存器数量(2B)+CRC(2B)

 

Modbus-TCP简介:

在MODBUS-RTU前添加6个字节,并删除MODBUS-RTU的CRC校验。

示例指令:

005100000009011000010001020000

6个字节部分称为“MBAP报文头”

示例:

005100000009

0051是客户端发出的校验信息,服务端原内容返回即可

0000表示modbus-tcp协议

0009表示后面还有9个字节

后面部分:

011000010001020000

01设备地址

10表示10指令

0001起始地址

0001写寄存器数量

02字节计数

0000数据

响应指令:

005100000006011000010001

 

System.h:

#ifndef_SYSTEM_H_

#define_SYSTEM_H_

#include"stm32f10x.h"

//=======================不常改动项==========================================

/******stm32f10x.h第505、506、507行已经定义了u32,u16和u8******/

//typedefunsignedcharu8;

//typedefunsignedshortintu16;

//typedefunsignedintu32;

//typedefunsignedcharINT8U;

//typedefunsignedshortintINT16U;

//typedefunsignedintINT32U;

//typedefsignedcharint8_t;

//typedefsignedshortintint16_t;

//typedefsignedintint32_t;

//typedefsignedlonglongintint64_t

typedefunsignedlonglongintu64;

typedefunsignedcharbool_t;

#defineFALSE0

#defineTRUE!

FALSE

#defineNULL0

#endif

 

CRC_Check.h

#ifndef_CRC_CHECK_H_

#define_CRC_CHECK_H_

#include"system.h"

u16CRC16_Verify(u8*puchMsg,u16usDataLen);

#endif

CRC_Check.c

#include"CRC_Check.h"

/*

*高位表

*/

staticconstu8auchCRCHi[]={

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

};

/*

*低位表

*/

staticconstu8auchCRCLo[]={

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

};

/*******************************************

*16位CRC校验函数,查表法

*******************************************/

u16CRC16_Verify(u8*puchMsg,u16usDataLen)

{

u8uchCRCHi=0xFF;

u8uchCRCLo=0xFF;

u16uIndex;

while(usDataLen--)

{

uIndex=uchCRCHi^*puchMsg++;

uchCRCHi=uchCRCLo^auchCRCHi[uIndex];

uchCRCLo=auchCRCLo[uIndex];

}

//return(((u16)(uchCRCLo)<<8)|uchCRCHi);

return(((u16)(uchCRCHi)<<8)|uchCRCLo);

}

Modbus_RTU.h

#ifndef_MODBUS_RTU_H_

#define_MODBUS_RTU_H_

#include"system.h"

/*-----------------------------------------------------

*是否启用“记录写入功能”

*0=不记录写入操作,1=记录写入操作。

*需要将数据存储到其他地方时,需要开启“记录写入功能”。

-----------------------------------------------------*/

#defineREC_WRITE1

/*---------------------------------------

*定义MODBUS缓存大小(8位)

*寄存器数量=MODBUS_BUFFER_LEN/2

---------------------------------------*/

#defineMODBUS_BUFFER_LEN4000

#defineMODBUS_IDLE_REG0xFFFF//MODBUS空闲寄存器地址。

表示未配置,不允许操作。

externu8*Modbus_sBuf;

externu8Modbus_Buffer[MODBUS_BUFFER_LEN];

externu16Modbus_Start_Addr;

externu8Modbus_Swap_Endian;

 

u16Modbus_16BitsSwapEndian(u16num);

u32Modbus_32BitsSwapEndian(u32num);

u64Modbus_64BitsSwapEndian(u64num);

u8Modbus_Read_WRecord(u16start,u16length);

voidModbus_Write_WRecord(u16start,u16length,u8sta);

u8Modbus_Read_Buffer(u8*buffer,u16addr,u16length);

u8Modbus_Write_Buffer(u8*buffer,u16addr,u16length);

voidModbus_Example(void);

voidModbus_WRecod_Example(void);

voidModbus_Init(void);

u8Modbus_RTU_Handler(u8*rBuf,void(*Send_Function)(u8*string,u16x));

#endif

 

Modbus_RTU.c

#include"Modbus_RTU.h"

#include"CRC_Check.h"

#defineModbus_Addr1//modbus地址。

可以定义为在其他地方定义的地址,例如save.localAddr。

//u8*Modbus_sBuf=Usart_sBuf;//发送缓存

u8Modbus_sBuf[128];//由外部定义时,使用上面的定义方法。

u8Modbus_Buffer[MODBUS_BUFFER_LEN];//modbus缓存(定义为8位方便传输)

u16Modbus_Start_Addr=0;//modbus起始地址

u8Modbus_Swap_Endian=1;//0=不转换字节顺序,1=允许转换字节顺序(51单片机设为0,STM32设为1)

#ifREC_WRITE

u8Modbus_WRecord[MODBUS_BUFFER_LEN/16+1];//记录modbus寄存器的写入操作。

需要将数据存储到其他地方时,需要开启“写入记录功能”。

#endif

/*--------------------------------------------------

*读modbus寄存器(16位)写入状态

*start:

起始地址

*length:

寄存器个数

*返回:

0个寄存器有写入操作,返回0

*至少有1个寄存器有写入操作,返回1

--------------------------------------------------*/

#ifREC_WRITE

u8Modbus_Read_WRecord(u16start,u16length)

{

u16i;

u16end;

if(length==0)return0;

end=start+length-1;

if(end>=MODBUS_BUFFER_LEN/2)return0;

for(i=start;i<=end;i++)

{

if(Modbus_WRecord[i/8]&(u8)1<<(i%8))return1;

}

return0;

}

#endif

/*--------------------------------------------------

*写modbus寄存器(16位)写入状态

*start:

起始地址

*length:

寄存器个数

*sta:

写入状态,0=无写入操作,1=有写入操作。

--------------------------------------------------*/

#ifREC_WRITE

voidModbus_Write_WRecord(u16start,u16length,u8sta)

{

u16i;

u16end;

if(length==0)return;

end=start+length-1;

if(end>=MODBUS_BUFFER_LEN/2)return;

if(sta){

for(i=start;i<=end;i++)

Modbus_WRecord[i/8]|=(u8)1<<(i%8);

}else{

for(i=start;i<=end;i++)

Modbus_WRecord[i/8]&=~((u8)1<<(i%8));

}

}

#endif

/*--------------------------------------------------

*读modbus缓存(8位)

*buffer:

将读取的数据存入buffer数组

*addr:

起始地址

*length:

读取长度

*返回:

0=读取失败,1=读取成功。

--------------------------------------------------*/

u8Modbus_Read_Buffer(u8*buffer,u16addr,u16length)

{

u16i;

u8*p_data;

if(length==0)return0;

if(addr+length>MODBUS_BUFFER_LEN)return0;

p_data=Modbus_Buffer+addr;

for(i=0;i

{buffer[i]=p_data[i];}

return1;

}

/*--------------------------------------------------

*写modbus缓存(8位)

*buffer:

将buffer数组的数据写入Modbus_Buffer。

*addr:

起始地址

*length:

写入长度

*返回:

0=写入失败,1=写入成功。

--------------------------------------------------*/

u8Modbus_Write_Buffer(u8*buffer,u16addr,u16length)

{

u16i;

u8*p_save;

if(length==0)return0;

if(addr+length>MODBUS_BUFFER_LEN)return0;

p_save=Modbus_Buffer+addr;

for(i=0;i

{p_save[i]=buffer[i];}

return1;

}

/*--------------------------------------------------

*16位变量存储顺序转换

--------------------------------------------------*/

u16Modbus_16BitsSwapEndian(u16num)

{

if(Modbus_Swap_Endian)

{

returnnum<<8|num>>8;

}elsereturnnum;

}

/*--------------------------------------------------

*32位变量存储顺序转换

--------------------------------------------------*/

typedefunion

{

chararr[4];

int32_tint32;

floatf;

}MODBUS_UNION32;

u32Modbus_32BitsSwapEndian(u32num)

{

u8temp;

MODBUS_UNION32res;

if(Modbus_Swap_Endian)

{

res.int32=num;

temp=res.arr[0];

res.arr[0]=res.arr[3];

res.arr[3]=temp;

temp=res.arr[1];

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 医学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1