目录

  • 版本和开发环境说明
  • 操作步骤
  • 源码的修改
    • 开放串口发送任意数据的API
    • 轮询modbus接收数据时不阻塞
  • 项目代码示例

版本和开发环境说明

libmodbus的官网上面有源码与文档,建议从上面获取一手资料。

  • libmodbus版本为 3.1.6
  • 交叉编译host为 Ubuntu16.04
  • 交叉编译target为 arm A7内核的imx6ull
  • 交叉编译器为 arm-linux-gnueabihf-gcc

操作步骤

交叉编译libmodbus的流程相对简单:

#use alias setcc to config cross compile environment
setcc
cd ./libmodbus-3.1.6
./configure --host=arm-linux-gnueabihf --prefix=$(pwd)/install
make & make install
  • 如果需要静态库,则./configure加上选项:
    –enable-static
  • 如果需要动态库,则./configure加上选项:
    –enable-shared

编译完成后,在install生成三个目录: include, lib, share,里面是我们需要用到的库文件与头文件。
lib文件夹下的libmodbus.so.5.1.0即为可以被调用的库文件,在实际编程的时候需要包含头文件:#include"modbus.h"

源码的修改

本章节是笔者在进行libmodbus开发时,根据项目需求对源码进行修改以获得新的功能特性。由于libmodbus已经对串口进行了较为完善的封装,我们无法利用这个库发送自定义格式的一些数据(某些设备或者从机在某些情况下并不是采用标准的modbus协议,需要我们自己自定义每一帧的数据)。因此,本章节的修改主要目的在于开放串口发送任意数据的API,已增加库的扩展性与通用性。同时,笔者需要在轮询modbus接收数据的时候不造成阻塞,开放了结构体 modbus_t的内部,以获得串口文件句柄,然后借助select机制将读取串口数据变为不阻塞的。

开放串口发送任意数据的API

进入到./libmodbus-3.1.6/src/中,修改modbus.c与modbus.h文件:
在modbus.c中定义函数:

int modbus_send_msg(modbus_t *ctx, uint8_t *msg, int msg_length)
{return ctx->backend->send(ctx, msg, msg_length);
}

在modbus.h中添加声明:

MODBUS_API int modbus_send_msg(modbus_t *ctx, uint8_t *msg, int msg_length);

即可在项目代码中调用modbus_send_msg(modbus_t *ctx, uint8_t *msg, int msg_length)函数发送任意数据。


轮询modbus接收数据时不阻塞

在modbus-rtu.c中,函数:

static ssize_t _modbus_rtu_recv(modbus_t *ctx, uint8_t *rsp, int rsp_length)
{#if defined(_WIN32)return win32_ser_read(&((modbus_rtu_t *)ctx->backend_data)->w_ser, rsp, rsp_length);
#elsereturn read(ctx->s, rsp, rsp_length);
#endif
}

由于采用了read机制,会使得程序在轮询接收数据的时候(在modbus.c中),造成阻塞。

int modbus_receive(modbus_t *ctx, uint8_t *req)
{if (ctx == NULL){errno = EINVAL;return -1;}return ctx->backend->receive(ctx, req);
}

修改代码,开放***typedef struct _modbus modbus_t***的内部,以获得串口文件句柄,然后借助select机制将读取串口数据变为不阻塞的。具体操作如下:

将modbus-private.h中关于_modbus结构体的定义、_modbus_backend结构体、_sft结构体的定义直接复制到已经编译好的库“./install/include/modbus/modbus.h”中。不需要修改源码,亦不影响编译过程。

