这里首先说明一下,这个为什么叫串口设备调试工具而不是串口调试工具,是因为这个工具比网络上的串口调试工具多出了一些真实需要的用来调试设备的功能,首先一点就是大部分的串口调试工具收到数据都是立即返回,这样的数据都是连着的,头一条数据和后一条数据头尾相连,对于调试着来说要看数据非常麻烦,而且在不断有数据过来时,要停下来看数据除非关闭串口,而不能在打开串口的时候看数据,因为不断有数据过来冲掉前面的数据显示,甚至有些还不能最大化等等情况,这个工具是根据将近四年的与硬件通信这块开发工具的切身实际需求量身定做的,还能模拟设备立即回复数据。之前很多QT开发的版本源码分成两套,一套在windows下编译,一套在linux下编译,甚至麻烦,虽然QT5.1之后的版本自带了串口通信类,本人测试过,貌似还有小问题,在快速收发数据时容易卡住,这次带来的源码不用做任何改动即可在多个平台编译。

项目名称:串口设备调试工具

开发环境:WIN7+QT4.7+QT CREATOR2.8+MINGW

已编译通过测试平台:XP、Win7、ubuntu、tiny210

技术实现:通过第三方串口通信类,解析协议并作出处理

基本功能:

1:支持16进制数据发送与接收。

2:支持windows下COM9以上的串口通信。

3:自动加载对应操作系统串口号。

4:实时显示收发数据字节大小以及串口状态。

高级功能:

1:可自由管理需要发送的数据,每次只要从下拉框中选择数据即可,无需重新输入数据。

2:可模拟设备回复数据,需要在主界面开启模拟设备回复数据。当接收到设置好的指令时,立即回复设置的回复指令。例如指定收到0x16 0x00 0xFF 0x01需要回复0x16 0x00 0xFE 0x01,则只需要在SendData.txt中添加一条数据16 00 FF 01:16 00 FE 01即可。

3:可定时发送数据和保存数据到文本文件:,默认间隔5秒钟,可更改间隔时间。

4:在不断接收到大量数据时,可以暂停显示数据来查看具体数据,后台依然接收数据但不处理,无需关闭串口来查看已接收到的数据。

5:每次收到的数据都是完整的一条数据,而不是脱节的,做了延时处理。

6:一套源码随处编译,无需更改串口通信类,已在XP/WIN7/UBUNTU/ARMLINUX系统下成功编译并运行。

如果有更好的建议或者意见,请Q我(517216493),谢谢!

运行截图:

粗略步骤:

第一步:布局好界面,控件命名好,建议用pascal命名法。

第二步:准备unix和windows串口通信第三方类qextserialport.h、qextserialport.cpp、qextserialport_global.h、qextserialport_p.h、qextserialport_unix.cpp、qextserialport_win.cpp。

导入到工程,在pro文件中这样写:

QT       += core gui

TARGET = mySerialPortTools

TEMPLATE = app

SOURCES += main.cpp\

qextserialport.cpp\

frmmain.cpp

HEADERS += frmmain.h \

qextserialport_global.h \

qextserialport.h \

myhelper.h

win32 { SOURCES += qextserialport_win.cpp }

unix { SOURCES += qextserialport_unix.cpp }

FORMS += frmmain.ui

RESOURCES += \

main.qrc

MOC_DIR=temp/moc

RCC_DIR=temp/rcc

UI_DIR=temp/ui

OBJECTS_DIR=temp/obj

DESTDIR=bin

win32:RC_FILE=main.rc

CONFIG += warn_off      #关闭警告

这样的话在不同平台下会自动加载对应平台的cpp实现文件来编译。

第三步:初始化主界面,自动加载对应串口号波特率等信息。

