嵌入式Libmodbus之RTU模式Master端程序示例

Posted 沧海一笑-dj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了嵌入式Libmodbus之RTU模式Master端程序示例相关的知识,希望对你有一定的参考价值。

00. 目录

01. 软件开发流程

Modbus结合libmodbus开发库可以自由开发主设备端或从设备端的应用程序,而且支持RTU和TCP两种常用的模式。

开发主设备端(Master或者Client)程序的基本流程如下图所示:
在这里插入图片描述

开发从设备端(Slave或者Server)程序的基本流程如下图所示:
在这里插入图片描述

02. 获取版本信息

程序示例

#include <stdio.h>

#ifndef _MSC_VER
#include <unistd.h>
#endif

#include <string.h>
#include <stdlib.h>
#include <errno.h>

//包含Modbus相关头文件
#include "modbus.h"



int main(void)
{
	printf("hello world\\n");
	//输出libmodbus版本信息
	printf("Compiled with libmodbus version: %s (%06X)\\n", LIBMODBUS_VERSION_STRING, LIBMODBUS_VERSION_HEX);

	//判断当前版本是否大于或者等于3.1.5
	if (LIBMODBUS_VERSION_CHECK(3, 1, 5))
	{
		printf("The functions to read/write float values are available (2.1.0).\\n");
	}

	//判断当前版本是否大于或者等于3.1.6
	if (LIBMODBUS_VERSION_CHECK(3, 1, 6))
	{
		printf("Oh gosh, brand new API(3.1.6)!\\n");
	}

	return 0;
}

执行结果
在这里插入图片描述

03. 读写单个线圈程序示例

程序示例

#include <stdio.h>

#ifndef _MSC_VER
#include <unistd.h>
#endif

#include <string.h>
#include <stdlib.h>
#include <errno.h>

//包含Modbus相关头文件
#include "modbus.h"

//相关参数设置
#define LOOP	1			//循环次数
#define  SERVER_ID 17		//从设备地址
#define ADDRESS_START	0	//测试寄存器起始地址
#define ADDRESS_END		99	//测试寄存器结束地址


int main(void)
{
	modbus_t* ctx = NULL;


	int ret = -1;
	int nums = 0;
	int addr = 0;
	int i = 0;
	int tmp = 0;

	uint8_t* tab_rq_bits = NULL;
	uint8_t* tab_rp_bits = NULL;


	//1. 创建一个RTU类型的变量
	//设置串口设备  波特率 奇偶校验 数据位 停止位
	ctx = modbus_new_rtu("COM4", 9600, 'N', 8, 1);
	if (NULL == ctx)
	{
		fprintf(stderr, "Error: %s\\n", modbus_strerror(errno));
		return 1;
	}
	else
	{
		printf("设置串口信息成功\\n");
	}


	//2. 设置从机地址
	ret = modbus_set_slave(ctx, SERVER_ID);
	if (-1 == ret)
	{
		fprintf(stderr, "Error: 设置从机地址失败\\n");

		modbus_free(ctx);

		return 1;
	}

	//3. 设置Debug模式
	ret = modbus_set_debug(ctx, TRUE);
	if (-1 == ret)
	{
		fprintf(stderr, "Error: 设置Debug模式失败");
		modbus_free(ctx);
		return 1;
	}

	//4. 在RTU模式下打开串口
	ret = modbus_connect(ctx);
	if (-1 == ret)
	{
		fprintf(stderr, "Connection failed: %s\\n", modbus_strerror(errno));
		modbus_free(ctx);
		return 1;
	}

	//5. 计算需测试的寄存器个数
	nums = ADDRESS_END - ADDRESS_START;

	//6. 申请内存 保存发送和接收的数据
	tab_rq_bits = (uint8_t*)malloc(nums * sizeof(uint8_t));
	if (NULL == tab_rq_bits)
	{
		fprintf(stderr, "malloc failed\\n");
		modbus_free(ctx);
		return 1;
	}
	else
	{
		memset(tab_rq_bits, 0, nums * sizeof(uint8_t));
	}


	tab_rp_bits = (uint8_t*)malloc(nums * sizeof(uint8_t));
	if (NULL == tab_rp_bits)
	{
		fprintf(stderr, "malloc failed\\n");
		modbus_free(ctx);
		return 1;
	}
	else
	{
		memset(tab_rp_bits, 0, nums * sizeof(uint8_t));
	}

	//7. 写单个线圈
	addr = ADDRESS_START;
	tmp = rand() / 100;
	tab_rq_bits[0] = tmp % 2;

	ret = modbus_write_bit(ctx, addr, tab_rq_bits[0]);
	if (1 != ret)
	{
		printf("Error modbus_write_bit: %d\\n", ret);
		printf("Address: %d value: %d\\n", addr, tab_rq_bits[0]);
	}
	else
	{
		//读取单个线圈
		ret = modbus_read_bits(ctx, addr, 1, tab_rp_bits);
		if (1 != ret)
		{
			printf("Error modbus_read_bits: %d\\n", ret);
		}
		else
		{
			printf("tab_rp_bits[0]: %d tab_rq_bits[0]: %d\\n", tab_rp_bits[0], tab_rq_bits[0]);
		}
	}


	//8. 释放内存
	free(tab_rp_bits);
	free(tab_rq_bits);

	//9. 断开连接
	modbus_close(ctx);
	modbus_free(ctx);

	return 0;
}

