罗工773 2023-10-09 10:53 采纳率: 88.2%
浏览 19
已结题

最近调试一个激光测距模块使用modbus rtu协议,发现返回的数据不正常,尝试了用串口传输,发现返回的数据是正常的,但用libmodbus就无法返回正常数据,请问这是怎么回事?

最近调试一个激光测距模块使用modbus rtu协议,发现返回的数据不正常,尝试了用串口传输,发现返回的数据是正常的,但用libmodbus就无法返回正常数据,请问这是怎么回事?

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

#define GPIO_EXPORT_PATH "/sys/class/gpio/export"
#define GPIO_PIN_PATH "/sys/class/gpio/gpio41"  // X为GPIO引脚号

// 定义MODBUS设备参数
const char *serial_port = "/dev/ttyS3";  // 串口设备路径
const int baud_rate = 115200;
const char parity = 'N';
const int data_bits = 8;
const int stop_bits = 1;
const int slave_id = 1;

// 定义测量数据结构
typedef struct {
    float distance;
} MeasurementData;

int wp_gpio(){
        int gpio_pin = 41;  // 替换为您要操作的GPIO引脚号
    // 导出GPIO引脚
    FILE *export_file = fopen(GPIO_EXPORT_PATH, "w");
    if (export_file == NULL) {
        perror("Failed to open export file");
        return 1;
    }
    fprintf(export_file, "%d", gpio_pin);
    fclose(export_file);

    // 设置GPIO引脚为输出模式
    char direction_path[50];
    sprintf(direction_path, "%s/direction", GPIO_PIN_PATH);
    FILE *direction_file = fopen(direction_path, "w");
    if (direction_file == NULL) {
        perror("Failed to open direction file");
        return 1;
    }
    fprintf(direction_file, "out");
    fclose(direction_file);

    // 将GPIO引脚设置为低电平
    char value_path[50];
    sprintf(value_path, "%s/value", GPIO_PIN_PATH);
    FILE *value_file = fopen(value_path, "w");
    if (value_file == NULL) {
        perror("Failed to open value file");
        return 1;
    }
    fprintf(value_file, "0");  // 设置为低电平
    fclose(value_file);

    // 在这里可以执行其他操作

    // 将GPIO引脚设置为高电平(唤醒)
    value_file = fopen(value_path, "w");
    if (value_file == NULL) {
        perror("Failed to open value file");
        return 1;
    }
    fprintf(value_file, "1");  // 设置为高电平(唤醒)
    fclose(value_file);
    return 0;
}

int close_gpio() {
    int gpio_pin = 41;  // 替换为您要操作的GPIO引脚号

    // 将GPIO引脚设置为低电平
    char value_path[50];
    sprintf(value_path, "%s/value", GPIO_PIN_PATH);
    FILE *value_file = fopen(value_path, "w");
    if (value_file == NULL) {
        perror("Failed to open value file");
        return 1;
    }
    fprintf(value_file, "0");  // 设置为低电平
    fclose(value_file);

    // 取消导出GPIO引脚
    FILE *unexport_file = fopen("/sys/class/gpio/unexport", "w");
    if (unexport_file == NULL) {
        perror("Failed to open unexport file");
        return 1;
    }
    fprintf(unexport_file, "%d", gpio_pin);
    fclose(unexport_file);

    return 0;
}


// 初始化MODBUS通信并连接到设备
modbus_t *initialize_modbus() {
    modbus_t *ctx = modbus_new_rtu(serial_port, baud_rate, parity, data_bits, stop_bits);
    if (ctx == NULL) {
        fprintf(stderr, "Failed to create MODBUS context\n");
        return NULL;
    }

    modbus_set_slave(ctx, slave_id);

    if (modbus_connect(ctx) == -1) {
        fprintf(stderr, "MODBUS connection failed: %s\n", modbus_strerror(errno));
        modbus_free(ctx);
        return NULL;
    }

    return ctx;
}

