一、以太网(modbus tcp/ip)
Modbus设备可分为主站(poll)和从站(slave)。主站只有一个,从站有多个,主站向各从站发送请求帧,从站给予响应。在使用TCP通信时,主站为client端,主动建立连接;从站为server端,等待连接。
二、所需的libmobus API(server端)
- 使用modbus_new_tcp创建一个modbus的上下文,ip地址为开发板自身的ip
modbus_t *ctx = modbus_new_tcp(const char *ip_address, int port); //开发板ip自行修改,port常用502。
- 地址映射
使用modbus_mapping_new_start_address初始化从站地址的映射,即线圈状态、离散输入、保持寄存器、输入寄存器的首地址和个数的映射。该首地址供主站进行寻址读取数值或写入数值。
modbus_mapping_t *mb_mapping = modbus_mapping_new_start_address(
unsigned int start_bits, unsigned int nb_bits,
unsigned int start_input_bits, unsigned int nb_input_bits,
unsigned int start_registers, unsigned int nb_registers,
unsigned int start_input_registers, unsigned int nb_input_registers);
完成mb_mapping的映射后需要绑定table的地址空间,即给相应指针开辟空间。该空间为后续写入和读取数据使用。
/* map 地址与存储空间 */
mb_mapping->tab_bits = UT_BITS_TAB;
mb_mapping->tab_input_bits = UT_INPUT_BITS_TAB;
mb_mapping->tab_registers = UT_REGISTERS_TAB;
mb_mapping->tab_input_registers = UT_INPUT_REGISTERS_TAB;
3.监听连接
使用以上创建的modbus tcp server监听客户的接入
int socket = modbus_tcp_listen(modbus_t *ctx, int nb_connection);
modbus_tcp_accept(modbus_t *ctx, int *s);
4.阻塞接收数据
接收主站的请求数据(原始数据)并保存在req指定的空间中。
modbus_receive(modbus_t *ctx, uint8_t *req);
5.响应接收
modbus_reply会自动解析modbus请求并做响应
modbus_reply(modbus_t *ctx, const uint8_t *req,
int req_length, modbus_mapping_t *mb_mapping);
三、从站(server)程序
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <modbus/modbus.h>
int main(void)
{
int socket;
modbus_t *ctx;
modbus_mapping_t *mb_mapping;
ctx = modbus_new_tcp("127.0.0.1", 1502); //开发板ip自行修改
/* modbus_set_debug(ctx, TRUE); */
mb_mapping = modbus_mapping_new_start_address(
UT_BITS_ADDRESS, UT_BITS_NB,
UT_INPUT_BITS_ADDRESS, UT_INPUT_BITS_NB,
UT_REGISTERS_ADDRESS, UT_REGISTERS_NB_MAX,
UT_INPUT_REGISTERS_ADDRESS, UT_INPUT_REGISTERS_NB);
if (mb_mapping == NULL) {
fprintf(stderr, "Failed to allocate the mapping: %s\n",
modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
socket = modbus_tcp_listen(ctx, 1);
modbus_tcp_accept(ctx, &socket);
for (;;) {
uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];
int rc;
rc = modbus_receive(ctx, query);
if (rc != -1) {
/* rc is the query size */
modbus_reply(ctx, query, rc, mb_mapping);
printf("In the loop \n");
} else {
/* Connection closed by the client or error */
break;
}
}
printf("Quit the loop: %s\n", modbus_strerror(errno));
modbus_mapping_free(mb_mapping);
modbus_close(ctx);
modbus_free(ctx);
return 0;
}