1.   半双工模式实时检测串口

ComHalfDuplex类是为了解决上位机发送控制指令和下位机发送数据会在半双工RS485总线中产生冲突引起乱码而引入的(v0.010版本引入)。

解决冲突的原理主要是实时检测串口,若一段时间内下位机不发送数据,则认为此时串口是空闲的,可以向下位机发送数据。

若在等待过程中接收到下位机发送数的据,则重置超时定时器。实时检测串口采用阻塞式方法waitForReadyRead等待串口接收到数据,

顾名思义,该方法其实就是等到readyRead信号到来时停止阻塞并继续运行代码,理论上和ComFullDuplex的实际做法是一样的,而如果要ComFullDuplex类实现实时检测串口,需要添加一个读取超时定时器并对超时做一定处理(未做处理)。

1.1.  CommForWin (deprecated)

CommForWin类是利用Windows的C API进行串口的读取操作。主要原理及任务和ComHalfDuplex类似,用的同样是阻塞式方法读取串口,实现实时检测串口。

需要注意的是,程序运行时只会用到这三个类中的某一个类,其中CommForWin不推荐使用:

1、许多继承下来的方法只是一个空实现,需要用Windows API来实现代码;

2、这部分代码只能在Windows使用,不如使用Qt提供的API;

3. 需要将校验位、波特率等对应到Qt的校验位和波特率上,否则将会导致串口无法正确收发数据。

串口是线程独占的,无法在其它线程或进程中打开同一个串口(若跨线程调用方法将会出现警告)。

AbstractComm的这两个实现类ComHalfDuplex和CommForWin是为了解决无法实时检测串口的问题。因为串口收发数据时有16ms的间隔,所以半双工模式无法正常工作,关于FTR232的半双工工作模式问题可参考我的另一篇文章:https://www.cnblogs.com/brifuture/p/9113091.html

2. 控制器与设备的交互

  每个协议中都应该维护一个待查讯的指令队列,若当前指令尚未执行完毕(成功执行或超时都视为执行完毕),后续需要查询的指令需要排队。当一个指令执行完毕时,CommManager会通知该命令所属的协议,取出该协议的指令队列中的下一条指令,并执行该指令。在当前协议中的所有命令都处理完毕后,再从其它的协议中选择。每当有指令的入队和出队操作时,CommManager发出cmdCountChanged信号,通知其它部件当前队列的长度有变化。

队首指令从队列中弹出时,将进入到子线程中等待查询,为了避免多线程竞争访问资源,在设置指令时需要进行加锁操作,保证线程安全。同样的,当指令成功执行后,对指令进行清除(防止不必要的重复查询)也需要进行加锁操作,操作完成后释放锁。

控制器在主线程(UI线程)中执行,串口操作在子线程中执行,控制器的主要工作是将来自串口的信号转发给其它部件:

图  Com中信号和槽的连接

  对串口操作类的调用并没有用到信号和槽,而是直接使用了QMetaObject::invokeMethod方法进行调用,原理和信号槽机制是类似的,但不需要特意声明一个信号了,使用起来比较方便。

3. 网络接口

  网络接口CommNetwork实现了AbstractComm 的接口,作为网络通讯的实现类,其与串口通讯的代码大同小异。内部实际负责通讯的对象为QTcpSocket,与QSerialPort类似(两者都是QIODevice的子类,所以接口大部分也相同)。

4. CommandObject与DataObject

  CommandObject和DataObject是在CommManager和AbstractProtocol之间传递信息时用到的对象。使用CommandObject可以获取命令的内容和其它的信息,使用DataObject可以获取下位机发送的数据和其它信息。

  比起直接在CommManager和AbstractProtocol之间传递QByteArray来说,使用这两种数据对象可以方便程序扩展,以后需要增加传递其它信息时添加这两种数据对象的接口即可。

5. 总结

  最开始编写communicator库的目的是为了让已有的程序分层,communicator作为最底层负责处理的都是QByteArray字节,后来对代码进行优化之后程序的逻辑更加清楚,而且communicator层的代码基本上不需要改动,直接就将其编译成静态库文件,减少项目重新构建时所需的编译时间。

  将communicator作为静态库构建的过程中也出现不少问题,之前并没有构建过静态库/动态库,对这方面不太了解。在实际项目中遇到过这样的问题:

General库(构建为动态库)引用了Communicator库,并在general库中调用Comm命令空间的初始化方法,应用程序引用general动态库和Communicator静态库,运行Demo程序时,发现经常出现内存访问错误的问题,经过调试后发现general库中虽然对Communicator进行了初始化,但demo应用程序中Communicator却没有初始化,Comm::manager 指针始终为空指针。

  在程序中对Communicator库进行初始化操作后仍然不能解决问题,原因可能在于动态库和应用程序之间的全局变量不能共享。最后把general库改为静态链接库就可以解决这个问题。

另外关于Qt的应用程序构建还有很多值得学习的东西,在构建Communicator这个库时尝试使用.pri文件,它可以简化库文件的引用,

不过它更多的用处应该是可以把一个大的项目分成若干个小部分,方便项目的构建和测试。例如我在Communicator项目中添加一个Communicator.pri文件。

