1 Qextserialport类介绍
在Qt5之前的版本中并没有特定的串口控制类,现在大部分人使用的是第三方写的qextserialport类,本文章主要是讲解怎样利用此类实现串口通信。
注意:Qt5发布之前,Qt实现串口通信一般是采用第三方类库qextserialport。Qt5发布后自带了QtSerialPort 能够支持串口通信。
2 文件下载地址
http://blog.csdn.net/wangzhen209/article/details/52605514
3 文件内容:
http://blog.csdn.net/wangzhen209/article/details/52605514
(实在懒得贴图了,哈哈)
4 串口通信的实现
4.1 声明串口对象 :
Win_QextSerialPort *myCom; //Windows系统内
Posix_QextSerialPort *myCom; //Linux系统内
4.2 串口定义:
//Windows中有两种查询模式,一种polling模式,一种EventDriven模式
myCom = new Win_QextSerialPort("COM1",QextSerialBase::Polling); //设置为查询模式
myCom = new Win_QextSerialPort("COM1",QextSerialBase::EventDriven); //设置为事件模式
//Linux中只有Polling模式
myCom = new Posix_QextSerialPort("/dev/ttyS0",QextSerialBase::Polling);
事件驱动方式EventDriven就是使用事件处理串口的读取,一旦有数据到来,就会发出readyRead()信号,我们可以关联该信号来读取串口的数据。在事件驱动的方式下,串口的读写是异步的,调用读写函数会立即返回,它们不会冻结调用线程。
查询方式Polling则不同,读写函数是同步执行的,信号不能工作在这种模式下,而且有些功能也无法实现。但是这种模式下的开销较小。我们需要自己建立定时器来读取串口的数据。
在Windows下支持以上两种模式,而在Linux下只支持Polling模式。
4.3 串口打开模式
myCom ->open(QIODevice::ReadWrite); //打开模式 表示以可读可写的方式打开串口
QIODevice::Unbuffered 0x0020 描述
QIODevice::NotOpen 0x0000
QIODevice::ReadOnly 0x0001
QIODevice::WriteOnly 0x0002
QIODevice::ReadWrite ReadOnly | WriteOnly
QIODevice::Append 0x0004
QIODevice::Truncate 0x0008
QIODevice::Text 0x0010
4.4 串口的配置函数
myCom->setBaudRate(BAUD9600); //波特率设置,我们设置为9600
myCom->setDataBits(DATA_8); //数据位设置,我们设置为8位数据位
myCom->setParity(PAR_NONE); //奇偶校验设置,我们设置为无校验
myCom->setStopBits(STOP_1); //停止位设置,我们设置为1位停止位
myCom->setFlowControl(FLOW_OFF); //控制流
myCom->setTimeout(long); //设置时间间隔
setTimeout(long)参数决定了Polling查询模式的读取串口的速度。
4.5 串口工作
connect(myCom,SIGNAL(readyRead()),this,SLOT(readMyCom())); //EventDriven模式下才能触发readyRead()信号
connect(readTimer,SIGNAL(timeout()),this,SLOT(readMyCom())); //Polling模式定时器触发timeout()信号
4.6 串口读取数据
QByteArray temp = myCom->readAll(); //返回读取的字节
int byteLen = myCom->bytesAvailable(); //返回串口缓冲区字节数
4.7 串口写数据
myCom -> Write(const char * data, qint64 maxSize ); //
myCom -> Write(const char * data ); //
myCom -> Write(const QByteArray & byteArray); //
int byteLen = myCom->bytesToWrite(); //输出写数据的字节数
//bytesWritten()信号函数来获取已经发送的数据的大小。
5 实际编程
界面如下
可以看到,我在界面上放了两LlinEedit,用来显示收发的数据,几个PushButton,用来发送数据,清空收发送区,两个Check Box,用来选择是否是HEX发送或HEX接收
MainWindow.h
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
static QByteArray QString2Hex(QString str); //转换为16进制函数
static char ConvertHexChar(char ch);
private slots:
void ReadMycom(); //读取串口中的数据
void on_SendButton_clicked();
void on_Close_clicked();
void on_ClearReceive_clicked();
void on_ClearSend_clicked();
private:
Ui::MainWindow *ui;
Win_QextSerialPort *myCom;
QTimer *timer; //用于声明定时器
};
私有地几个槽函数我相信看函数的名字也能猜到他们实现什么功能,因此就不赘述。
MainWindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
timer=new QTimer(this);
myCom = new Win_QextSerialPort("COM5",QextSerialBase::Polling); //设置串口的查询模式
myCom->open(QIODevice::ReadWrite); //以可读可写的方式打开串口
if(!myCom->isOpen())
{
qDebug("no com open\n");
}
//串口参数设置
myCom->setBaudRate(BAUD115200);
myCom->setDataBits(DATA_8);
myCom->setParity(PAR_NONE);
myCom->setStopBits(STOP_1);
myCom->setFlowControl(FLOW_OFF);
//this->ui->SendNumber->setDecMode();
//设置时间间隔
myCom->setTimeout(100);
timer->start(300);
QObject::connect(timer,SIGNAL(timeout()),
this,SLOT(ReadMycom()));
ui->setupUi(this);
}
我们的程序是以查询的方式去读取串口中的数据,首先设置定时器,当定时器时间到时,去执行槽函数ReadMycom()函数,该函数的作用是读取串口中的数据。
/*
函数名:
函数功能:读取串口中的数据
函数类型:槽函数
函数返回值:无
*/
void MainWindow::ReadMycom()
{
int byteLen = myCom->bytesAvailable(); //返回串口缓冲区字节
if(byteLen<=0) return; //减小内存占用
qDebug("byteLen=%d\n",byteLen);
//串口内有数据才往下继续执行
QByteArray temp = myCom->readAll(); //返回读取的字节
this->ui->textEdit->clear();
if(this->ui->HexShow->isChecked()) //如果是16进制显示
{
this->ui->textEdit->setText(temp.toHex());
//temp.toHex();
}
else
{
this->ui->textEdit->setText(temp);
}
this->ui->ReceiveNumber->display(byteLen);
}
注意:增加了一个判断
int byteLen = myCom->bytesAvailable(); //返回串口缓冲区字节
if(byteLen<=0) return; //减小内存占用
如果不这样的话,每次定时读取都会延时,内存占用很高,当然,如果采用事件机制的话,这里不需要任何延时或者判断。
/*
函数名:
函数功能:发送数据
函数类型:槽函数
返回值:无
*/
void MainWindow::on_SendButton_clicked()
{
QString input=this->ui->SDendData->text();
QByteArray hexByte;
if(input.isEmpty())
{
qDebug("no message\n");
}
else
{
if(this->ui->HexSend->isChecked()) //选中16进制发送数据
{
hexByte=QString2Hex(input);
myCom->write(hexByte);
}
else
{
myCom->write(input.toAscii());
}
}
this->ui->SendNumber->display(input.size());
}
void MainWindow::on_Close_clicked()
{
close();
}
/*
在测试时发现,当底层硬件发送数据的间隔时间太短时容易在成串口读写数据错误,因为
本程序是使用定时器的方法去读取串口数据
*/
void MainWindow::on_ClearReceive_clicked()
{
this->ui->textEdit->clear();
}
void MainWindow::on_ClearSend_clicked()
{
this->ui->SDendData->clear();
}
/*
函数名:
函数功能:将QString类型转换为hex形式
函数类型:
函数参数:
返回值:
*/
QByteArray MainWindow::QString2Hex(QString str)
{
QByteArray senddata;
qDebug("QString2Hex\n");
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].toAscii();
if(hstr == ' ')
{
i++;
continue;
}
i++;
if(i >= len)
break;
lstr = str[i].toAscii();
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);
return senddata;
}
/*
函数功能:将单个字符串转换为hex
*/
char MainWindow::ConvertHexChar(char ch)
{
qDebug("ConvertHexChar\n");
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 (-1);
}
与其他程序相比,本程序实现了HEX发送,当在界面选择HEX发送时,程序就会执行到
通过调用QString2Hex()函数转为16进制,采用16进制发送的原因是很多单片机只吃16进制数据。
源代码下载地址:
http://download.csdn.net/detail/qq_27312943/9661418
参考资料:
1 http://blog.csdn.net/wangzhen209/article/details/52605514 本文主要是参考这一篇文章,但是原文章中没有给出全部的代码以及实现16进制的发送方式,本文进行了增添。
2 http://blog.csdn.net/huwei2003/article/details/36418471 介绍了有关串口通信的基本知识,对于串口通信不明白的可以参考这篇文章
3 http://www.cnblogs.com/feiyangqingyun/p/3483764.html
注意事项:
1 在程序中没有采用QT5的QtSerialPort 类主要是我们在一次实际开发当中,调用这个类的一个readall()函数时,明明串口中有数据,但是无法读出来,最后采用了第三方库qextserialport得到了解决。