硬汉嵌入式论坛

 找回密码
 立即注册
查看: 2766|回复: 13
收起左侧

[UART] Modbus主从机数据量较大时,解析可以做成map映射表的形式,方便修改

  [复制链接]

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106649
QQ
发表于 2022-10-28 01:23:29 | 显示全部楼层 |阅读模式


之前分享的视频和文档:
BSP视频教程第23期:通过Modbus解析器,轻松掌握Modbus主从协议栈(2022-09-16)
https://www.armbbs.cn/forum.php?mod=viewthread&tid=115474

BSP视频教程第24期:应用实战,设计一款属于自己的Modbus RTU主从协议栈(2022-10-03)
https://www.armbbs.cn/forum.php?mod=viewthread&tid=115788


Modbus收发数据少的话,直接已经发布的例子方案即可,如果上百上千个寄存器处理,可以考虑map映射表的形式。

$(_1_70}IPJ%ZE}2Y@~ZETP.png

[C] 纯文本查看 复制代码
/*
*********************************************************************************************************
*	函 数 名: MODS_01H
*	功能说明: 读取线圈状态(对应远程开关D01/D02/D03)
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
/* 说明:这里用LED代替继电器,便于观察现象 */
typedef struct
{
	uint8_t (*ModbusCbFuncRead)(uint8_t arg); /* Modbus回调处理函数,如果参数多,考虑将uint8_t改成结构体定义 */
	void (*ModbusCbFuncWrite)(uint8_t arg);   /* Modbus回调处理函数 */

	uint16_t ModbusRegStart;	   /* 寄存器起始地址 */
	uint16_t ModbusRegEnd;		   /* 寄存器结束地址 */
	uint16_t Reserve1;             /* 保留未使用,可以自己扩增 */
	uint16_t Reserve2;
	uint16_t Reserve3;
}MODBUS_T;

const MODBUS_T g_tModbus_01_MAP[] = 
{
	{bsp_IsLedOn, bsp_LedToggle, 0x0101, 0x0104, 0, 0, 0}, 
	{NULL, NULL, 0x2101, 0x2104, 0, 0, 0}, 	
	{NULL, NULL, 0x3101, 0x3104, 0, 0, 0}, 	
};

static void MODS_01H(void)
{
	/*
	 举例:
		主机发送:
			11 从机地址
			01 功能码
			00 寄存器起始地址高字节
			13 寄存器起始地址低字节
			00 寄存器数量高字节
			25 寄存器数量低字节
			0E CRC校验高字节
			84 CRC校验低字节

		从机应答: 	1代表ON,0代表OFF。若返回的线圈数不为8的倍数,则在最后数据字节未尾使用0代替. BIT0对应第1个
			11 从机地址
			01 功能码
			05 返回字节数
			CD 数据1(线圈0013H-线圈001AH)
			6B 数据2(线圈001BH-线圈0022H)
			B2 数据3(线圈0023H-线圈002AH)
			0E 数据4(线圈0032H-线圈002BH)
			1B 数据5(线圈0037H-线圈0033H)
			45 CRC校验高字节
			E6 CRC校验低字节

		例子:
			01 01 10 01 00 03   29 0B	--- 查询D01开始的3个继电器状态
			01 01 10 03 00 01   09 0A   --- 查询D03继电器的状态
	*/
	uint32_t n = 0;
	uint16_t reg;
	uint16_t num;
	uint16_t i;
	uint16_t m;
	uint8_t status[10];
	
	g_tModS.RspCode = RSP_OK;

	/** 第1步: 判断接到指定个数数据 ===============================================================*/
	/*  没有外部继电器,直接应答错误 
		地址(8bit)+指令(8bit)+寄存器起始地址高低字节(16bit)+寄存器个数(16bit)+ CRC16
	*/
	if (g_tModS.RxCount != 8)
	{
		g_tModS.RspCode = RSP_ERR_VALUE;				/* 数据值域错误 */
		return;
	}

	/** 第2步: 数据解析 ===========================================================================*/
	/* 数据是大端,要转换为小端 */
	reg = BEBufToUint16(&g_tModS.RxBuf[2]); 			/* 寄存器号 */
	num = BEBufToUint16(&g_tModS.RxBuf[4]);				/* 寄存器个数 */

	/* 不足字节整数倍,补齐 */
	m = (num + 7) / 8;
	
	/* 寄存器处理 */
	for(n = 0; n < (sizeof(g_tModbus_01_MAP)/sizeof(g_tModbus_01_MAP[0])); n++)
	{
		/* 解析主机命令要读取的状态 */
		if ((reg >= g_tModbus_01_MAP[n].ModbusRegStart) && (num > 0) && (reg + num <= g_tModbus_01_MAP[n].ModbusRegEnd + 1))
		{
			for (i = 0; i < m; i++)
			{
				status[i] = 0;
			}
			
			for (i = 0; i < num; i++)
			{
				if(g_tModbus_01_MAP[n].ModbusCbFuncRead != NULL)
				{
					if (g_tModbus_01_MAP[n].ModbusCbFuncRead(i + 1 + reg - REG_D01))		/* 读LED的状态,写入状态寄存器的每一位 */
					{  
						status[i / 8] |= (1 << (i % 8));
					}
				}
			}
		}
		else
		{
			g_tModS.RspCode = RSP_ERR_REG_ADDR;				/* 寄存器地址错误 */
		}
	}
	
	/** 第3步: 应答回复 =========================================================================*/
	if (g_tModS.RspCode == RSP_OK)						/* 正确应答 */
	{
		g_tModS.TxCount = 0;
		g_tModS.TxBuf[g_tModS.TxCount++] = g_tModS.RxBuf[0]; /* 返回从机地址 */
		g_tModS.TxBuf[g_tModS.TxCount++] = g_tModS.RxBuf[1]; /* 返回从机指令 */
		g_tModS.TxBuf[g_tModS.TxCount++] = m;				 /* 返回字节数 */

		for (i = 0; i < m; i++)
		{
			g_tModS.TxBuf[g_tModS.TxCount++] = status[i];	/* 返回继电器状态 */
		}
		MODS_SendWithCRC(g_tModS.TxBuf, g_tModS.TxCount);
	}
	else
	{
		MODS_SendAckErr(g_tModS.RspCode);				/* 告诉主机命令错误 */
	}
}

