自己写一个Modbus从站程序,读写主站保存寄存器 、读取主站输入寄存器、读取主站输入开关量、读写主站输出线圈

2 篇文章 0 订阅

Modbus常用功能码功能

在这里插入图片描述

Modbus各个功能打包程序 Modbus.c文件

#include <Modbus.h>

#define ModbusSendMaxCount	(16*2+9)	//串口发送最大字节数,发送 16 Word(Register_Address)
#define ModbusReceMaxCount	(16*2+9)	//串口接收最大字节数,接收 16 Word(Register_Address)
unsigned char ModbusSendBuf[ModbusSendMaxCount];
unsigned char ModbusReceBuf[ModbusReceMaxCount];

unsigned char Demo;

uchar WBDO15[8];//
unsigned int  WWAO16[8];//
//===========================================================================================
//CRC校验字节值表
//===========================================================================================
//CRC校验高位字节值表
const unsigned char code auchCRCHi[] = {   
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 } ;   
//CRC校验低位字节值表
const unsigned char code auchCRCLo[] = {   
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 short CRC16 ( unsigned char *puchMsg, unsigned short usDataLen )    
{   
 unsigned char uchCRCHi = 0xFF ;  //\* 高字节初始化值   \*/   
 unsigned char uchCRCLo = 0xFF ;  //\* 低字节初始化值   \*/   
 unsigned uIndex ;    
    
 while (usDataLen--)   
 {   
  uIndex = uchCRCLo ^ *puchMsg++ ;     
  uchCRCLo = uchCRCHi ^ auchCRCHi[uIndex] ;   
  uchCRCHi = auchCRCLo[uIndex];   
 }   
 return (uchCRCHi << 8 | uchCRCLo) ;   
}   


//===========================================================================================
//Modbus功能函数,功能码:01 02 03 04 05 06
//===========================================================================================	
void Modbus_Reduce_ReadFunction01_02_03_04_WriteFunction05_06(uchar ModbusSalveAddress,uchar ModbusFunction,uint RegisterStartAddress,uint RegisterNumberOrData)
{
	unsigned short CRC_Data;
	ModbusSendBuf[0] = ModbusSalveAddress;
	ModbusSendBuf[1] = ModbusFunction;
	ModbusSendBuf[2] = RegisterStartAddress>>8;
	ModbusSendBuf[3] = RegisterStartAddress&0x00ff;
	ModbusSendBuf[4] = RegisterNumberOrData>>8;
	ModbusSendBuf[5] = RegisterNumberOrData&0x00ff;
	CRC_Data				 = CRC16(ModbusSendBuf,6);
	ModbusSendBuf[6] = CRC_Data&0x00ff;
	ModbusSendBuf[7] = CRC_Data>>8;
	if((ModbusFunction == 0x01)||(ModbusFunction == 0x02)||(ModbusFunction == 0x03)||(ModbusFunction == 0x04)||(ModbusFunction == 0x05)||(ModbusFunction == 0x06))
	SendByte(ModbusSendBuf,8);	
}
//===========================================================================================
//打包读多路数字量输出子西数:功能码01
//===========================================================================================	
void ModbusReduce_Read_Multiple_Digital_Output (uchar ModbusSlaveAddress, uint RegisterStartAddress, uint Register_Number) 
{
	Modbus_Reduce_ReadFunction01_02_03_04_WriteFunction05_06(ModbusSlaveAddress,0x01,RegisterStartAddress,Register_Number);
}

//===========================================================================================
//打包读多路数字量输入子函数:功能码02
//===========================================================================================	
void ModbusReduce_Read_Multiple_Digital_Input 	(uchar ModbusSlaveAddress ,uint RegisterStartAddress, uint Register_Number) 
{
	Modbus_Reduce_ReadFunction01_02_03_04_WriteFunction05_06(ModbusSlaveAddress,0x02,RegisterStartAddress,Register_Number);
}
//===========================================================================================
//打包读多路模拟量输出子函数:功能码03
//===========================================================================================	
void ModbusReduce_Read_Multiple_Hold_Registers 	(uchar ModbusSlaveAddress, uint RegisterStartAddress, uint Register_Number)
{
	Modbus_Reduce_ReadFunction01_02_03_04_WriteFunction05_06(ModbusSlaveAddress,0x03,RegisterStartAddress,Register_Number);
}
//===========================================================================================
//打包读多路模拟量输入子西数:功能码04
//===========================================================================================	
void ModbusReduce_Read_Multiple_Analog_Input 	(uchar ModbusSlaveAddress, uint RegisterStartAddress, uint Register_Number)
{
	Modbus_Reduce_ReadFunction01_02_03_04_WriteFunction05_06(ModbusSlaveAddress,0x04,RegisterStartAddress,Register_Number);
}
//===========================================================================================
//打包写单路数字三输出子西数:功能码05
//===========================================================================================	
void ModbusReduce_Write_Single_Digital_Output 	(uchar ModbusSlaveAddress, uint RegisterStartAddress, uint Register_Data)
{
	Modbus_Reduce_ReadFunction01_02_03_04_WriteFunction05_06(ModbusSlaveAddress,0x05,RegisterStartAddress,Register_Data);
}
//===========================================================================================
//打包写单路模拟量输出子函数:功能码06
//===========================================================================================	
void ModbusReduce_Write_Single_Hold_Registers (uchar ModbusSlaveAddress, uint RegisterStartAddress, uint Register_Data)
{
	Modbus_Reduce_ReadFunction01_02_03_04_WriteFunction05_06(ModbusSlaveAddress,0x06,RegisterStartAddress,Register_Data);
}
//===========================================================================================
//打包写多路数字量输出子西数:功能码15
//===========================================================================================	
void ModbusReduce_Write_Multiple_Digital_Output(uchar ModbusSlaveAddress, uint RegisterStartAddress, uint Register_Number, uchar *UcharData)
{
	unsigned short CRC_Data;
	uchar Byte_Count , i;

	Byte_Count= Register_Number/8;
	if(Register_Number%8 != 0)
	Byte_Count++;

	ModbusSendBuf[0] = ModbusSlaveAddress;
	ModbusSendBuf[1] = 0x0f;
	ModbusSendBuf[2] = RegisterStartAddress>>8;
	ModbusSendBuf[3] = RegisterStartAddress&0x00ff;
	ModbusSendBuf[4] = Register_Number>>8;
	ModbusSendBuf[5] = Register_Number&0x00ff;
	ModbusSendBuf[6] = Byte_Count;
	
	for(i= 0;i<Byte_Count;i++) 
		ModbusSendBuf[i+7] = UcharData[i];
	CRC_Data = CRC16(ModbusSendBuf,Byte_Count+7);
	
	ModbusSendBuf[i+7] = CRC_Data&0x00ff;
	ModbusSendBuf[i+8] = CRC_Data>>8;
	SendByte(ModbusSendBuf,Byte_Count+9);	
}
//===========================================================================================
//打包写多路数字量输出子西数:功能码16
//===========================================================================================	
void ModbusReduce_Write_Multiple_Hold_Registers (uchar ModbusSlaveAddress, uint RegisterStartAddress, uint Register_Number, unsigned int  *UintData)
{
	unsigned short CRC_Data;
	uchar Byte_Count , i;

	Byte_Count = Register_Number*2;

	ModbusSendBuf[0] = ModbusSlaveAddress;
	ModbusSendBuf[1] = 0x10;
	ModbusSendBuf[2] = RegisterStartAddress>>8;
	ModbusSendBuf[3] = RegisterStartAddress&0x00ff;
	ModbusSendBuf[4] = Register_Number>>8;
	ModbusSendBuf[5] = Register_Number&0x00ff;
	ModbusSendBuf[6] = Byte_Count;

	for(i= 0;i<Register_Number;i++)
	{
		ModbusSendBuf[i*2+7] = UintData[i]>>8;
		ModbusSendBuf[i*2+8] = UintData[i]&0x00ff;
	}
	CRC_Data = CRC16(ModbusSendBuf,Byte_Count+7);
	
	ModbusSendBuf[Byte_Count+7] = CRC_Data&0x00ff;
	ModbusSendBuf[Byte_Count+8] = CRC_Data>>8;	
	SendByte(ModbusSendBuf,Byte_Count+9);	
}


void DemonstrationReduce(void)
{
	unsigned char i;
if(Demo>3)	Demo = 0;
	switch(Demo)
	{
		case 0:
		{
			ModbusReduce_Read_Multiple_Digital_Output(1,0,10);//Modbus Slave 测试通过
			Demo = 1;
			break;
		}
		case 1:
		{
			ModbusReduce_Read_Multiple_Digital_Input(1,0,10);//Modbus Slave 测试通过
			Demo = 2;
			break;
		}
		case 2:
		{
			ModbusReduce_Read_Multiple_Hold_Registers(1,0,6);//Modbus Slave 测试通过
			Demo = 3;
			break;
		}
		case 3:
		{
			ModbusReduce_Read_Multiple_Analog_Input(1,0,6);//Modbus Slave 测试通过
			Demo = 4;
			break;
		}
		case 4:
		{
			ModbusReduce_Write_Single_Digital_Output(1,9,0xff00);//Modbus Slave 测试通过,注意最高字节为0xff00才能正确置位相应位地址,地址从0开始计算
			Demo = 5;
			break;
		}
		case 5:
		{
			ModbusReduce_Write_Single_Hold_Registers(1,0,2222);//Modbus Slave 测试通过
			Demo = 6;
			break;
		}
		case 6:
		{
			WBDO15[0] = 0x0f;
			WBDO15[1] = 0x01;
			ModbusReduce_Write_Multiple_Digital_Output(1,0,10,WBDO15);//Modbus Slave 测试通过
			Demo = 7;
			break;
		}
		case 7:
		{
			for(i=0;i<6;i++)
			WWAO16[i] = i+10;
			ModbusReduce_Write_Multiple_Hold_Registers(1,0,6,WWAO16);//Modbus Slave 测试通过 保持寄存器
			Demo = 0;
			break;
		}
		default:
		{
			Demo = 0;			
		}
	}
}

uchar ReceState = 0;
uchar ReceiveDataCounter = 0;
uchar ActualDataCounter = 0;
uchar ReceCount = 0;


sbit LCD7=P3^7;    
sbit LCD6=P3^6;    
sbit LCD5=P3^5;     
sbit LCD4=P3^4;   

void DemonstrationUnpark(unsigned char ReceiveData) 
{
//	 unsigned short CRCData;
	switch (ReceState)
	{
		case 0:
			if(ReceiveData == ModbusSendBuf[0] )//从站地址
			{
				
				ReceiveDataCounter = 0;
				ModbusReceBuf[ReceiveDataCounter] = ReceiveData;
				ReceState 	= 1;	
			}
			else
				ReceState = 0;	
			break;
		case 1:
			if(ReceiveData == ModbusSendBuf[1])//Modbus功能码
			{
				ReceiveDataCounter++;
				ModbusReceBuf[ReceiveDataCounter] = ReceiveData;			
				ReceState = 2;
			}
			else
				ReceState = 0;	
			break;
		case 2:																//接收字节数量
			if((ModbusSendBuf[1] == 0x01)||(ModbusSendBuf[1] == 0x02)||(ModbusSendBuf[1] == 0x03)||(ModbusSendBuf[1] == 0x04))//Modbus功能码
			{
				ReceiveDataCounter++;	
				ModbusReceBuf[ReceiveDataCounter] = ReceiveData;	
				ActualDataCounter = ReceiveData;								//接收字节数量						
				ReceState = 3;
				
			}	
			else
				ReceState = 0;	
			break;
		case 3:			
			if(ReceCount<ActualDataCounter)//开始接收数据
			{
				ReceiveDataCounter++;	
				ModbusReceBuf[ReceiveDataCounter] = ReceiveData;							
//				ucharDataBuff[ReceCount]=ReceiveData;
				P0 = ~ModbusReceBuf[3];
				P2 = ~ModbusReceBuf[4];
				ReceCount++;
				
			}
			else//接收完成
			{
//				CRCData = CRC16(ModbusReceBuf,ActualDataCounter+5);	
//				if((ModbusReceBuf[ActualDataCounter+5-2] == (CRCData>>8))&&(ModbusReceBuf[ActualDataCounter+5-1] == (CRCData&0x00ff)))
				{
//					P0 = ~ModbusReceBuf[3];
//					P2 = ~ModbusReceBuf[4];
				}
				//数据CRC校验判断数据完整性
				ReceiveDataCounter = 0;
				ReceCount = 0;
				ReceState = 0;							
			}
//			if(ReceCount == ActualDataCounter)
//			{
//				ReceiveDataCounter = 0;
//				ReceCount = 0;
//				ReceState = 0;							
//			}	
			break;
		default:				 
			ReceState=0;
			break;
	}
}

Modbus.h文件

#ifndef __Modbus_H__
#define __Modbus_H__

#include <STC12C5A_Uart2.H>

typedef unsigned char uchar;
typedef unsigned int uint;

extern unsigned char ModbusSendBuf[];
extern unsigned char ModbusReceBuf[];


/*
//解包读多路数字量输出子函数:功能码01
extern void ModbusUnpark_Read_Multiple_Digtal_Output(void);

//解包读多路数字量输出子函数:功能码02
extern void ModbusUnpark_Read_Multiple_Digtal_Input(void);

//解包读多路数字量输出子函数:功能码03
extern void ModbusUnpark_Read_Multiple_Analog_Output(void);

//解包读多路数字量输出子函数:功能码04
extern void ModbusUnpark_Read_Multiple_Analog_Input(void);

//解包读单路数字量输出子函数:功能码05
extern void ModbusUnpark_Write_Single_Analog_Input(void);

//解包写单路数字量输出子函数:功能码06
extern void ModbusUnpark_Write_Singlee_Analog_Output(void);

//解包写多路数字量输出子函数:功能码15
extern void ModbusUnpark_Write_Multiple_Digtal_Output(void);

//解包写多路数字量输出子函数:功能码16
extern void ModbusUnpark_Write_Multiple_Analog_Output(void);*/

//打包读多路数字量输出子西数:功能码01
extern void ModbusReduce_Read_Multiple_Digital_Output (uchar ModbusSlaveAddress, uint RegisterStartAddress, uint Register_Number) ;
//打包读多路数字量输入子函数:功能码o2
extern void ModbusReduce_Read_Multiple_Digital_Input 	(uchar ModbusSlaveAddress ,uint RegisterStartAddress, uint Register_Number) ;
//打包读多路模拟量输出子函数:功能码03
extern void ModbusReduce_Read_Multiple_Hold_Registers (uchar ModbusSlaveAddress, uint RegisterStartAddress, uint Register_Number);
//打包读多路模拟量输入子西数:功能码04
extern void ModbusReduce_Read_Multiple_Analog_Input 	(uchar ModbusSlaveAddress, uint RegisterStartAddress, uint Register_Number);
//打包写单路数字三输出子西数:功能码g5
extern void ModbusReduce_Write_Single_Digital_Output 	(uchar ModbusSlaveAddress, uint RegisterStartAddress, uint Register_Data);
//打包写单路模拟量输出子函数:功能码06
extern void ModbusReduce_Write_Single_Hold_Registers 	(uchar ModbusSlaveAddress, uint RegisterStartAddress, uint Register_Data);
//打包写多路数字量输出子西数:功能码15
extern void ModbusReduce_Write_Multiple_Digital_Output(uchar ModbusSlaveAddress, uint RegisterStartAddress, uint Register_Number, uchar *UcharData);
//打包写多路数字量输出子西数:功能码16
extern void ModbusReduce_Write_Multiple_Hold_Registers(uchar ModbusSlaveAddress, uint RegisterStartAddress, uint Register_Number, uint *UintData);


extern void DemonstrationReduce(void);//在主程序里调用,发送指定的功能码
extern void DemonstrationUnpark(unsigned char ReceiveData) ;//解包程序在串口中断程序中调用,按字节接收


#endif

发送指定的功能码

DemonstrationReduce();

接收返回数据进行解包程序在串口中断程序中调用

DemonstrationUnpark(unsigned char ReceiveData)
  • 2
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值