Communicator 的代码仓库:https://github.com/BriFuture/qt_components/tree/master/basic_communicator

自定义Qt组件-通讯模块(P3)的更多相关文章

  1. 自定义Qt组件-通讯模块(P1)

    通讯模块Communicator 通讯模块是整个项目设计中位于最底层的模块,用于处理与串口或网络等设备的通讯,所有设备的通讯通过CommManager类完成,上层软件设计时需要根据comm模块(主要是 ...

  2. 自定义Qt组件-通讯模块(P2)

    1.  抽象协议AbstractProtocol 抽象协议AbstractProtocol定义CommManager与协议之间的接口.AbstractProtocol中的一些属性(如enabled)用 ...

  3. C/C++ Qt TableDelegate 自定义代理组件

    TableDelegate 自定义代理组件的主要作用是对原有表格进行调整,例如默认情况下Table中的缺省代理就是一个编辑框,我们只能够在编辑框内输入数据,而有时我们想选择数据而不是输入,此时就需要重 ...

  4. SSIS自定义数据流组件开发(血路)

    由于特殊的原因(怎么特殊不解释),需要开发自定义数据流组件处理. 查了很多资料,用了不同的版本,发现各种各样的问题没有找到最终的解决方案. 遇到的问题如下: 用VS2015编译出来的插件,在SSDTB ...

  5. Android Studio开发基础之自定义View组件

    一般情况下,不直接使用View和ViewGroup类,而是使用使用其子类.例如要显示一张图片可以用View类的子类ImageView,开发自定义View组件可分为两个主要步骤: 一.创建一个继承自an ...

  6. [UE4]自定义MovementComponent组件

    自定义Movement组件 目的:实现自定义轨迹如抛物线,线性,定点等运动方式,作为组件控制绑定对象的运动. 基类:UMovementComponent 过程: 1.创建UCustomMovement ...

  7. Qt组件中的双缓冲无闪烁绘图

      双缓冲绘图在Qt4中,所有的窗口部件默认都使用双缓冲进行绘图.使用双缓冲,可以减轻绘制的闪烁感.在有些情况下,用户要关闭双缓冲,自己管理绘图.下面的语句设置了窗口部件的Qt::WA_PaintOn ...

  8. 【转】Android学习基础自定义Checkbox组件

    原文网址:http://forum.maiziedu.com/thread-515-1-1.html heckbox组件是一种可同时选中多项的基础控件,即复选框,在android学习中,Checkbo ...

  9. 自定义Qt按钮

    转自:http://blog.csdn.net/starcloud_zxt/article/details/5185556 Qt自带的PushButton样式比较单一,在开发的时候往往按钮的形状各异, ...

随机推荐

  1. javascript window.showModalDialog不兼容goole解决方案

    window.showModalDialog不兼容goole解决方案 一.弹框方案: 1.window.open; 2.window.showModalDialog; 3.div制作窗口:(本节忽略) ...

  2. eclise远程调试

    配置很简单,如下: 1. tomcat在bin/catalina.sh中添加如下:declare -x CATALINA_OPTS="-server -Xdebug -Xnoagent -D ...

  3. MySql数据库内部常用命令大全

    1.     连接Mysql 格式: mysql -h主机地址 -u用户名 -p用户密码 1)         连接到本机上的MYSQL. 首先打开DOS窗口,然后进入目录mysql\bin,再键入命 ...

  4. github blog

    git version 2.18.0.windows.1 node-v10.8.0-win-x64.zip 1 安装node.js,直接下载,配置环境变量即可(win10重启生效) 2 git安装,略 ...

  5. 【Java】Observer Pattern

    前言 代码来源于生活,更加高于生活.设计模式让我们的生活更加的方便.观测一个东西,盯着一个东西,关注一个公众号,这些东西,如果没有即时通知的话,我们又特别想了解这方面的内容,那么我们除了一直耗着时间找 ...

  6. DP【洛谷P3135】[USACO16JAN]堡哞Fort Moo

    [洛谷P3135][USACO16JAN]堡哞Fort Moo Bessie和她的朋友Elsie正在建筑一个堡垒,与任何一个好的堡垒一样,这个需要一个强固的框架.Bessie想造一个轮廓是1m宽的空心 ...

  7. java 反射 处理 空值

    package org.zkdg.utils.spring.annotations.impl; import java.lang.annotation.Annotation; import java. ...

  8. composer.json 配置设置

    配置文件的值为 key:val 必须双引号包裹 一.配置文件 名字 name包名称由用户名名称和仓库名称组成包版本限制来请求Monolog软件包 1.0.*.这意味着1.0开发分支中的任何版本,或大于 ...

  9. javascript 获取当前 URL 参数的两种方法

    window.location.host; //返回url 的主机部分,例如:www.xxx.com window.location.hostname; //返回www.xxx.com window. ...

  10. BZOJ 4373 算术天才⑨与等差数列 线段树+set(恶心死我了)

    mdzz,这道题重构了4遍,花了一个晚上... 满足等差数列的条件: 1. 假设min是区间最小值,max是区间最大值,那么 max-min+k(r−l) 2. 区间相邻两个数之差的绝对值的gcd=k ...