当前位置:   article > 正文

C语言基于libmodbus库Modbus Tcp 从站开发_libmodbus 从机

libmodbus 从机

C语言基于libmodbus库Modbus Tcp 从站开发

关键词

modbus TCP,从站,C语言,嵌入式,libmodbus库

理解

  • 当modbus tcp 作为从站(server)时,ip是被连接的服务器的ip,端口默认是502,当modbus tcp 作为主站(client)时,ip是将要去请求连接的地址,端口要大于1024,可以有多个主站,每个主站的端口不同。
  • 如果客户机与服务器的连接数量大于授权的连接数量,则最早建立的无用的连接被关闭。激活 访问控制机制检查远端客户机的 IP 地址是否是经过授权的。如果未经授权,将拒绝新的连接。
  • 从站又称服务器端server,从机,master。使用调试工具modbus poll模拟主站。
    主站主动找从站读写数据,客户端主动找服务端读写数据。所以当使用Modbus/TCP时,主站一般作为客户端,从站一般作为服务端。

设计流程

使用的是libmodbus标准库文件
1、初始化函数:

1、创建从机IP
	modbus_new_tcp
2、监听主站连接
	modbus_tcp_listen
3、设置阻塞或非阻塞模式
	阻塞:modbus_tcp_accept
	非阻塞:使用fcntl
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2、接收与回复函数

1、接收指令
	modbus_receive
2、回复
	modbus_reply
  • 1
  • 2
  • 3
  • 4

3、数据组包

1、指定起始地址
	modbus_mapping_new_start_address
2、创建数据组
	modbus_mapping_t  Map
  • 1
  • 2
  • 3
  • 4

实现

modbustcp.c

#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include "modbustcp.h"
#include "modbus.h"

#define MODBUS_TCP_POLL_CONNECT_MAX         1               /* 最多支持的主机数量 */
#define MODBUS_TCP_DEFAULT_IP               "192.168.1.1"
#define MODBUS_TCP_FUNCTION                 7               /* modbus tcp的function所在位置的偏移字节数 */
pthread_mutex_t dataMutex = PTHREAD_MUTEX_INITIALIZER;
static modbus_t *mb = NULL;
static int socketMb = -1, clientMb = -1;

static modbus_mapping_t *Map = NULL;

int ModbusTcp_Init()
{
	// 创建从机TCP
	mb = modbus_new_tcp(MODBUS_TCP_DEFAULT_IP, 502);

	if(NULL == mb)
	{
		return -1;
	}

	//设置调试模式,打开会有收发报文打印
	// modbus_set_debug(mb, TRUE);

	// 侦听主站连接
	socketMb = modbus_tcp_listen(mb, MODBUS_TCP_POLL_CONNECT_MAX);

	//阻塞模式,等待主站连接请求,没有则继续等待
	// modbus_tcp_accept(mb, &socketMb);
	
	if(-1 == socketMb)
	{
		modbus_free(mb);
		mb = NULL;
		return -1;
	}
	else
	{
		// 设置为非阻塞
		int flags = fcntl(socketMb, F_GETFL, 0);
		fcntl(socketMb, F_SETFL, flags | O_NONBLOCK);
	}

	// 设置服务端等待客户端请求超时时间
	modbus_set_indication_timeout(mb, 3, 0);
	return 0;
}
static void ModbusTcp_Disconnect_Client()
{
	if(clientMb > 0)
	{
		close(clientMb);
		clientMb = -1;
	}
}
static void ModbusTcp_Disconnect_Server()
{
	if(socketMb > 0)
	{
		close(socketMb);
		socketMb = -1;
	}
}
void ModbusTcp_Uninit()
{
	modbus_mapping_free(Map);

	modbus_close(mb);
	modbus_free(mb);

	ModbusTcp_Disconnect_Server();
	ModbusTcp_Disconnect_Client();
}
void Modbus_Data()
{
	int i;
	int cnt = 0;
	//只读 查询
	Map = modbus_mapping_new_start_address(0, 0, 0, 0, 0, 0, MODBUS_TCP_MAPPING_ADDR, MODBUS_TCP_DATA_SIZE * 个数);
	//xxx 是U32格式 ,采用大端显示  
	Map->tab_input_registers[cnt++] = xxx >> 16;
	Map->tab_input_registers[cnt++] = xx;
	//
	Map->tab_input_registers[cnt++] = yyy;
	Map->tab_input_registers[cnt++] = 0;
	Map->tab_input_registers[cnt++] =
	.
	.
	.
	//有规律的地址  如从10001开始,一个包占20个地址,有很多个包。
	cnt += (MODBUS_TCP_DATA_SIZE * (i + 1) - cnt);

}
void Modbus_Recive()
{
	//MODBUS_TCP_MAX_ADU_LENGTH在标准库里面定义
	uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH] = {0};  
	// 接收请求
	if(mb != NULL)
	{
		int ret = modbus_receive(mb, query);
		if(ret != -1)
		{
			uint16_t address = (query[MODBUS_TCP_FUNCTION + 1] << 8) + query[MODBUS_TCP_FUNCTION + 2];  //获取modbus的查询起始地址
			//MODBUS_TCP_MAPPING_ADDR 设定判断条件
			if(address >= MODBUS_TCP_MAPPING_ADDR)
			{
				pthread_mutex_lock(&dataMutex);
				Modbus_Data();
				pthread_mutex_unlock(&dataMutex);
				modbus_reply(mb, query, ret, Map);
			}
			else
			{
				modbus_reply(mb, query, ret, Map);
			}
		}
		else
		{
			ModbusTcp_Disconnect_Client();
			clientMb = modbus_tcp_accept(mb, &socketMb);
		}
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130

modbustcp.h

#include "modbus.h"
#define  MODBUS_TCP_DATA_SIZE                        20
#define  MODBUS_TCP_MAPPING_ADDR                     10001
void Modbus_Recive();
int ModbusTcp_Init();
void ModbusTcp_Uninit();
#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

主函数调用

#include "modbustcp.h"
int main(int argc, char **argv)
{
	ModbusTcp_Init();
	while1{
		Modbus_Recive();
	}
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

使用modbus poll 软件进行连接测试。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/971423
推荐阅读
  

闽ICP备14008679号