主要测试读保持寄存器,地址4xxxx开始。不废话直接上代码
下面是从站(server)代码:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <iostream>
#include "modbus.h"
#include "modbus-tcp.h"
#include "modbus-version.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define NB_CONNECTION 5
//读保持寄存器地址数据的定义
const uint16_t UT_REGISTERS_ADDRESS = 0;
/* Raise a manual exception when this adress is used for the first byte */
const uint16_t UT_REGISTERS_ADDRESS_SPECIAL = 0;
const uint16_t UT_REGISTERS_NB = 0x10;
const int UT_REGISTERS_TAB[] = { 0x022B, 0x0001, 0x0064 };
const float test[] = { 123.123, 4.012, 5.789, 12345.34, 223.4, 34.2, 33.44, 234.204};
/* If the following value is used, a bad response is sent.
It's better to test with a lower value than
UT_REGISTERS_NB_POINTS to try to raise a segfault. */
const uint16_t UT_REGISTERS_NB_SPECIAL = 0x2;
modbus_t *ctx = NULL;
int server_socket;
modbus_mapping_t *mb_mapping;
static void close_sigint(int dummy)
{
close(server_socket);
modbus_free(ctx);
modbus_mapping_free(mb_mapping);
exit(dummy);
}
int FloatTohex(float HEX)//浮点数到十六进制转换
{
return *( int *)&HEX;
}
int main(void)
{
int master_socket;
int rc;
int header_length;
fd_set refset;
fd_set rdset;
/* Maximum file descriptor number */
int fdmax;
ctx = modbus_new_tcp("10.88.33.26", 10086);
header_length = modbus_get_header_length(ctx);
//new一个modbus的映射空间A
mb_mapping = modbus_mapping_new(
0,//读线圈
0,//读离散量输入
UT_REGISTERS_ADDRESS + UT_REGISTERS_NB,//读保持寄存器
0);//读输入寄存器
if (mb_mapping == NULL)
{
fprintf(stderr, "Failed to allocate the mapping: %s\n",
modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
/**初始化读保持寄存器**/
for(int i=0; i<8; i++)
{
uint16_t aimReg[2] = { 0 };
MODBUS_SET_INT32_TO_INT16(aimReg, 0, FloatTohex(test[i]));
std::cout<<std::hex<<FloatTohex(test[i])<<"; " << std::hex<<aimReg[0]<<", "<<std::hex<<aimReg[1]<<"\n";
for(int j = 0; j< 2; j++){
mb_mapping->tab_registers[UT_REGISTERS_ADDRESS+i*2+j]= aimReg[j];
}
}
server_socket = modbus_tcp_listen(ctx, NB_CONNECTION);
signal(SIGINT, close_sigint);
/* Clear the reference set of socket */
FD_ZERO(&refset);
/* Add the server socket */
FD_SET(server_socket, &refset);
/* Keep track of the max file descriptor */
fdmax = server_socket;
for (;;)
{
rdset = refset;
if (select(fdmax+1, &rdset, NULL, NULL, NULL) == -1)
{
perror("Server select() failure.");
close_sigint(1);
}
/* Run through the existing connections looking for data to be
* read */
for (master_socket = 0; master_socket <= fdmax; master_socket++)
{
if (FD_ISSET(master_socket, &rdset))
{
if (master_socket == server_socket)
{
/* A client is asking a new connection */
socklen_t addrlen;
struct sockaddr_in clientaddr;
int newfd;
/* Handle new connections */
addrlen = sizeof(clientaddr);
memset(&clientaddr, 0, sizeof(clientaddr));
newfd = accept(server_socket, (struct sockaddr *)&clientaddr, &addrlen);
if (newfd == -1)
{
perror("Server accept() error");
}
else
{
FD_SET(newfd, &refset);
if (newfd > fdmax)
{
/* Keep track of the maximum */
fdmax = newfd;
}
printf("New connection from %s:%d on socket %d\n", inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port, newfd);
}
}
else
{
/* An already connected master has sent a new query */
uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];
modbus_set_socket(ctx, master_socket);
rc = modbus_receive(ctx, query);
if (rc != -1)
{
modbus_reply(ctx, query, rc, mb_mapping);
}
else
{
/* Connection closed by the client, end of server */
printf("Connection closed on socket %d\n", master_socket);
close(master_socket);
/* Remove from reference set */
FD_CLR(master_socket, &refset);
if (master_socket == fdmax)
{
fdmax--;
}
}
}
}
}
}
return 0;
}
我们可以通过modscan32工具来读取数据测试。
下面是主站(client)代码:
#include <stdio.h>
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <errno.h>
//包含Modbus相关头文件
#include "modbus.h"
#include "time.h"
//相关参数设置
#define LOOP 1 //循环次数
#define ADDRESS_START 0 //测试寄存器起始地址
#define ADDRESS_END 15 //测试寄存器结束地址
int FloatTohex(float HEX){ return *( int *)&HEX; }
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. 创建一个TCP类型的变量
ctx = modbus_new_tcp("10.88.33.26", 10086);
if (NULL == ctx)
{
fprintf(stderr, "Error: %s\n", modbus_strerror(errno));
return 1;
}
else
{
printf("设置TCP成功\n");
}
//2. 设置Debug模式
ret = modbus_set_debug(ctx, TRUE);
if (-1 == ret)
{
fprintf(stderr, "Error: 设置Debug模式失败");
modbus_free(ctx);
return 1;
}
//3. 连接Server
ret = modbus_connect(ctx);
if (-1 == ret)
{
fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
modbus_free(ctx);
return 1;
}
//4. 计算需测试的寄存器个数
nums = ADDRESS_END - ADDRESS_START;
//5. 申请内存 保存发送和接收的数据
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));
}
//7. 测试保持寄存器的单个读写
//随机数字
const float test[] = { 13.123, 24.012, 5.789, 233.23,11.22,33.44,55.66, 77.88};
for(int i=0; i< 8; i++)
{
uint16_t aimReg[2] = { 0 };
MODBUS_SET_INT32_TO_INT16(aimReg, 0, FloatTohex(test[i]));
for(int j = 0; j< 2; j++){
tab_rq_registers[i*2+j]= aimReg[j];
}
}
//换行
printf("\n");
addr = ADDRESS_START;
ret = modbus_write_registers(ctx, addr, nums + 1, tab_rq_registers);
if (nums + 1 != ret)
{
printf("Error modbus_write_registers: %d\n", ret);
printf("Address: %d nums: %d\n", addr, nums + 1);
}
else
{
//读取
printf("success to write");
}
//8. 释放内存
free(tab_rq_registers);
//9. 断开连接
modbus_close(ctx);
modbus_free(ctx);
return 0;
}