libmodbus庫使用RS485接口

問題:

在使用modbus時,選擇了github上的libmodbus庫,但是在實際使用中,不知道是自己不會用,還是libmodbus不支持,發現使用232時,可以正常使用,但是使用485接口時,就不能正常運行,自己在拿示波器抓波形等一通研究之後,先想了一種解決方法,但是個人感覺不是太好,但起碼先能跑通了485,寫一下,供大家參考。

libmodbus的github倉庫鏈接:https://github.com/stephane/libmodbus

下圖爲libmodbus源碼的文件:

解決方法:

1.我的解決方法是自己添加了兩個文件:modbus-485.cmodbus-485.h

/**
 * @file modbus-485.c
 * @brief modbus使用485通信的相關程序
 * @date 2020.03.30
 *
 * @author Lei
 * @version ver 1.0
 */

#include <stdio.h>
#include <termios.h>
#include <linux/ioctl.h>
#include <linux/serial.h>
#include <asm-generic/ioctls.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include "modbus-485.h"

/**
 * @fn rs485_enable
 * @brief 485使能函數
 * @param fd 485設備號
 * @param enable 是否使能
 * @return 成功:0 錯誤:其他
 */
int rs485_enable(const int fd, const RS485_ENABLE_t enable)
{
	struct serial_rs485 rs485conf;
	int res;

	/* Get configure from device */
	res = ioctl(fd, TIOCGRS485, &rs485conf);
	if(res < 0)
	{
		perror("Ioctl error on getting 485 configure:");
		close(fd);
		return res;
	}

	/* Set enable/disable to configure */
	if(enable)			// Enable rs485 mode
	{
		rs485conf.flags |= SER_RS485_ENABLED;
	}
	else        		// Disable rs485 mode
	{
		rs485conf.flags &= ~(SER_RS485_ENABLED);
	}

	rs485conf.delay_rts_before_send = 0x00000004;

	/* Set configure to device */
	res = ioctl(fd, TIOCSRS485, &rs485conf);
	if(res < 0)
	{
		perror("Ioctl error on setting 485 configure:");
		close(fd);
	}

	return res;
}

/**
 * @file modbus-485.h
 * @brief modbus使用485通信的相關程序
 * @date 2020.03.30
 *
 * @author Lei
 * @version ver 1.0
 */

#ifndef _MODBUS_485_H_
#define _MODBUS_485_H_

typedef enum
{
	DISABLE_485 = 0,
	ENABLE_485
}RS485_ENABLE_t;

int rs485_enable(const int fd, const RS485_ENABLE_t enable);

#endif

2.然後需要在modbus-rtu.c文件中添加幾句程序

在該文件中添加一句宏定義:(添加這一句即使用485,不添加則使用232)

#define RS485_MODE 1

3.同時modbus-rtu.c文件中大約273行位置的static ssize_t _modbus_rtu_send(modbus_t *ctx, const uint8_t *req, int req_length)函數進行修改:

修改前該函數程序:

static ssize_t _modbus_rtu_send(modbus_t *ctx, const uint8_t *req, int req_length)
{
#if defined(_WIN32)
    modbus_rtu_t *ctx_rtu = ctx->backend_data;
    DWORD n_bytes = 0;
    return (WriteFile(ctx_rtu->w_ser.fd, req, req_length, &n_bytes, NULL)) ? (ssize_t)n_bytes : -1;
#else
#if HAVE_DECL_TIOCM_RTS
    modbus_rtu_t *ctx_rtu = ctx->backend_data;
    if (ctx_rtu->rts != MODBUS_RTU_RTS_NONE) {
        ssize_t size;

        if (ctx->debug) {
            fprintf(stderr, "Sending request using RTS signal\n");
        }

        ctx_rtu->set_rts(ctx, ctx_rtu->rts == MODBUS_RTU_RTS_UP);
        usleep(ctx_rtu->rts_delay);

        size = write(ctx->s, req, req_length);

        usleep(ctx_rtu->onebyte_time * req_length + ctx_rtu->rts_delay);
        ctx_rtu->set_rts(ctx, ctx_rtu->rts != MODBUS_RTU_RTS_UP);

        return size;
    } else {
#endif
		return write(ctx->s, req, req_length);
#if HAVE_DECL_TIOCM_RTS
    }
#endif
#endif
}

修改後該函數程序:

static ssize_t _modbus_rtu_send(modbus_t *ctx, const uint8_t *req, int req_length)
{
#if defined(_WIN32)
    modbus_rtu_t *ctx_rtu = ctx->backend_data;
    DWORD n_bytes = 0;
    return (WriteFile(ctx_rtu->w_ser.fd, req, req_length, &n_bytes, NULL)) ? (ssize_t)n_bytes : -1;
#else
#if HAVE_DECL_TIOCM_RTS
    modbus_rtu_t *ctx_rtu = ctx->backend_data;
    if (ctx_rtu->rts != MODBUS_RTU_RTS_NONE) {
        ssize_t size;

        if (ctx->debug) {
            fprintf(stderr, "Sending request using RTS signal\n");
        }

        ctx_rtu->set_rts(ctx, ctx_rtu->rts == MODBUS_RTU_RTS_UP);
        usleep(ctx_rtu->rts_delay);

        size = write(ctx->s, req, req_length);

        usleep(ctx_rtu->onebyte_time * req_length + ctx_rtu->rts_delay);
        ctx_rtu->set_rts(ctx, ctx_rtu->rts != MODBUS_RTU_RTS_UP);

        return size;
    } else {
#endif
#if RS485_MODE
    	int num = write(ctx->s, req, req_length);
		usleep(10 * 1000);
		rs485_enable(ctx->s, ENABLE_485);
		return num;
#else
		return write(ctx->s, req, req_length);
#endif
#if HAVE_DECL_TIOCM_RTS
    }
#endif
#endif
}

4.這樣,libmodbus就能在Linux開發板上正常使用485進行通信了。

 

注意:這種方法不是特別好,但是能暫時解決問題。個人感覺這裏延時的時間,可以根據發送的數據長度和波特率來進行計算得出,而不只是給一個固定值(time = 10 * ByteLenth / bandrate * 1000(單位爲ms)),但這種方法還沒進行實驗測試,後續測試完成,再進行修改發博。如果各位有更好的方法,或者使用上述程序遇到問題,可以私信博主互相交流。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章