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. WPARAM和LPARAM的含义

    lParam 和 wParam 是宏定义,一般在消息函数中带这两个类型的参数,通常用来存储窗口消息的参数. LRESULT CALLBACK WindowProc(HWND hwnd, UINT uM ...

  2. C#使用Newtonsoft.Json操作json

    1.下载 Newtonsoft.Json 右键引用,选择 管理NuGet程序包,选择浏览,输入log4net,然后点击下载 2.json数据的组装与解析 public class Class { pu ...

  3. ubuntu - 14.04,常用PPA源(第三方提供的deb格式安装文件)!!

    说明: 1,下面所有PPA源的执行命令,均为在shell中执行的命令,需要依次执行! 2,下面所有测试方法,均为在shell中执行的命令!! PPA源: 一,Oracle JDK:Oracle公司提供 ...

  4. Plexus容器学习笔记

    1. Plexus引入 Plexus是什么?它是一个IoC容器,由codehaus在管理的一个开源项目.和Spring框架不同,它并不是一个完整的,拥有各种组件的大型框架,仅仅是一个纯粹的IoC容器. ...

  5. AngularJS(三)——指令实战及自定义指令

    前言 上篇介绍了一些指令的应用,本篇介绍一些常用的用法格式. 内容 指令实战 下面通过输入一个名字实现实时更新文本内容. 需要的指令有: ng-app.ng-model.ng-bind.n-init ...

  6. poj2409(polya 定理模板)

    题目链接:http://poj.org/problem?id=2409 题意:输入 m, n 表示有 m 种颜色,要构造一个长度为 n 的手环,旋转和对称的只算一种,问能组成多少个不同的手环. 思路: ...

  7. Linux的SSH(Secure Shell Protocol)服务

    在数据传输前,SSH会对需要传输的数据进行加密,保证会话安全与会话中传输数据的安全,SSH客户端还包含一个远程拷贝scp. 1.SSH的结构 SSH服务由服务端软件(openssh)和客户端(SSH. ...

  8. echarts图标legend全选功能添加

    平时做图表的时候经常用echarts,确实是一款很好用的插件. 开发中遇到了一个问题,在展示的曲线,也就是legend很多的时候,不太好只展示其中几条.配置中是可以默认设置初始化是否展示,但不适用于全 ...

  9. ELK+Filebeat 实践 Error : read tcp 192.168.0.2:48968->121.40.216.20:5044: i/o timeout

    问题描述: 这是一个i/o time 的问题,一般考虑就是磁盘满的问题.以下是我遇到的具体问题: 1.Kibana页面刷新,没有新数据出来,再次刷新或者点击页面上其他地方,kibana就变成这样了: ...

  10. P3941 入阵曲

    \(\color{#0066ff}{ 题目描述 }\) 小 F 很喜欢数学,但是到了高中以后数学总是考不好. 有一天,他在数学课上发起了呆:他想起了过去的一年.一年前,当他初识算法竞赛的 时候,觉得整 ...