/* This structure reduces the number of params in functions and so* optimizes the speed of execution (~ 37%). */
typedef struct _sft {int slave;int function;int t_id;
} sft_t;typedef struct _modbus_backend {unsigned int backend_type;unsigned int header_length;unsigned int checksum_length;unsigned int max_adu_length;int (*set_slave) (modbus_t *ctx, int slave);int (*build_request_basis) (modbus_t *ctx, int function, int addr,int nb, uint8_t *req);int (*build_response_basis) (sft_t *sft, uint8_t *rsp);int (*prepare_response_tid) (const uint8_t *req, int *req_length);int (*send_msg_pre) (uint8_t *req, int req_length);ssize_t (*send) (modbus_t *ctx, const uint8_t *req, int req_length);int (*receive) (modbus_t *ctx, uint8_t *req);ssize_t (*recv) (modbus_t *ctx, uint8_t *rsp, int rsp_length);int (*check_integrity) (modbus_t *ctx, uint8_t *msg,const int msg_length);int (*pre_check_confirmation) (modbus_t *ctx, const uint8_t *req,const uint8_t *rsp, int rsp_length);int (*connect) (modbus_t *ctx);void (*close) (modbus_t *ctx);int (*flush) (modbus_t *ctx);int (*select) (modbus_t *ctx, fd_set *rset, struct timeval *tv, int msg_length);void (*free) (modbus_t *ctx);
} modbus_backend_t;struct _modbus {/* Slave address */int slave;/* Socket or file descriptor */int s;int debug;int error_recovery;struct timeval response_timeout;struct timeval byte_timeout;struct timeval indication_timeout;const modbus_backend_t *backend;void *backend_data;
};

modbus_t的成员s即串口文件句柄(Socket or file descriptor)


项目代码示例

在实际项目中(以C++/Qt4.8为例)可以通过以下方式轮询modbus,将接收数据变为不阻塞:

modbus_mapping_t *mb_mapping;
modbus_t *ctx;void ModbusThread::run()
{int rc;fd_set set;timeval timeout;timeout.tv_sec = 0;timeout.tv_usec = 1000;//    int use_backend;//初始化modbus rtuctx = modbus_new_rtu(SLAVE_PORT, 9600, 'N', 8, 1);//设定从设备地址modbus_set_slave(ctx, SLAVE_ADDR);//modbus连接modbus_connect(ctx);//qDebug()<<"serial port fd is: "<<ctx->s;//寄存器map初始化mb_mapping = modbus_mapping_new(MODBUS_MAX_WRITE_BITS, MODBUS_MAX_READ_BITS , MODBUS_MAX_WR_WRITE_REGISTERS, MODBUS_MAX_READ_REGISTERS);if (mb_mapping == NULL){fprintf(stderr, "Failed to allocate the mapping: %s\n",modbus_strerror(errno));modbus_free(ctx);return;}if (isRemoteMonitoringUsed_dialog == true){qDebug()<<"isRemoteMonitoringUsed_dialog:"<<isRemoteMonitoringUsed_dialog;mainWidget->timer_uploadDataToCloud.start(10000);qDebug()<<"Remote Monitoring is used.";}else {qDebug()<<"isRemoteMonitoringUsed_dialog:"<<isRemoteMonitoringUsed_dialog;qDebug()<<"Remote Monitoring is not used.";}while(true){uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];SyncModbusRegisters();FD_ZERO(&set);FD_SET(ctx->s, &set);                       //此处将读取的串口fd加入队列select(ctx->s+1,&set,NULL,NULL,&timeout);   //此次判断读取的队列if(!FD_ISSET(ctx->s, &set)){continue;}//轮询接收数据,并做相应处理QMutexLocker locker1(&modbusPortLock);rc = modbus_receive(ctx, query);locker1.unlock();if (rc > 0){//QString receivedData = "";//for(int i=0; i< rc ; i++)//{//  receivedData.append(QString::number(query[i],16)).append(" ");//}//qDebug()<<receivedData;modbus_reply(ctx, query, rc, mb_mapping);ModbusSyncAction();}else if (rc == -1){//qDebug()<<"Modbus connection closed by the client or error.";//break;}else{}QMutexLocker locker(&m_lock);if(!isThreadLoop){qDebug()<<"isThreadLoop:"<<isThreadLoop;break;}}printf("Modbus thread is terminated: %s\n", modbus_strerror(errno));modbus_mapping_free(mb_mapping);/* For RTU, skipped by TCP (no TCP connect) */modbus_close(ctx);modbus_free(ctx);
}

