最近需要写一个串口工具,一开始完全找不到方向只好到处瞎碰,写这个就是希望后来者不要那么心累的到处瞎找....
首先得把这个第三方库下载下来,链接:http://code.google.com/p/qextserialport/downloads/detail?name=qextserialport-1.2rc.zip
下载好了之后,解压,在红色框里的文件夹里把对应的.cpp和.h文件拷到你创建的文件夹下(什么系统就拷什么后缀的)。
在.pro里添加:
include(qextserialport.pri)
然后可以看到如下框架:
首先我是先做的界面,如图:(直接拉的框框,不是敲代码实现的,见谅见谅)
那5个Btn直接右键转到槽选择第一个信号clicked()之后会跳到tool.cpp,大的框是textBrowser小的是lineEdit。
头文件tool.h:
#ifndef TOOL_H
#define TOOL_H
#include
#include
#include
#include
#include "qextserialport.h"
#include "qextserialenumerator.h"
namespace Ui {
class tool;
}
class tool : public QMainWindow
{
Q_OBJECT
public:
explicit tool(QWidget *parent = 0);
~tool();
private:
Ui::tool *ui;
QextSerialPort *myCom;
private:
void initPortList();
private slots:
void readMyCom();
void on_openMyComBtn_clicked();
void on_closeMyComBtn_clicked();
void on_cleanReceBtn_clicked();
void on_sendDataBtn_clicked();
void on_cleanSendBtn_clicked();
void on_textBrowser_textChanged();
};
#endif // TOOL_H
tool.cpp文件:
#include "tool.h"
#include "ui_tool.h"
#include
#include
tool::tool(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::tool)
{
ui->setupUi(this);
//设置各按钮初始状态
ui->closeMyComBtn->setEnabled(false);
ui->cleanReceBtn->setEnabled(false);
ui->cleanSendBtn->setEnabled(false);
ui->sendDataBtn->setEnabled(false);
initPortList();
//按钮设置关联槽函数
connect(ui->openMyComBtn, SIGNAL(clicked()), SLOT(on_openMyComBtn_clicked()));
connect(ui->closeMyComBtn, SIGNAL(clicked()), SLOT(on_closeMyComBtn_clicked()));
connect(ui->sendDataBtn, SIGNAL(clicked()), SLOT(on_sendDataBtn_clicked()));
connect(ui->cleanReceBtn, SIGNAL(clicked()),SLOT(on_cleanReceBtn_clicked()));
connect(ui->cleanSendBtn, SIGNAL(clicked()),SLOT(on_cleanSendBtn_clicked()));
connect(myCom, SIGNAL(readyRead()), SLOT(readMyCom()));
//窗口标题
setWindowTitle(tr("串口工具"));
}
tool::~tool()
{
delete ui;
}
//读取系统可用的串口,并显示在combox中
void tool::initPortList()
{
QList ports = QextSerialEnumerator::getPorts();
foreach( QextPortInfo port, ports )
{
ui->portNameComboBox->addItem(port.portName);
}
ui->portNameComboBox->setEditable(true);
PortSettings settings = {BAUD9600, DATA_8, PAR_NONE, STOP_1, FLOW_OFF, 10};
myCom = new QextSerialPort(ui->portNameComboBox->currentText(), settings, QextSerialPort::EventDriven);
}
//串口read事件槽函数
void tool::readMyCom()
{
QByteArray temp = myCom->readAll();
ui->textBrowser->insertPlainText(temp.toHex());
}
//open按钮点击事件槽函数
void tool::on_openMyComBtn_clicked()
{
myCom->open(QIODevice::ReadWrite);
//设置波特率
if (ui->baudRateComboBox->currentText() == tr("9600")){
myCom->setBaudRate(BAUD9600);
}else if (ui->baudRateComboBox->currentText() == tr("115200")){
myCom->setBaudRate(BAUD115200);
}
//设置数据位
if (ui->dataBitsComboBox->currentText() == tr("8")){
myCom->setDataBits(DATA_8);
}else if (ui->dataBitsComboBox->currentText() == tr("7")){
myCom->setDataBits(DATA_7);
}
//设置奇偶校验
if (ui->parityComboBox->currentText() == tr("无")){
myCom->setParity(PAR_NONE);
}else if (ui->parityComboBox->currentText() == tr("奇")){
myCom->setParity(PAR_ODD);
}else if (ui->parityComboBox->currentText() == tr("偶")){
myCom->setParity(PAR_EVEN);
}
//设置停止位
if (ui->stopBitsComboBox->currentText() == tr("1")){
myCom->setStopBits(STOP_1);
}else if (ui->stopBitsComboBox->currentText() == tr("2")){
myCom->setStopBits(STOP_2);
}
//设置数据流控制,我们使用无数据流控制的默认设置
myCom->setFlowControl(FLOW_OFF);
//设置延时
myCom->setTimeout(10);
//设置各按钮是否可用
ui->openMyComBtn->setEnabled(false);
ui->closeMyComBtn->setEnabled(true);
ui->cleanReceBtn->setEnabled(true);
ui->cleanSendBtn->setEnabled(true);
ui->sendDataBtn->setEnabled(true);
//设置各组合框是否可用
ui->baudRateComboBox->setEnabled(false);
ui->dataBitsComboBox->setEnabled(false);
ui->parityComboBox->setEnabled(false);
ui->portNameComboBox->setEnabled(false);
ui->stopBitsComboBox->setEnabled(false);
}
//close按钮点击事件槽函数
void tool::on_closeMyComBtn_clicked()
{
myCom->close();
ui->openMyComBtn->setEnabled(true);
ui->closeMyComBtn->setEnabled(false);
ui->sendDataBtn->setEnabled(false);
ui->cleanReceBtn->setEnabled(true);
ui->cleanSendBtn->setEnabled(true);
ui->baudRateComboBox->setEnabled(true);
ui->dataBitsComboBox->setEnabled(true);
ui->parityComboBox->setEnabled(true);
ui->portNameComboBox->setEnabled(true);
ui->stopBitsComboBox->setEnabled(true);
}
//清除接收框按钮点击事件槽函数
void tool::on_cleanReceBtn_clicked()
{
ui->textBrowser->setText("");
}
//把读取到的string型的转为16进制
void tool::StringToHex(QString str, QByteArray & senddata)
{
int hexdata,lowhexdata;
int hexdatalen = 0;
int len = str.length();
senddata.resize(len/2);
char lstr,hstr;
for (int i = 0;i < len;)
{
hstr = str[i].toLatin1();
if (hstr == ' ')
{
i++;
continue;
}
i++;
if (i >= len)
{
break;
}
lstr = str[i].toLatin1();
hexdata = ConvertHexChar(hstr);
lowhexdata = ConvertHexChar(lstr);
if ((hexdata == 16) || (lowhexdata == 16))
{
break;
}else
{
hexdata = hexdata*16 + lowhexdata;
}
i++;
senddata[hexdatalen] = (char)hexdata;
hexdatalen++;
}
senddata.resize(hexdatalen);
}
char tool::ConvertHexChar(char ch)
{
if ((ch >= '0') && (ch <= '9'))
{
return ch-0x30;
}else if ((ch >= 'A') && (ch <= 'F'))
{
return ch-'A'+10;
}else if ((ch >= 'a') && (ch <= 'f'))
{
return ch-'a'+10;
}else
{
return ch-ch;
}
}
//send按钮点击事件槽函数
void tool::on_sendDataBtn_clicked()
{
QString str = ui->lineEdit->text();
if (!str.isEmpty())
{
//isHexSend = ui->isHexSend->isChecked();
int len = str.length();
//如果发送的数据个数为奇数的,则在前面最后落单的字符前添加0
if (len%2 == 1)
{
str = str.insert(len-1, '0');
}
QByteArray senddata;
StringToHex(str, senddata);
myCom->write(senddata);
}
}
//清除发送框按钮点击事件槽函数
void tool::on_cleanSendBtn_clicked()
{
ui->lineEdit->setText("");
}
//接收框显示最新数据
void tool::on_textBrowser_textChanged()
{
ui->textBrowser->moveCursor(QTextCursor::End);
}
这样几乎就可以收发串口的数据了,但是肯定是不完善的.....
注意事项:
1、中文乱码问题:
在mian.cpp里添加以下代码,大部分是能够解决的:
//使程序可以处理中文
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
QTextCodec::setCodecForTr(codec);
QTextCodec::setCodecForLocale(QTextCodec::codecForLocale());
QTextCodec::setCodecForCStrings(QTextCodec::codecForLocale());
2、接收框当接收数据超过当前框大小,后面数据会看不见,就需要tool.cpp最后一个槽函数来解决,这个可以见另一篇博客。http://blog.csdn.net/lingy_/article/details/74942037
3、接收转16进制显示的改写了,Qt自己封装了的,之前还傻乎乎的自己写...
4、发送按钮槽函数重新写了,改为发送16进制的数据(一般都是发16进制的命令吧=_=)
5、新增保存功能,在UI拉个pushbutton转到槽选择clicked()
要加头文件:
#include
#include
#include
槽函数:
void tool::on_saveDataBtn_clicked()
{
QString type = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation);
QDir *temp = new QDir;
bool exist = temp->exists(type + "/data");
if(!exist)
temp->mkdir(type + "/data");
QDateTime datetime;
QString timestr = datetime.currentDateTime().toString("yyyyMMddHHmmss");
QString fileName = type + "/data/" + timestr + ".txt";
QFile file(fileName);
file.open(QIODevice::WriteOnly | QIODevice::Truncate);
QString str = ui->textBrowser->toPlainText();
QTextStream out(&file);
out << str;
file.close();
}
然后重写接收:
void tool::readMyCom()
{
QByteArray temp = myCom->readAll();
//根据CheckBox是否选取来判断是否16进制显示
if (ui->checkBox->isChecked())
{
ui->textBrowser->insertPlainText(temp.toHex());
}else
{
ui->textBrowser->insertPlainText(temp);
}
}
7、现在功能是比较齐全 的了,这篇博客就不在更新了。