一、如果使用QT读取串口数据
使用定时器定时发送信号,然后调用槽函数来读取串口数据,串口数据读取过程加锁。
timer1 = startTimer(15);
connect(this, SIGNAL(callCapData()), this, SLOT(CapData()));
void ecgfrom::timerEvent(QTimerEvent *event)
{
if(event->timerId() == timer5) {
if(...)
{
...;
}
}
}
当有多个窗体时,使用线程。
ecgfrom::ecgfrom(QWidget *parent) :
QDialog(parent),
ui(new Ui::ecgfrom)
{
ui->setupUi(this);
//推荐写法:去掉this.(加上this,耗时任务仍在主线程中完成)
m_myThread = new QThread();
// 将工作类(这里是窗体显示)移入线程,
// 什么时候开始执行,执行完成后需要干什么,都是通过信号槽来完成。
this->moveToThread(m_myThread);
m_myThread->start();
/* 其他处理 */
...;
}
二、串口通信的过程
概念:
1、一个数据包(帧)长度
以上图为例,数据帧(包)长度为33(Byte)
2、按每次32个数据包,处理接收缓冲区数据。(读取一次串口接收缓冲区数据能读到32个数据)
qint32 tempval[256] = {0}; // 每个数据 4 字节,共4*256 = 1024 字节
3、时间频率为15ms(定时器定时每15ms去读取一次串口接收缓冲区数据)
timer1 = startTimer(15);
采集卡(外设)与电脑通过串口通信流程:
启发自这个视频链接: https://www.bilibili.com/video/BV1Pd4y1k7sE/?spm_id_from=333.999.0.0&vd_source=b91967c499b23106586d7aa35af46413
当电脑端的应用程序点击打开串口时,发送缓冲区的数据会以指定的波特率发送至电脑短的FIFO中,电脑端在点击读取串口数据时,会从FIFO中读取指定大小的数据,同时被读出的数据 会从FIFO中出队列,等待下次发送过来的数据。
从下面的
qint32 tempval[256] = {0}; // 每个数据 4 字节,共4*256 = 1024 字节
可知,电脑端接收缓冲区中的数据至少为1024个字节,应该会更大(由于下位机(采集卡)每次只发送 256 个数据,所以及时我将读取的时间调整为更大,tempval数据的大小调整为512个字节,可以读取512个字节,但是只是 0 — 255有数值,剩下的256 — 512个都为 0)。
重视这个问题,可以解决问题 —— 滤除杂波(这里是起始数据乱了)。
方法是,再开个定时器,先将杂波数据读出来之后,再将该定时器关闭和把原来采样定时器开启。
timer5 = startTimer(15);
/* 作用:消除杂波 */
if(event->timerId() == timer5) { // 15ms
if (CapType==0)
{
if(viewing)
{
times+=1;
if(times<=90)
{
qDebug()<<times<<"start read";
emit callCapDataDel();
qDebug()<<"end read";
if (times==90)
{
timer2 = startTimer(15); // 启动原先负责采样的定时器
killTimer(timer5);
qDebug()<<"killTimer5";
}
}
}
}
}
void ecgfrom::CapDataDel()
{
mutex.lock();
if(CapType==0)
{
m_Libcom.ReadCoom(tempval); // 将杂波滤除
}
mutex.unlock();
}