执行结果
在这里插入图片描述

04. 读写多个线圈程序示例

程序示例

#include <stdio.h>


#ifndef _MSC_VER
#include <unistd.h>
#endif

#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>

//包含Modbus相关头文件
#include "modbus.h"

//相关参数设置
#define LOOP	1			//循环次数
#define  SERVER_ID 17		//从设备地址
#define ADDRESS_START	0	//测试寄存器起始地址
#define ADDRESS_END		99	//测试寄存器结束地址


int main(void)
{
	modbus_t* ctx = NULL;


	int ret = -1;
	int nums = 0;
	int addr = 0;
	int i = 0;
	int tmp = 0;

	uint8_t* tab_rq_bits = NULL;
	uint8_t* tab_rp_bits = NULL;

	//设置随机种子
	srand((int)time(0));

	//1. 创建一个RTU类型的变量
	//设置串口设备  波特率 奇偶校验 数据位 停止位
	ctx = modbus_new_rtu("COM4", 9600, 'N', 8, 1);
	if (NULL == ctx)
	{
		fprintf(stderr, "Error: %s\\n", modbus_strerror(errno));
		return 1;
	}
	else
	{
		printf("设置串口信息成功\\n");
	}


	//2. 设置从机地址
	ret = modbus_set_slave(ctx, SERVER_ID);
	if (-1 == ret)
	{
		fprintf(stderr, "Error: 设置从机地址失败\\n");

		modbus_free(ctx);

		return 1;
	}

	//3. 设置Debug模式
	ret = modbus_set_debug(ctx, TRUE);
	if (-1 == ret)
	{
		fprintf(stderr, "Error: 设置Debug模式失败");
		modbus_free(ctx);
		return 1;
	}

	//4. 在RTU模式下打开串口
	ret = modbus_connect(ctx);
	if (-1 == ret)
	{
		fprintf(stderr, "Connection failed: %s\\n", modbus_strerror(errno));
		modbus_free(ctx);
		return 1;
	}

	//5. 计算需测试的寄存器个数
	nums = ADDRESS_END - ADDRESS_START;

	//6. 申请内存 保存发送和接收的数据
	tab_rq_bits = (uint8_t*)malloc((nums + 1) * sizeof(uint8_t));
	if (NULL == tab_rq_bits)
	{
		fprintf(stderr, "malloc failed\\n");
		modbus_free(ctx);
		return 1;
	}
	else
	{
		memset(tab_rq_bits, 0, (nums + 1) * sizeof(uint8_t));
	}


	tab_rp_bits = (uint8_t*)malloc((nums + 1) * sizeof(uint8_t));
	if (NULL == tab_rp_bits)
	{
		fprintf(stderr, "malloc failed\\n");
		modbus_free(ctx);
		return 1;
	}
	else
	{
		memset(tab_rp_bits, 0, (nums + 1) * sizeof(uint8_t));
	}


	//7. 写多个线圈
	//随机数字
	for (i = 0; i < nums; i++)
	{
		tmp = rand() % 100;
		tab_rq_bits[i] = tmp % 2; 
		if (0 == i)
		{
			printf("写入的值: ");
		}
		printf("%hd ", tab_rq_bits[i]);
	}
	//换行
	printf("\\n");

	addr = ADDRESS_START;
	ret = modbus_write_bits(ctx, addr, nums + 1, tab_rq_bits);
	if (nums + 1 != ret)
	{
		printf("Error modbus_write_bit: %d\\n", ret);
		printf("Address: %d nums: %d\\n", addr, nums);
	}
	else
	{
		//读取多个线圈
		ret = modbus_read_bits(ctx, addr, nums + 1, tab_rp_bits);
		if (nums + 1 != ret)
		{
			printf("Error modbus_read_bits: %d\\n", ret);
		}
		else
		{
			//输出
			for (i = 0; i < nums; i++)
			{
				if (0 == i)
				{
					printf("读取到的值: ");
				}
				printf("%hd ", tab_rp_bits[i]);
			}
			//换行
			printf("\\n");
		}
	}


	//8. 释放内存
	free(tab_rp_bits);
	free(tab_rq_bits);

	//9. 断开连接
	modbus_close(ctx);
	modbus_free(ctx);

	return 0;
}