void frmMain::InitForm()
{
ReceiveCount=0;
SendCount=0;
IsShow=true;
IsAutoClear=false;
IsHexSend=true;
IsHexReceive=true;
IsDebug=false; QStringList comList;//串口号
QStringList baudList;//波特率
QStringList parityList;//校验位
QStringList dataBitsList;//数据位
QStringList stopBitsList;//停止位 #ifdef Q_OS_WIN//如果是windows系统
comList<<"COM1"<<"COM2"<<"COM3"<<"COM4"<<"COM5"<<"COM6"
<<"COM7"<<"COM8"<<"COM9"<<"COM10"<<"COM11"<<"COM12"
<<"COM13"<<"COM14"<<"COM15";
#else//如果是unix或者其他系统
comList<<"ttyUSB0"<<"ttyUSB1"<<"ttyUSB2"<<"ttyUSB3"<<"ttyUSB4"<<"ttyUSB5"
<<"ttyS0"<<"ttyS1"<<"ttyS2"<<"ttyS3"<<"ttyS4"<<"ttyS5"<<"ttyS6"
<<"ttyS7"<<"ttyS8"<<"ttyS9";
#endif ui->cboxPortName->addItems(comList);
ui->cboxPortName->setCurrentIndex(0); baudList<<"50"<<"75"<<"100"<<"134"<<"150"<<"200"<<"300"
<<"600"<<"1200"<<"1800"<<"2400"<<"4800"<<"9600"
<<"14400"<<"19200"<<"38400"<<"56000"<<"57600"
<<"76800"<<"115200"<<"128000"<<"256000"; ui->cboxBaudRate->addItems(baudList);
ui->cboxBaudRate->setCurrentIndex(12); parityList<<"无"<<"奇"<<"偶"; #ifdef Q_OS_WIN//如果是windows系统
parityList<<"标志";
#endif parityList<<"空格"; ui->cboxParity->addItems(parityList);
ui->cboxParity->setCurrentIndex(0); dataBitsList<<"5"<<"6"<<"7"<<"8";
ui->cboxDataBit->addItems(dataBitsList);
ui->cboxDataBit->setCurrentIndex(3); stopBitsList<<"1"; #ifdef Q_OS_WIN//如果是windows系统
stopBitsList<<"1.5";
#endif stopBitsList<<"2"; ui->cboxStopBit->addItems(stopBitsList);
ui->cboxStopBit->setCurrentIndex(0); //读取数据(采用定时器读取数据,不采用事件,方便移植到linux)
myReadTimer=new QTimer(this);
myReadTimer->setInterval(300);
connect(myReadTimer,SIGNAL(timeout()),this,SLOT(ReadMyCom())); //发送数据
mySendTimer=new QTimer(this);
mySendTimer->setInterval(5000);
connect(mySendTimer,SIGNAL(timeout()),this,SLOT(WriteMyCom())); //保存数据
mySaveTimer=new QTimer(this);
mySaveTimer->setInterval(5000);
connect(mySaveTimer,SIGNAL(timeout()),this,SLOT(SaveMyCom())); //显示日期时间
myTimer=new QTimer(this);
myTimer->start(1000);
connect(myTimer,SIGNAL(timeout()),this,SLOT(SetTime())); QDate dateNow=QDate::currentDate();
ui->labDate->setText(QString("日期:%1").arg(dateNow.toString("yyyy年MM月dd日 dddd"))); for (int i=1;i<=60;i++)
{
ui->cboxSend->addItem(QString::number(i)+"秒");
ui->cboxSave->addItem(QString::number(i)+"秒");
} ui->cboxSave->setCurrentIndex(4);
ui->cboxSend->setCurrentIndex(4); ui->cboxSend->setEnabled(false);
ui->cboxSave->setEnabled(false); this->ChangeEnable(false);
this->ReadConfigData();//读取发送数据加载到下拉框
this->ReadSendData();//读取数据转发文件 ui->txtSend->installEventFilter(this);//安装监听器监听发送数据框回车响应
}

第四步:采用定时器读取串口数据,其实也可以采用事件机制,在几大平台也测试通过事件来收数据也可以,但是在windows下在快速收发大量数据时候居然会卡住,同样的代码在linux表现很好,不明原因,后面采用定时器读取机制,问题就没有了。

