赞
踩
modbus TCP,从站,C语言,嵌入式,libmodbus库
使用的是libmodbus标准库文件。
1、初始化函数:
1、创建从机IP
modbus_new_tcp
2、监听主站连接
modbus_tcp_listen
3、设置阻塞或非阻塞模式
阻塞:modbus_tcp_accept
非阻塞:使用fcntl
2、接收与回复函数
1、接收指令
modbus_receive
2、回复
modbus_reply
3、数据组包
1、指定起始地址
modbus_mapping_new_start_address
2、创建数据组
modbus_mapping_t Map
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); } } }
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
主函数调用
#include "modbustcp.h"
int main(int argc, char **argv)
{
ModbusTcp_Init();
while(1)
{
Modbus_Recive();
}
return 0;
}
使用modbus poll 软件进行连接测试。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。