串口用了无数次,没想到到QT这蹩脚了。基本的配置直接看QT的示例代码就行了,接收的时候分同步接收和异步接收。
异步接收:
//.h中声明
QByteArray rxData;
//cpp构造函数中绑定接收事件
connect(serial0, &QSerialPort::readyRead, this, &SerialBoard::readData);
//直接读取全部数据
void SerialBoard::readData()
{
rxData = serial0->readAll();
}
异步有个问题,当数据较多时,readAll不能一次全读完,因为接收数据也需要时间,但是readyRead不能设置触发阈值,接收到数据就触发readData事件了。
QT示例中又block传输方法,在单独线程中
while (serial.waitForReadyRead(10))
responseData += serial.readAll();
嗯,不错,但感觉这只适合传输文件之类的,当进入readData槽后再wait时有新的数据进来就不会再次触发槽函数,而是wait返回true接收数据,没数据后只能等wait 10ms超时后返回false才返回,显然有点拖慢系统的速度。我的协议中只是有些命令数据稍大,看了看别人的例子,可以用阻塞和非阻塞接收数据。阻塞就是加延时,然后再读数。我采用加定时器同步接收
//.h中加一个
QTimer *rxTimer;
//cpp构造函数中增加定时器初始化,单次定时,超时触发槽函数,槽函数自己注册
connect(serial0, &QSerialPort::readyRead, this, &SerialBoard::readData);
rxTimer = new QTimer(this);
QObject::connect( rxTimer, &QTimer::timeout,this,&SerialBoard::CheckData);
rxTimer->setSingleShot(true);
rxTimer->setInterval(0);
void SerialBoard::readData()
{
//数据追加
rxData += serial0->readAll();
//rxTimer->setInterval(0);
//开启10ms定时器,10ms内没再次接收到数据就超时了
rxTimer->start(10);
}
void SerialBoard::CheckData()
{
//超时,表示此次传输完成,开始处理数据包,这里是校验接收的数据是否正确,然后将结果用回调方式传出去
rxTimer->stop();
errordata=0;
if(rxData.size() != TESTSIZE)
{
errordata = TESTSIZE - rxData.size();
}
qDebug() << "serial0 Data size " + QString::number(rxData.length(),10);
for(int i=0;i
{
if(rxData[i] != (char)(i&0xFF))
{
errordata++;
}
}
m_psink->OnReaddataFinished("serial0 rx/total:"+QString::number(errordata,10)+"/" + QString::number(TESTSIZE,10)+"\n");
}
暂时先这么用着,感觉还有点不完美,以后再追加。
=继续补充==================================================================================
在使用中发现 串口缓冲区并没有起到作用
serial0->setReadBufferSize(2000);
设置的2000个字节缓冲,事实没有read完数据,后面的数据会丢掉很多,可能底层驱动没做内存缓冲,硬件FIFO肯定比较小了。
于是槽函数做缓冲,数据处理定时处理。
connect(serial0, &QSerialPort::readyRead, this, &SerialTelephone::readData);
//100ms定时器---------------------------------------------------
m_pTimer = new QTimer(this);
connect(m_pTimer, SIGNAL(timeout()), this, SLOT(Timer1Handle()));
m_pTimer->start(100);
void SerialTelephone::readData()
{
rxData += serial0->readAll();
// QString text = "telephone board rx: ";
// QByteArray str = rxData.toHex().toUpper();
// for(int i = 0; i < str.size(); i+=2)
// text = text + " 0x" + str.at(i) + str.at(i+1);
// qDebug() << text;
timeoutCount++;
}
void SerialTelephone::Timer1Handle()
{
if(timeoutCount > 0)
{
while(0 == decode(rxData));
}
}
decode处理数据时,需要拆包处理,因为100ms可能收到多个数据包,有不完整的数据包时需要剔除数据,配合协议来完善,例如经典的使用0x7E包头,内容0x7D 0x5E替换0x7E,0x7D 0x5D 替换0x7D。