void frmMain::ReadMyCom()
{
//这个判断尤为重要,否则的话直接延时再接收数据,空闲时和会出现高内存占用
if (myCom->bytesAvailable()<=0){return;} myHelper::Sleep(100);//延时100毫秒保证接收到的是一条完整的数据,而不是脱节的
QByteArray buffer=myCom->readAll(); if (IsShow)
{
if (IsHexReceive)
{
QString tempDataHex=myHelper::ByteArrayToHexStr(buffer);
ui->txtDataHex->append(QString("接收:%1 时间:%2")
.arg(tempDataHex)
.arg(QTime::currentTime().toString("HH:mm:ss"))); if (IsDebug)//2013-8-6增加接收数据后转发数据,模拟设备
{
foreach(QString tempData,SendDataList)
{
QStringList temp=tempData.split(';');
if (tempDataHex==temp[0])
{
//这里没有跳出循环,有可能一条数据会对应多条数据需要转发
myCom->write(myHelper::HexStrToByteArray(temp[1]));
}
}
}
}
else
{
QString tempDataNormal=QString(buffer);
ui->txtDataHex->append(QString("接收:%1 时间:%2")
.arg(tempDataNormal)
.arg(QTime::currentTime().toString("HH:mm:ss"))); if (IsDebug)//2013-8-6增加接收数据后转发数据,模拟设备
{
foreach(QString tempData,SendDataList)
{
QStringList temp=tempData.split(';');
if (tempDataNormal==temp[0])
{
//这里没有跳出循环,有可能一条数据会对应多条数据需要转发
myCom->write(temp[1].toAscii());
}
}
}
} ReceiveCount=ReceiveCount+buffer.size();
ui->labReceive->setText(QString("接收:%1 字节").arg(ReceiveCount));
}
}
void frmMain::WriteMyCom()
{
QString str=ui->txtSend->currentText();
if (str==""){ui->txtSend->setFocus();return;}//发送数据为空
if (!myCom->isOpen()) { return; }//串口没有打开 QByteArray outData=str.toAscii();
int size=outData.size(); if (IsHexSend)//转化为16进制发送
{
outData=myHelper::HexStrToByteArray(str);
size=outData.size();
myCom->write(outData);
}
else
{
size=outData.size();
myCom->write(outData);
} ui->txtDataHex->append(QString("发送:%1 时间:%2")
.arg(str)
.arg(QTime::currentTime().toString("HH:mm:ss"))); SendCount=SendCount+size;
ui->labSend->setText(QString("发送:%1 字节").arg(SendCount)); if (IsAutoClear)
{
ui->txtSend->setCurrentIndex(-1);
ui->txtSend->setFocus();
}
} void frmMain::SaveMyCom()
{
QString tempData=ui->txtDataHex->toPlainText();
if (tempData==""){return;}//如果没有内容则不保存 QDateTime now=QDateTime::currentDateTime();
QString name=now.toString("yyyyMMddHHmmss");
QString fileName=name+".txt"; QFile file(fileName);
file.open(QFile::WriteOnly | QIODevice::Text);
QTextStream out(&file);
out<<tempData;
file.close();
}

这里有个细节说下,就是在接收数据函数里面,增加了一个判断if (myCom->bytesAvailable()<=0){return;}如果不这样的话,每次定时读取都会延时,内存占用很高,当然,如果采用事件机制的话,这里不需要任何延时或者判断。

可执行文件下载地址:http://download.csdn.net/detail/feiyangqingyun/6745003

源码猛点这里:http://download.csdn.net/detail/feiyangqingyun/6745011