imx6ull交叉编译libmodbus相关推荐

  1. 中国ai chip初创公司_这个AI事实检查初创公司正在做Facebook和Twitter不会做的事情

    中国ai chip初创公司 By Jared Newman 杰里德·纽曼(Jared Newman) In late April, an investigation by The Guardian t ...

  2. linux内核imx6,imx6ull之linux内核移植

    imx6ull开发环境之系统安装请参考:https://www.cnblogs.com/gxlblogs/p/14382547.html imx6ull交叉编译工具链安装 请参数:https://ww ...

  3. 嵌入式linux/鸿蒙开发板(IMX6ULL)开发(十四)文字显示

    文章目录 一.文字显示 1.1 字符的编码方式 1.1.1 编码和字体 a. ASCII b. ANSI c. UNICODE 1.1.2 UNICODE编码实现 1.2 ASCII字符点阵显示 1. ...

  4. Freetype 的安装与使用

    4 交叉编译程序 4.1 程序运行的一些基础知识 编译程序时去哪找头文件? 系统目录:就是交叉编译工具链里的某个 include 目录: 也可以自己指定:编译时用 " -I dir &quo ...

  5. 【iMX6ULL】触觉 imx6ull开发板交叉编译环境搭建

      开发IMX6ULL需要有一个安装了交叉编译器的linux操作系统的开发环境,用于编译开发板的uboot.kernel.文件系统和应用软件.下面以触觉智能imx6ull开发板为例. 1.开发环境说明 ...

  6. 交叉编译 arm-poky-linux-gnueabi-gcc libmodbus库笔记

    1:修改makefile CC  =   arm-poky-linux-gnueabi-gcc -march=armv7-a -mthumb-interwork -mfloat-abi=hard -m ...

  7. NXP IMX6ULL的官方文档、官方BSP、交叉编译工具链下载

    目录 1 官网下载BSP以及相关文档 1.1 文档下载 1.2 NXP 官方uboot和kernel源码下载 1.3 官方评估板硬件资料下载 1.4 官方BSP下载 2 官网SDK下载 3 交叉编译工 ...

  8. imx6ull项目也是封装成脚本安装 Poky 交叉编译工具链类似ATK-STM32MP157交叉编译

    [正点原子MP157连载]第六章 ATK-STM32MP157交叉编译篇 学习 2021-05-29 10:20887阅读 · 25喜欢 · 3评论 粉丝:17.3万文章:122 关注 正点原子提供了 ...

  9. QT4.8.6的交叉编译 - 编译平台:Ubuntu 20.04 LTS,目标平台:linux/imx6ull

    版本记录表 开发环境 编译环境: 64位Ubuntu 20.04 LTS 交叉编译工具链: arm-linux-gnueabihf-GCC 4.9.1 本地编译器:gcc version 7.5.0 ...

最新文章

  1. Python使用matplotlib可视化散点图、并在可视化图像的底部和右边添加边缘直方图、自定义边缘直方图的色彩(Marginal Histogram)
  2. Github霸榜月余,原来是阿里技术官的千亿级并发系统设计手册上线了
  3. 如何让 python 处理速度翻倍?内含代码
  4. ctrl f显示查找计算机,请教:快捷方式查找Ctrl+F失效,怎么办 – 手机爱问
  5. 海信电视root工具_中国企业的远见:用一项自主技术,打败日韩电视,成为行业引领者...
  6. Spring : Spring容器之SmartLifeCycle的简单使用
  7. YunOS互联网汽车:妥协下的创新
  8. 给PhotoShop安装Portraiture插件
  9. EasyUI DataGrid 可编辑列级联操作
  10. 纳加服务器授权文件,VJSAC(纳加VJMS3服务管理终端)
  11. 统计学常用的数据分析方法总结
  12. 利用 Erdas 软件将矿区拐点坐标转换为经纬度坐标
  13. TypesScript + Nodejs + Express + Mongoose 实现 RESTful API 实战视频教程(33 个视频)
  14. Word 2010版本
  15. 马尔可夫链(Markov chain)的性质
  16. docker安装konga
  17. JAVA中JButton常用设置
  18. OMAP4 pandaboard ES开发资料总结
  19. 基于历史K线数据比较的量化选股方法及其系统分享
  20. 联想服务器提示系统初始化,联想服务器故障

热门文章

  1. 算法美学!从欧拉公式到傅里叶动画!
  2. 豌豆荚手机精灵试用测试
  3. Windows Server 2012 R2 此更新不适用于你的计算机 问题解决
  4. HTML基础——header, nav, footer, article, section, aside
  5. 【计算机网络】实验四 应用层和传输层协议分析(PacketTracer)
  6. python中字典的使用
  7. 过秦楼 . 碧玉连空
  8. (6)Scrum Master的七种武器之碧玉刀多情环
  9. 在网上如何找靠谱的兼职?
  10. MySQL数据库安装教程(windows)