执行结果
在这里插入图片描述

05. 读写单个保持寄存器程序示例

程序示例

#include <stdio.h>


#ifndef _MSC_VER
#include <unistd.h>
#endif

#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>

//包含Modbus相关头文件
#include "modbus.h"

//相关参数设置
#define LOOP	1			//循环次数
#define  SERVER_ID 17		//从设备地址
#define ADDRESS_START	0	//测试寄存器起始地址
#define ADDRESS_END		99	//测试寄存器结束地址


int main(void)
{
	modbus_t* ctx = NULL;


	int ret = -1;
	int nums = 0;
	int addr = 0;
	int i = 0;
	int tmp = 0;

	uint16_t* tab_rq_registers = NULL;
	uint16_t* tab_rp_registers = NULL;

	//设置随机种子
	srand((int)time(0));

	//1. 创建一个RTU类型的变量
	//设置串口设备  波特率 奇偶校验 数据位 停止位
	ctx = modbus_new_rtu("COM4", 9600, 'N', 8, 1);
	if (NULL == ctx)
	{
		fprintf(stderr, "Error: %s\\n", modbus_strerror(errno));
		return 1;
	}
	else
	{
		printf("设置串口信息成功\\n");
	}


	//2. 设置从机地址
	ret = modbus_set_slave(ctx, SERVER_ID);
	if (-1 == ret)
	{
		fprintf(stderr, "Error: 设置从机地址失败\\n");

		modbus_free(ctx);

		return 1;
	}

	//3. 设置Debug模式
	ret = modbus_set_debug(ctx, TRUE);
	if (-1 == ret)
	{
		fprintf(stderr, "Error: 设置Debug模式失败");
		modbus_free(ctx);
		return 1;
	}

	//4. 在RTU模式下打开串口
	ret = modbus_connect(ctx);
	if (-1 == ret)
	{
		fprintf(stderr, "Connection failed: %s\\n", modbus_strerror(errno));
		modbus_free(ctx);
		return 1;
	}

	//5. 计算需测试的寄存器个数
	nums = ADDRESS_END - ADDRESS_START;



	//6. 申请内存 保存发送和接收的数据
	tab_rq_registers = (uint16_t*)malloc((nums + 1) * sizeof(uint16_t));
	if (NULL == tab_rq_registers)
	{
		fprintf(stderr, "malloc failed\\n");
		modbus_free(ctx);
		return 1;
	}
	else
	{
		memset(tab_rq_registers, 0, (nums + 1) * sizeof(uint16_t));
	}


	tab_rp_registers = (uint16_t*)malloc((nums + 1) * sizeof(uint16_t));
	if (NULL == tab_rp_registers)
	{
		fprintf(stderr, "malloc failed\\n");
		modbus_free(ctx);
		return 1;
	}
	else
	{
		memset(tab_rp_registers, 0, (nums + 1) * sizeof(uint16_t));
	}


	//7. 测试保持寄存器的单个读写
	//随机数字
	tab_rq_registers[0] = rand() % 100;
	printf("写入的值为: %hd\\n", tab_rq_registers[0]);
	//换行
	printf("\\n");

	addr = ADDRESS_START;以上是关于嵌入式Libmodbus之RTU模式Master端程序示例的主要内容,如果未能解决你的问题,请参考以下文章

嵌入式Libmodbus之RTU模式Slave端程序示例

嵌入式Libmodbus源码分析-RTU相关函数分析

嵌入式Libmodbus之TCP模式Slave端程序示例

基于libmodbus库实现modbus TCP/RTU通信

Modbus库开发笔记之六:Modbus RTU Master开发

Arm Qt 实战二:使用libmodbus创建MobusRtu-modbus_new_rtu为NULL的问题