自定义Qt组件-通讯模块(P1)
通讯模块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)的更多相关文章
- 自定义Qt组件-通讯模块(P3)
1. 半双工模式实时检测串口 ComHalfDuplex类是为了解决上位机发送控制指令和下位机发送数据会在半双工RS485总线中产生冲突引起乱码而引入的(v0.010版本引入). 解决冲突的原理主 ...
- 自定义Qt组件-通讯模块(P2)
1. 抽象协议AbstractProtocol 抽象协议AbstractProtocol定义CommManager与协议之间的接口.AbstractProtocol中的一些属性(如enabled)用 ...
- C/C++ Qt TableDelegate 自定义代理组件
TableDelegate 自定义代理组件的主要作用是对原有表格进行调整,例如默认情况下Table中的缺省代理就是一个编辑框,我们只能够在编辑框内输入数据,而有时我们想选择数据而不是输入,此时就需要重 ...
- SSIS自定义数据流组件开发(血路)
由于特殊的原因(怎么特殊不解释),需要开发自定义数据流组件处理. 查了很多资料,用了不同的版本,发现各种各样的问题没有找到最终的解决方案. 遇到的问题如下: 用VS2015编译出来的插件,在SSDTB ...
- Android Studio开发基础之自定义View组件
一般情况下,不直接使用View和ViewGroup类,而是使用使用其子类.例如要显示一张图片可以用View类的子类ImageView,开发自定义View组件可分为两个主要步骤: 一.创建一个继承自an ...
- [UE4]自定义MovementComponent组件
自定义Movement组件 目的:实现自定义轨迹如抛物线,线性,定点等运动方式,作为组件控制绑定对象的运动. 基类:UMovementComponent 过程: 1.创建UCustomMovement ...
- Qt组件中的双缓冲无闪烁绘图
双缓冲绘图在Qt4中,所有的窗口部件默认都使用双缓冲进行绘图.使用双缓冲,可以减轻绘制的闪烁感.在有些情况下,用户要关闭双缓冲,自己管理绘图.下面的语句设置了窗口部件的Qt::WA_PaintOn ...
- 【转】Android学习基础自定义Checkbox组件
原文网址:http://forum.maiziedu.com/thread-515-1-1.html heckbox组件是一种可同时选中多项的基础控件,即复选框,在android学习中,Checkbo ...
- 自定义Qt按钮
转自:http://blog.csdn.net/starcloud_zxt/article/details/5185556 Qt自带的PushButton样式比较单一,在开发的时候往往按钮的形状各异, ...
随机推荐
- ASP.NET网页动态添加数据行
一看到这标题<ASP.NET网页动态添加数据行>,想起来似乎有点难实现.因为网页的周期性原因,往往在PostBack之后,状态难于有所保留.但Insus.NET又想实现这样的效果,用户点击 ...
- c语言参考书籍
很惭愧没能把c++学的很好,毕竟离开始工作只有2年时间,对自己要求不要过高,慢慢来吧.话说知道自己的不足,以后要更加抓紧了!fighting~ 现在计划着把c语言给学习一下了,当然这次指的是深入地学习 ...
- maven+selenium+java+testng+jenkins自动化测试
最近在公司搭建了一套基于maven+selenium+java+testng+jenkins的自动化测试框架,免得以后重写记录下 工程目录 pom.xml <project xmlns=&quo ...
- Xcode的编辑利器Xvim,如何去掉烦人工具栏和文件路径
最近网上看到了一篇关于Xcode的编辑利器,因为以前做FPGA工作时候在ISE SDK下用过vim作为编辑器,所以深知vim的强大,所以安装Xvim: 在安装之后遇到一些配置问题,因为本来就完美控制, ...
- javascript的offset、client、scroll、screen使用方法
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAfQAAAHuCAYAAABpm/53AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjw
- Android自动化----adb shell,appium,uiautomator2
1.区别 1,adb shell脚本的方式 不但可以在有电脑的情况下使用,通过数据线连接电脑然后adb shell命令,而且还可以打包成app,在手机的终端使用adb shell命令. 2,appiu ...
- [Groovy] Private fields and methods are not private in groovy
如题,, 具体介绍请参看: http://refaktor.blogspot.com/2012/07/private-fields-and-methods-are-not.html
- C#校验手机端或客户端
以下代码用来检查,客户端是手机端还是PC端 string strUserAgent = Request.UserAgent.ToString().ToLower(); bool isMobile = ...
- 处女座和小姐姐(三)(数位dp)
链接:https://ac.nowcoder.com/acm/contest/329/G 来源:牛客网 题目描述 经过了选号和漫长的等待,处女座终于拿到了给小姐姐定制的手环,小姐姐看到以后直呼666! ...
- P2575 高手过招
传送门 直接搞好像搞不了 考虑转换模型 显然每一行棋子不会跑到其他行.. 所以可以把每一行的情况看成一个子博弈 显然整个答案就是每一行的SG值的异或和 不懂的回去学SG函数... 考虑怎么分析一行的状 ...