我在一条RS485总线上有多个从站。到目前为止,我一直在使用pymodbus,但我对它的性能和其他问题不太满意。所以我想测试一下libmodus并使用它。
我写了一个最小的程序来读取我的从属的型号
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <modbus.h>
#include <errno.h>
char *bigendian_vec_to_str(uint16_t *vec, size_t vec_size, char *buff, size_t buff_len)
{
memset(buff, 0, sizeof *buff * buff_len);
int i;
for(i = 0; i < vec_size; ++i)
{
uint16_t fl = vec[i] >> 8;
uint16_t sl = vec[i] & 0xff;
if(2*i >= buff_len - 1)
return buff;
if(fl == 0)
return buff;
buff[2 * i] = fl;
if(2*i + 1 >= buff_len - 1)
return buff;
if(sl == 0)
return buff;
buff[2 * i + 1] = sl;
}
return buff;
}
char *get_model_name_of(modbus_t *modbus, int slave, char *buff, size_t buff_len)
{
modbus_flush(modbus);
modbus_set_slave(modbus, slave);
int rc;
uint16_t reg[9];
memset(reg, 0, sizeof reg);
rc = modbus_read_registers(modbus, 0xe, 8, reg);
if (rc == -1) {
fprintf(stderr, "Error %d while reading: %s\n", errno, modbus_strerror(errno));
return NULL;
}
return bigendian_vec_to_str(reg, 8, buff, buff_len);
}
int main(void)
{
modbus_t *modbus = modbus_new_rtu("/dev/ttyUSB0", 9600, 'N', 8, 1);
modbus_rtu_set_serial_mode(modbus, MODBUS_RTU_RS485);
if (modbus_connect(modbus) == -1) {
fprintf(stderr, "Connexion failed: %s\n", modbus_strerror(errno));
modbus_free(modbus);
return -1;
}
char buff[1024];
int i;
for(i = 2; i < 5; ++i)
{
printf("Model of slave %d: %s\n", i, get_model_name_of(modbus, i, buff, sizeof buff));
}
modbus_free(modbus);
return 0;
}当我运行这段代码时,我得到
Model of slave 2: LEFS25B-600
Error 110 while reading: Connection timed out
Model of slave 3: (null)
Model of slave 4: LEHF10K2-16第二个模块没有响应,这似乎很奇怪。所以我把get_model_name_of循环到2,3,4,2,3,4,2,3,4....每隔一秒的读取尝试都以Error 110 while reading: Connection timed out结束。在行modbus_set_slave(modbus, slave);之后我添加了
usleep(0.005 * 1000000);然后我就再也没有暂停了。我看了两遍手册页,没有发现任何关于这一点的警告。我也在谷歌上搜索,但我找到的“相似”帖子都没有任何帮助。
处理多个从属的最好方法是什么?为什么在这里增加半毫秒的睡眠会有帮助呢?我的意思是libmodus上的代码
static int _modbus_set_slave(modbus_t *ctx, int slave)
{
/* Broadcast address is 0 (MODBUS_BROADCAST_ADDRESS) */
if (slave >= 0 && slave <= 247) {
ctx->slave = slave;
} else {
errno = EINVAL;
return -1;
}
return 0;
}在上下文中设置内部值。在更改上下文中的内部值和读取/写入总线之间是否存在时间限制?如果是这样,我应该在set_slave之后等待多长时间?为什么libmodbus要全局设置从属id,而不是像其他库(如pymodbus)那样将其作为read/write方法中的参数?
或者我只是不正确地使用了这个API?
谢谢
发布于 2018-10-02 09:09:33
我可能错了..。但是..。据我所知。modbus主机发出一个请求,目标是特定的从机号。其目的是接收来自目标从站的应答,然后向下一个从站发送请求,并等待来自第二个从站的应答。如果在没有等待第一个从站回复的情况下发出请求..则有可能错过来自第二个从设备(或第三个或任何数量的从设备)的应答,而第一个从设备应答正在由主设备发送和接收。
我不擅长C语言编程。但我建议你检查一下this..as,我想这可能是为什么你添加一个延迟似乎有帮助的原因。(还有..Modbus协议的一部分确实要求在信号传输中暂停以定义传输的开始和结束。)如果我是正确的,那么只有当您知道正在发送的数据的大小和计算response..For的时间时,使用延迟才能很好地工作。其他情况下,某种握手将是安全的。例如读取线圈..其指示数据是否被刷新并准备好作为可能的交通信号灯从从机读取。以控制去往其它从站的请求的时序,并避免响应的冲突。再一次..。我不擅长C语言,如果我曲解了程序..请忽略我所说的话。如果有帮助的话..我会很高兴听到的。
彼得
https://stackoverflow.com/questions/34387820
复制相似问题