评分

参与人数 1金币 +20 收起 理由
missfox + 20 很给力!

查看全部评分

回复

使用道具 举报

0

主题

214

回帖

214

积分

高级会员

积分
214
发表于 2022-10-28 07:51:57 | 显示全部楼层
需要判断4种状况
屏幕截图 2022-10-28 075030.png
回复

使用道具 举报

12

主题

141

回帖

177

积分

初级会员

积分
177
发表于 2022-10-28 08:58:53 | 显示全部楼层
modus主设备没有搞过,但一直存在一个疑问,modbus从设备不同厂家的寄存器都是自定义的,同一数据对象不同厂家的寄存器地址不一样,数据格式可能也不一样,作为modus主设备的话如何才能兼容这些不同厂家的modbus从设备,我想到的是通过一个配置软件去配置这些要抄读的数据对象的具体寄存器地址和数据格式,然后下发给modus主设备,根据新配置的寄存器去抄读和解析。
回复

使用道具 举报

4

主题

74

回帖

86

积分

初级会员

积分
86
发表于 2022-10-28 08:59:51 | 显示全部楼层
赞赞,感谢分享
回复

使用道具 举报

1

主题

18

回帖

21

积分

新手上路

积分
21
发表于 2022-10-28 09:18:22 | 显示全部楼层
是的这种方式比较好,可以把协议和数据分开,实现自动处理。另外在ModbusCbFuncRead和ModbusCbFuncWrite中可添加回调函数,在modbus读写操作时触发动作,比如对时,操作端口等。
回复

使用道具 举报

0

主题

5

回帖

5

积分

新手上路

积分
5
发表于 2022-10-28 10:06:24 | 显示全部楼层
感谢硬汉群内的指导帮助,很有帮助!
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106649
QQ
 楼主| 发表于 2022-10-28 11:09:06 | 显示全部楼层
gnail092 发表于 2022-10-28 08:58
modus主设备没有搞过,但一直存在一个疑问,modbus从设备不同厂家的寄存器都是自定义的,同一数据对象不同 ...

可以的。

一般不用去兼容他们,只有你的主机产品确实需要去控制其他厂家,根据他们厂家的产品说明书兼容即可。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106649
QQ
 楼主| 发表于 2022-10-28 11:10:07 | 显示全部楼层
regbbs 发表于 2022-10-28 07:51
需要判断4种状况

对,根据需求可以把需要的都配置成映射表。
回复

使用道具 举报

1

主题

6

回帖

9

积分

新手上路

积分
9
发表于 2022-11-4 23:18:40 | 显示全部楼层
gnail092 发表于 2022-10-28 08:58
modus主设备没有搞过,但一直存在一个疑问,modbus从设备不同厂家的寄存器都是自定义的,同一数据对象不同 ...

要兼容不同类型的设备很麻烦,比方说浮点数就有1234,3412这样不同的方式,量程倍率都没法统一,配置起来挺复杂的;这部分做成脚本来解析数据是可以严重考虑一下的
回复

使用道具 举报

23

主题

1403

回帖

1472

积分

至尊会员

积分
1472
发表于 2022-11-11 12:05:14 | 显示全部楼层
好帖,正在想怎么解决比较好
代码不规范,亲人两行泪!
回复

使用道具 举报

14

主题

109

回帖

151

积分

初级会员

积分
151
发表于 2022-11-12 14:17:27 | 显示全部楼层
好办法,好好学习研究下
回复

使用道具 举报

18

主题

42

回帖

96

积分

初级会员

积分
96
发表于 2022-12-8 14:30:31 | 显示全部楼层
硬汉哥,10H写大量连续寄存器怎么操作呀,switch case的方式太麻烦了,有没有什么好办法
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106649
QQ
 楼主| 发表于 2022-12-9 10:13:29 | 显示全部楼层
Zachary唷 发表于 2022-12-8 14:30
硬汉哥,10H写大量连续寄存器怎么操作呀,switch case的方式太麻烦了,有没有什么好办法

楼主位的方式就行。
回复

使用道具 举报

38

主题

194

回帖

318

积分

高级会员

积分
318
发表于 2022-12-13 08:06:33 | 显示全部楼层
gnail092 发表于 2022-10-28 08:58
modus主设备没有搞过,但一直存在一个疑问,modbus从设备不同厂家的寄存器都是自定义的,同一数据对象不同 ...

每个从机都给一个特定的主机....
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-4-27 23:33 , Processed in 0.220985 second(s), 37 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表