MODBUS RTU C语言 主机接收实现

该代码示例展示了如何解析Modbus协议,特别是在RS485通信中处理接收到的数据。它包括了数据帧的头部检查、命令识别、长度验证、数据存储以及CRC校验的过程,用于确保数据的完整性和正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考链接:Modbus协议解析--小白一看就懂的协议_“社会大学三年级”的博客-优快云博客_modbus协议详解

水平有限,仅供参考

typedef unsigned int uint32_t;
typedef unsigned short uint16_t;
typedef unsigned char uint8_t;

#define REMOTE_ADDR 0x01//设备地址
#define RCV_MAX_LENGTH 60//接收字节的最大长度

#define RX_ARR_LENGTH 50
uint8_t rxIndexHigh;
uint8_t rxIndexLow;
uint8_t rxArr[RX_ARR_LENGTH];//接收到的数据放到循环数组里

#define RX_DEAL_LENGTH 100
uint8_t rxDealLength;//目前接收到的长度
uint8_t frameLength;//这一帧的长度
uint8_t rxDealArr[RX_DEAL_LENGTH];

uint8_t rxTimeOut;//超时

typedef enum{
	n_485_HEAD=0,
	n_485_CMD,
	n_485_LENGTH,
	n_485_DATA
}Rs485StepEnum;

Rs485StepEnum step;

void rx_deal(void)//2ms执行一次
{
	uint8_t data;
	uint8_t t;

	t = 0;
	while(t < 4)//一次处理4个数据,可根据自己的数据量添加
	{
		t++;
		if(rxIndexLow != rxIndexHigh)
		{
			rxTimeOut = 0;

			data = rxArr[rxIndexLow];
			rxIndexLow++;
			if(rxIndexLow >= RX_ARR_LENGTH)rxIndexLow=0;

			switch(step)
			{
				case n_485_HEAD:
					if(REMOTE_ADDR == data)
					{
						rxDealArr[rxDealLength++] = data;
						step = n_485_CMD;
					}
					break;
				case n_485_CMD:
					if(0X06 == data || 0X10 == data || 0X03 == data)
					{
						if(0X06 == data || 0X10 == data)
						{
							frameLength = 8;
							rxDealArr[rxDealLength++] = data;
							step = n_485_DATA;
						}
						else
						{
							rxDealArr[rxDealLength++] = data;
							step = n_485_LENGTH;
						}
					}
					else
					{
						step = n_485_HEAD;
						rxDealLength = 0;
					}
					break;
				case n_485_LENGTH:
					if(data > RCV_MAX_LENGTH)
					{
						step = n_485_HEAD;
						rxDealLength = 0;
					}
					else
					{
						frameLength = dat + 5;
						rxDealArr[rxDealLength++] = data;
						step = n_485_DATA;
					}
					break;
				case n_485_DATA:
					rxDealArr[rxDealLength++] = data;
					if(rxDealLength >= frameLength)
					{
						if(crc_modbusrtu(rxDealArr,rxDealLength) == 0)
						{
							if(rxDealArr[1] == 0X06)//单个写回复
							{
								
							}
							else if(rxDealArr[1] == 0X10)//多个写回复
							{
								
							}
							else if(rxDealArr[1] == 0X03)//0X03,读回复
							{
								//这里处理返回的数据
							}
						}
						step = n_485_HEAD;
						rxDealLength = 0;
					}
					break;
				default:
					step = n_485_HEAD;
					rxDealLength = 0;
					break;
			}
		}
	}

	//超时控制,多久没接收到完整的数据就丢弃原来的数据
	if(rxTimeOut++ > 10)
	{
		rxTimeOut = 0;
		step = n_485_HEAD;
		rxDealLength = 0;
	}
}

WORD crc_modbusrtu(BYTE *ptr, BYTE len)
{
	BYTE i;
	WORD crc = 0xffff;
	WORD temp;
 
	if (len == 0) {
		len = 1;
	}
	while (len--) {
		crc ^= *ptr;
		for (i = 0; i<8; i++)
		{
			if (crc & 1) {
				crc >>= 1;
				crc ^= CRC_CHECK_NUM;
			}
			else {
				crc >>= 1;
			}
		}
		ptr++;
	}

	temp = crc>>8;
	temp |= (crc<<8);

	return(temp);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值