最近忙着学习linux的嵌入式开发,QT的开发暂时告一段落,所以完美解决的程序也没有编写,现在抽出时间对前面的QT串口动态实时显示大量数据波形程序又加工了下,希望能帮助从事单片机而又不熟悉QT的小伙伴。
先总结下QT的最终感受:
(1)能用别人编写好的模板就用模板,能省下来不少时间;
(2)能用全局变量就用变量,方便。最重要的是能看这篇文章的大部分都是搞单片机的,不是搞嵌入式显示的,所以思维逻辑一时半会也改不过来,按照以前的思维方式比较舒服;
(3)想快速出东西,不用知道具体代码什么意思,知道怎么用就行。QT和while(1)的程序不一样,都是一块一块的,知道一个功能,改吧改吧就行,能输出自己想要的就行。
串口接收程序
此部分分为两部分,(1)数据接收,(2)数据处理。
先说数据接收:20ms接收一次,不管接收多少东西,只要在20ms的特定波特率能接收的最大数据之内就好,也就是能接收到全部数据。直接上程序:
void MainWindow::receive_20ms()
{
int nRxAllLength;
QByteArray recvData;
recvData.resize(256);
uint8_t gnReceiveData[256];
nRxAllLength = m_serial->bytesAvailable();
recvData = m_serial->readAll();
for(int i=0; i=UART_RX_BUF_SIZE) nUartRxBufHead=0;
if(nUartRxBufHead==nUartRxBufTail)
{
nUartRxBufTail++;
if(nUartRxBufTail>=UART_RX_BUF_SIZE) nUartRxBufTail=0;
}
}
}
代码功能:接收数据,并且放到一个fifo里面,接收多少,把fifo开大点,接收一个别覆盖原来的数据就行,反正电脑上运行,随便开。如果需要精简内存,那没办法,需要自己算算开多大合适。
再说处理程序:1ms处理一次。为啥1ms,2ms也是可以的,只要比20ms小就行,最好越快处理越好,但是不能处理不过来。
存在问题:1ms在嵌入式里面不是不能正确定时么?差不多就行,1ms左右就行,只要能在短时间内执行就行。不用特别精确的时间,这个自己估量就行。反正线程处理的时间都是大概的时间,不用太在意这个。除非你要非常精确的时间输出或者输入,那没办法。还是直接上程序:
void MainWindow::dealdata_1ms()
{
nUartRxLengthTemp = nUartRxBufHead - nUartRxBufTail;
if( nUartRxLengthTemp < 0 )
{
nUartRxLengthTemp = nUartRxLengthTemp+ UART_RX_BUF_SIZE;
}
switch( nUartRxCtrlMode )
{
case MODE_UARTRXCMD_WAIT:
if(nUartRxLengthTemp >= 2)//报头为两个byte,先检测报头
{
nUartRxHeadCheck = UartRdCharRxBuff();
if(nUartRxHeadCheck == 0x5A) //保证解析的前两个字节时5AA5
{
nUartRxHeadCheck = UartRdCharRxBuff();
if(nUartRxHeadCheck == 0xA5)
{
nUartRxCtrlMode = MODE_UARTRXCMD_FRAME;
}
}
}
break;
case MODE_UARTRXCMD_FRAME:
if(nUartRxLengthTemp >= 14)//数据帧14个字节,根据自己需要变化
{
for (int i=0;i<14;i++)
{
gnUartRxDataBuffer[i] = UartRdCharRxBuff();
}
数据处理程序代码;
gnLatchCnt++;
if(gnLatchCnt == 8)//8个点存储一次,根据需要多少个点显示存储多少次
{
gnUartRxRecDoneFlag = 1;
}
nUartRxCtrlMode = MODE_UARTRXCMD_WAIT;
}
break;
default:
nUartRxCtrlMode = MODE_UARTRXCMD_WAIT;
break;
}
}
代码功能:(1)从接收的数据里面寻找报头5AA5,这个根据自己的数据定,只要能找到就行,找不到就抛掉,知道找到开始的5AA5。(2)找到后处理剩余14数据,14是我自己的剩余数据,也就是说每帧数据一共16个字节,前两个是报头,后面的数据是自己需要显示的数据。
注意:这里需要说一个习惯,每次处理数据最好用buffer缓存下,第一个功能防止被覆盖,第二个是可以随时加入其它程序,变换一步最好放入一个新的数组里。
缓存8帧数据(8个点)之后,出来一个flag,用来显示数据标志。这个看你自己想要多少个点显示一次,因为是用串口助手发的数据,所以8个点差不多了,如果用单片机的数据,这个随便改。
波形处理程序
波形处理程序就比较简单了,直接上代码:
void ampshow::dealdata_5ms()
{
if(gnUartRxRecDoneFlag == 1)
{
ui->PLOTVAMP->graph(0)->setData(gvUTCms,gvVsuAmp);
ui->PLOTVAMP->graph(1)->setData(gvUTCms,gvVsvAmp);
ui->PLOTVAMP->graph(2)->setData(gvUTCms,gvVswAmp);
ui->PLOTIAMP->graph(0)->setData(gvUTCms,gvIsuAmp);
ui->PLOTIAMP->graph(1)->setData(gvUTCms,gvIsvAmp);
ui->PLOTIAMP->graph(2)->setData(gvUTCms,gvIswAmp);
ui->PLOTVAMP->replot();
ui->PLOTIAMP->replot();
gnUartRxRecDoneFlag = 0;
}
}
接收里面1ms处理一次,这个5ms更新一次,当flag变化后,这边开始描点,就可以正确显示了。
先上报文:随便发,5AA5是报头,0001到0008变化是时间,一共8次。后面是显示数据。根据自己的需要自己变化。
5AA50001000100020003000400050006
5AA50002000100020003000400050006
5AA50003000100020003000400050006
5AA50004000100020003000400050006
5AA50005000100020003000400050006
5AA50006000100020003000400050006
5AA50007000100020003000400050006
5AA50008000100020003000400050006
效果图:
用串口助手测试接收数据,试过每次发100个数据,每10ms发一次,串口都可以正确接收。并且可以正确显示。
需要代码的小伙伴可以加公众号,完整代码将放在百度网盘中,可自行下载,如有问题可在公众号中私信,届时会一一解答。