QT开发之旅三串口设备调试工具的更多相关文章

  1. QT开发之旅二TCP调试工具

    TCP调试工具顾名思义用来调试TCP通信的,网上这样的工具N多,之前用.NET写过一个,无奈在XP下还要安装个.NET框架才能运行,索性这次用QT重写,发现QT写TCP通信比.NET还要便捷一些,运行 ...

  2. QT开发之旅一DS7400主机调试工具

    接触QT三年有余,期间因为工作需要断断续续学习过,2010年开始接触,当时好像是4.7版本,现在都已经到5.2版本了,更新真快,前阵子安装了下5.2版本,还是有很多变化的,不过感觉好像编译速度慢了很多 ...

  3. QT开发之旅四邮件发送工具

    终于有了一个晚上安静的写写程序,最近一直忙着公司商务上的事情,一直想用QT实现一个调用最底层socket通信来实现的邮件发送程序,以前用C#写过,微软都封装好的,不知道底层是如何实现的,只知道调用方法 ...

  4. QT开发之旅-Udp聊天室编程

    一.概要设计 登录对话框(继承自QDialog类)进行用户登录查询数据库用户是否存在,注册插入数据到用户表.用户表字段: (chatid int primary key, passwd varchar ...

  5. ubuntu QT开发环境(三种方法安装Qt4.8,其中apt-get方法安装QT库最简单)good

    方法一 QT4.8.0库+QT Creator 2.4.1 特别声明:此方法极其耗时间,看电脑性能了.配置configure可减少编译时间 1.下载Qt .进入网址http://qt.nokia.co ...

  6. VS2008下QT开发环境搭建(转)

    原博文地址:http://blog.csdn.net/sunnyboycao/article/details/6364444 VS2008集成QT4.7.2环境搭建 作者:jimmy 日期:2011- ...

  7. Qt开发技术:QCharts(三)QCharts样条曲线图介绍、Demo以及代码详解

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

  8. ESP8266开发之旅 网络篇⑯ 无线更新——OTA固件更新

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

  9. ESP8266开发之旅 基础篇③ ESP8266与Arduino的开发说明

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...

随机推荐

  1. CentOS英文提示修改为中文提示的方法

    1.安装中文支持包:yum -y groupinstall chinese-support 2.修改文件/etc/sysconfig/i18n如下: LANG="zh_CN.UTF-8″ S ...

  2. Mysql:This version of MySQL doesn’t yet support ‘LIMIT & IN/ALL/ANY/SOME 错误解决

    From: http://blog.chinaunix.net/uid-22414998-id-2945656.html This version of MySQL doesn’t yet suppo ...

  3. linux cfs调度器_模型实现

    调度器真实模型的主要成员变量及与抽象模型的对应关系 I.cfs_rq结构体    a) struct sched_entity *curr        指向当前正在执行的可调度实体.调度器的调度单位 ...

  4. Android Studio添加so文件并打包到APK的lib文件夹中

    Gradle官方在新版本中已经实现了自动打包.so文件功能了. 只需要在build.gradle的文件中的android目录下配置一下即可: sourceSets { main { jniLibs.s ...

  5. selenium +chrome headless Adhoc模式渲染网页

    mannual和adhoc模式比较 Manual vs. Adhoc In the script above, we start the ChromeDriver server process whe ...

  6. MTK 强制横屏

    frameworks\base\policy\src\com\android\internal\policy\impl目录下的PhoneWindowManager.java的rotationForOr ...

  7. 基于JavaScript判断浏览器到底是关闭还是刷新(超准确)

    这篇文章主要介绍了基于JavaScript判断浏览器到底是关闭还是刷新(超准确)的相关资料,需要的朋友可以参考下 本文是小编总结的一些核心内容,个人感觉对大家有所帮助,具体内容请看下文: 页面加载时只 ...

  8. Disconf (version : 2.6.21)

    通常我们会做如下配置:(disconf 2.6.21) <!-- 一次扫描 --> <bean id="disconfMgrBean" class="c ...

  9. Java -- 异常的捕获及处理 -- 自定义异常类

    7.4 自定义异常类 定义异常类只需要继承Exception类即可. 例:自定义异常类 Class : MyException package limeThrowable._7_4; public c ...

  10. GoF--装饰者设计模式

    顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例. 装饰器模式的应用场景: 1.需要扩展一个类的功能. 2.动态的为 ...