通讯模块Communicator

通讯模块是整个项目设计中位于最底层的模块,用于处理与串口或网络等设备的通讯,所有设备的通讯通过CommManager类完成,上层软件设计时需要根据comm模块(主要是CommManager)提供的接口访问设备。通讯组件实现类的重要类是 QIODevice,所有通讯过程中发送/接收的字符都经过QIODevice发送到设备中。

通讯模块的测试和API 文档 基本完成,生成文档可使用 qdoc 工具,将代码中的注释转换成网页格式的文档,文档图如下:

Communicator层中提供了Comm 命名空间简化使用该库的过程,要使用该库文件,可以参考下列方式:

1.         通讯设备:串口或网络

磁罗盘通过USB-RS485转接线连接到PC上位机,从而实现的上下位机通讯,由于半双工的RS485无法同时收发数据,若在下位机发送数据时,上位机向下位机发送指令,将会导致RS485上电平异常,通讯失败,上位机接收数据时出现乱码(由于下位机程序设计的原因,不能同时收发数据,所以此时下位机一般不会接收数据)。为了找到下位机发送语句的间隔而找到合适的发送指令时机,通讯代码使用多线程+阻塞式的方法监听串口,在通讯接口空闲时上位机才发送数据(实际上RS485是通过FT232r芯片转接到USB上连接电脑,所以其实是通过USB端口监听RS485串口)。

若设备的连接方式支持全双工模式,可以设置串口的工作模式为全双工,全双工模式和半双工的模式区别在于:全双工在接收到管理器的查询指令后将会立即将指令写入到设备中;半双工则会监听设备,在线路空闲时发送指令。

为实现远程操控下位机,通讯设备中新增加了网络通讯模式。网络通讯模式与串口通讯模式差别不大,主要差别在于网络通讯要指定端口,而串口通讯要指定波特率停止位等。

2.         控制器CommManager

项目中串口控制器的类为CommManager,该类的作用有:

  • 聚合协议和串口;
  • 处理来自协议的查询请求;
  • 根据协议的部分参数进行请求;
  • 接收来自串口的数据并分发给各个协议;
  • 对串口/网络子线程进行控制。

关于CommManager的更多具体用法,可以参考API文档。

上位机串口通信若采用信号/槽类型的异步接收数据方式在主线程中接收并处理数据,不需要让通讯类在一个独立的子线程中运行,但半双工模式下需要通过阻塞方式实时监听串口,因此需要通过一个串口线程控制器来操作子线程的运行和停止。

接收、发送数据及字符串拼接的工作在子线程中执行。

图 1 CommManager的部分接口

CommManager的主要目的是隐藏具体的多线程实现,统一了编程接口,使得其它类可以直接调用控制器中相应的方法,而不需要通过连接多线程对象中的信号与槽(即信号槽的方式)调用通讯器的方法。因为Qt的多线程机制,在控制器中采用了反射或信号等方式,通过CommManager隐藏多线程的实现,简化其它部分的代码。

注:Qt的Thread多线程机制与其它编程语言的多线程稍有不同,不同之处在于QThread更确切的来说应该是一个线程控制器而非一个具体的线程。而将QObject子类对象通过moveToThread方法放置到子线程中后,若直接调用该对象的foo方法,则foo方法将会在主线程中执行,为了避免这种情况的发生,需要使用Qt的信号槽机制,利用信号来调用foo槽函数,使槽函数在所在的子线程中执行,即不会阻塞UI线程。

串口通讯需要有相应的协议来实现,通过CommManager对象的addProtocol接口添加协议,CommManager将会自动绑定信号和槽。接收到来自下位机的数据(以行为单位)时,调用接口AbstractProtocol实现类的processData回调函数对接收到的数据进行处理。接收到来自协议的请求时,从协议队列中选取一个协议并取出命令,将命令的内容发送到下位机。

CommManager计算指令的执行时间(从上位机Qt程序中发送到串口至下位机响应的时间),根据AbstractProtocol实现类的 cmdExecuteTime值决定命令的重发次数。管理器在接收到协议发送的信号后,会优先查询高优先级协议,并获取高优先级的AbstractProtocol类中的待查讯指令进行查询。默认情况下,最先注册到CommManager中的协议有最高的优先级,当该协议中的指令全部查询结束后才会查询次优先级协议中的指令。