// 读取测量数据
int read_measurement_data(modbus_t *ctx, MeasurementData *measurement) {
    // 发送打开激光命令
    uint16_t open_laser_cmd[] = {0x00, 0x01, 0x02, 0x00, 0x00};
    uint16_t open_buffer[16]={0};
    int write_result = modbus_write_registers(ctx, 0x1c05, sizeof(open_laser_cmd), open_laser_cmd);
    if (write_result == -1) {
        fprintf(stderr, "Failed to write open laser command: %s\n", modbus_strerror(errno));
        modbus_close(ctx);
        modbus_free(ctx);
        return 1;
    }

    usleep(500000);
    int ret = modbus_read_registers(ctx, 0x1c, 2, open_buffer);
    printf(" ret = %d\n",ret);
    printf("buffer: %x    %x\n",open_buffer[0],open_buffer[1]);

    // 开启测量
    uint16_t start_measurement_cmd[] = {0x00, 0x01, 0x02, 0x00, 0x00};
    uint16_t start_buffer[16]={0};
    int start_write = modbus_write_registers(ctx, 0x1c06, sizeof(start_measurement_cmd), start_measurement_cmd);
    if (start_write == -1) {
        fprintf(stderr, "Failed to write start laser command: %s\n", modbus_strerror(errno));
        modbus_close(ctx);
        modbus_free(ctx);
        return 1;
    }

    usleep(500000); // 500ms
    modbus_read_registers(ctx, 0x1c, 2, start_buffer);
    printf("start_buffer:%x    %x\n",start_buffer[0],start_buffer[1]);

    float measured_distance = -9999.0;
    uint16_t read_measurement_cmd[] = {0x00, 0x02};
    uint16_t measurement_data[4];

    // 读取测量值
    while (measured_distance <= 0) {
        for(int i = 0;i<=4;i++){
        // 发送读取测量值的命令
        modbus_write_registers(ctx, 0x0100, sizeof(read_measurement_cmd), read_measurement_cmd);

        // 等待读取完成
        usleep(500000); // 500ms

        // 读取测量值
        modbus_read_registers(ctx, 0x04, 4, measurement_data);

        printf("start_buffer:%x    %x   %x  %x\n",measurement_data[0],measurement_data[1],measurement_data[2],measurement_data[3]);
        // 解析测量值
        uint16_t high_byte = measurement_data[2];
        uint16_t low_byte = measurement_data[3];
        /*
        uint32_t combined_value = (high_byte << 16) | low_byte;
        memcpy(&measured_distance, &combined_value, sizeof(float));*/
        //memcpy(&measured_distance, measurement_data, sizeof(float));
        uint32_t combined_value = (high_byte << 16) | low_byte;
        float measured_distance;
        memcpy(&measured_distance, &combined_value, sizeof(float));

        // 根据您的需求,可以添加其他测量结果的处理

        if (measured_distance > 0) {
            break; // 退出循环
        }
    // 将测量值保存到measurement结构
    measurement->distance = measured_distance;

        usleep(100000); // 100ms
    }
    break;
    }

    return 0;
}


int main() {
    wp_gpio();
    // 初始化MODBUS通信
    modbus_t *ctx = initialize_modbus();
    if (ctx == NULL) {
        return 1;
    }

    // 读取测量数据
    MeasurementData measurement;
    if (read_measurement_data(ctx, &measurement) == -1) {
        fprintf(stderr, "Failed to read measurement data\n");
        modbus_close(ctx);
        modbus_free(ctx);
        return 1;
    }

    // 打印测量结果
    if (measurement.distance == -9999.0) {
        fprintf(stdout, "Measurement failed or signal weak\n");
    } else {
        fprintf(stdout, "Measured Distance: %.2f meters\n", measurement.distance);
    }

    // 关闭MODBUS连接和释放上下文
    modbus_close(ctx);
    modbus_free(ctx);

    close_gpio();

    return 0;
}


  • 写回答

1条回答 默认 最新

  • CSDN-Ada助手 CSDN-AI 官方账号 2023-10-09 12:02
    关注

    【相关推荐】



    • 帮你找了个相似的问题, 你可以看下: https://ask.csdn.net/questions/7651390
    • 除此之外, 这篇博客: Modbus驱动库—libmodbus驱动库的使用中的 为什么要使用驱动库? 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:

      上一篇文章,我们介绍了

      Modbus协议物理层和协议层,我们知道了Modbus是一种总线协议,它可以基于串口或网口,以基于串口的Modbus-RTU为例,我们需要在Windows或Linux下实现一个上位机,上位机的功能是读写Modbus接口传感器设备的数据,或者是和单片机等从设备进行交互。

      当需要向某个从机寄存器写入某个值时,如向01地址的设备,0x0105保持寄存器写入1个数据:0x0190为例,那么需要构建这样一个数据帧:

      主机发送: 01 06 01 05 01 90 99 CB

      01表示从机地址,06功能码表示写单个保持寄存器,0105表示寄存器地址,0190表示写入寄存器的数值,99 CB为CRC校验值。

      如果从机正确的收到了数据,会回复一个数据帧:

      从机回复: 01 06 01 05 01 90 99 CB

      所以作为主机,写数据的流程是:

      1. 构建一个Modbus-RTU数据帧

      2. 等待从机响应的数据

      3. 如果响应数据正确,说明写入成功,否则写入失败。

      读数据也是同样的流程,我们可以基于串口发送、串口接收函数、定时器等,自己写一个Modbus驱动库,来实现对从设备的读写。当然,也可以直接使用别人写好的Modbus驱动库,比如libmodbus,本文将介绍如何使用libmodbus驱动库,实现Modbus主机和从机。


    如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 系统已结题 3月1日
  • 已采纳回答 2月22日
  • 创建了问题 10月9日

悬赏问题

  • ¥15 软件工程用例图的建立(相关搜索:软件工程用例图|画图)
  • ¥15 如何在arcgis中导出拓扑关系表
  • ¥15 处理数据集文本挖掘代码
  • ¥15 matlab2017
  • ¥15 在vxWorks下TCP/IP编程,总是connect()报错,连接服务器失败: errno = 0x41
  • ¥15 AnolisOs7.9如何安装 Qt_5.14.2的运行库
  • ¥20 求:怎么实现qt与pcie通信
  • ¥50 前后端数据顺序不一致问题,如何解决?(相关搜索:数据结构)
  • ¥15 基于蒙特卡罗法的中介效应点估计代码
  • ¥15 罗技G293和UE5.3