3.         通讯接口及部分实现类

项目中所有的串口/网络通讯设备都继承自AbstractComm接口并实现AbstractComm中定义的纯虚方法。AbstractComm定义了与CommManager之间的接口。

图 2 AbstractCom 的部分接口

若要调用 AbstractCom 的实现类中的方法,应当采用信号槽机制或这QMetaObject::invokeMethod 方法来调用,这样才可以保证AbstractCom实现类中的槽函数全部运行在子线程中。对于AbstractCom实现类中的标志位和查询指令可以直接通过函数调用来修改(需要加锁保证线程安全)。

ComFullDuplex 通讯器实现类为工作于全双工模式下的串口,通过连接 QSerialPort 实例的 readyRead 信号和自身的onRead槽函数对串口发送的信息进行处理。使用 readyRead 信号进行响应,异步执行数据处理,尽管这个类的方法可以在主线程中执行,但为了统一控制器和串口之间的接口,仍将其放在子线程中执行。在这个实现类中上位机不会控制发送指令的时间(认为该类是工作于全双工模式,上位机和下位机可以同时发送信息,不会导致信道电平异常产生乱码),而是在接收到来自用户的操作后立即向下位机发送指令,但若在RS485串口中错误使用该类,将可能导致在半双工模式下的RS485总线中产生乱码无法正常收到回复。若单片机使用RS485半双工连接上位机时,建议不要选择该类发送串口数据(若上位机不需要发送指令,则不会导致乱码)。而单片机使用RS232全双工连接时可以使用该模式。

4. 代码及文档

文档:https://brifuture.github.io/qt_components/basic_communicator/docs/

代码:https://github.com/BriFuture/qt_components/tree/master/basic_communicator

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

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

    1.   半双工模式实时检测串口 ComHalfDuplex类是为了解决上位机发送控制指令和下位机发送数据会在半双工RS485总线中产生冲突引起乱码而引入的(v0.010版本引入). 解决冲突的原理主 ...

  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. CefSharp使用一

    一.使用NuGet搜索CefSharp然后下载CefSharp.WinForms和CefSharp.Common 二.引用CefSharp.Windows,CefSharp,CefSharp三个dll ...

  2. 图片展示js特效

    html 代码片段,做一个table表格 <table width="798" height="276" border="0" ali ...

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

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

  4. 安卓手机牛逼软件Termux中安装Archlinux,安装Jdk

    说出来你可能不信,手机上居然装了两个linux系统,和真实的linux有些许些差别. 首先安装了Termux以后你发现,好多linux常用功能都有,什么Pyhton,gcc,g++,ruby,Php, ...

  5. poj2409(polya 定理模板)

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

  6. dedecms有缩略图则显示缩略图,没有则显示随机缩略图

    随着html5以及扁平化等新的设计概念的深入人心,缩略图功能则成了一般网页模版制作不可或缺的一个功能,dedecms默认的的缩略图调用标签[field:imglink/] 或者 [field:litp ...

  7. numpy方法介绍

    三.numpy系列 1.np.maximum:(X, Y, out=None) X 与 Y 逐位比较取其大者: 最少接收两个参数 h=[[-2,2,10],[-5,-9,20]] hh=np.maxi ...

  8. Python: 安装 sklearn 包出现错误的解决方法

    今天在安装 Python 的 sklearn 包时出现了 Cannot uninstall 'numpy' 和 Cannot uninstall 'scipy' 错误,下面记录了我尝试了很多网上的方法 ...

  9. for循环删除list中多个元素出现的误区

    错误的做法是: for(int i= 0;i<list.size();i++) 因为在你删除元素的同时list.size()也在变小,这样就会照成越界. 正确做法:因为要删除list里面的多个的 ...

  10. IT网址大全

    图像处理 [素材]   在线作图 [素材]   思缘设计论坛 [素材]   ps联盟 [素材]   ps学习网 [素材]   ps教程论坛 [素材]   ps爱好者 [素材]   46ps [素材] ...