整体介绍:这是一个用QT编写的,运行在树莓派上的小程序,当然运行在PC上也是可以的
一、树莓派准备工作
1、树莓派的蓝牙和GPIO口的UART不可兼得
树莓派3上用户目前无法正常是使用GPIO中的UART串口(GPIO14&GPIO15),,原因是树莓派CPU内部有两个串口,一个是硬件串口(官方称为PL011 UART),一个是迷你串口(官方成为mini-uart)。在树莓派2B/B+这些老版树莓派上,官方设计时都是将“硬件串口”分配给GPIO中的UART(GPIO14&GPIO15),因此可以独立调整串口的速率和模式。而树莓派3的设计上,官方在设计时将硬件串口分配给了新增的蓝牙模块上,而将一个没有时钟源,必须由内核提供时钟参考源的“迷你串口”分配给了GPIO的串口,这样以来由于内核的频率本身是变化的,就会导致“迷你串口”的速率不稳定,这样就出现了无法正常使用的情况。目前解决方法就是,关闭蓝牙对硬件串口的使用,将硬件串口重新恢复给GPIO的串口使用,也就意味着树莓派3的板载蓝牙和串口,现在成了鱼和熊掌,两者无法兼得。
解决办法:
查看下当前系统的串口信息
编辑/boot目录下的config.txt文件
sudo vim/boot/config.txt
末行添加
dtoverlay=pi3-miniuart-bt
注意:"pi3-miniuart-bt"是在文件夹/boot/overlays中可以找到的。如果没有,你可以下载一个"pi3-miniuart-bt-overlay"文件并将其拷贝至/boot/overlays文件夹中,并且将下面的语句更改为:dtoverlay=pi3-miniuart-bt-overlay即可。
再编辑cmdline.txt文件
sudo gdit /boot/cmdline.txt
修改以下内容:
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait
保存重启即可。
查看下重启后的串口信息
出现两个串口,表示操作成功
我们不再使用蓝牙,所以为了节省能耗,关掉蓝牙
sudo systemctl diable hciuart
sudo vim /lib/systemd/system/hciuart.service
将ttyAMA0改成ttyS0,如下图:
安装串口工具minicom
sudo apt-get install minicom
运行工具
sudo minicom -s
选择第三项
配置参数
先内部环回测试,短接GPIO14和GPIO15,在mincom时打开回显(Ctrl+A,再全部松开按Z,跳出配置界面按E)
输入一个在字符,先回显字符,然后自己又接收到字符,如下图测试成功
对接电脑的USB转TTL,树莓派RX对TTL的TX,树莓派TX对TTL的RX,测试成功,如下图:
电路原理图
至此,树莓派串口就配置好了
2、树莓派安装QT并配置模块
sudo apt-get update
sudo apt-upgrade(耗时,占空间)非必要步骤
sudo rpi-update
安装qt5-default
sudo apt-get install qt5-default
安装qtcreator
sudo apt-get install qtcreator
3、安装QtSerialPort模块
sudo apt-get install libqt5serialport5-dev libudev-dev
模块有没有安装成功在pro工程文件中添加QT += serialport如果没有报错就说明模块安装成功,可以进行一下一步开发了
二、代码编写
1、新建QT工程,并在工程文件中导入模块
QT += serialport
2、导入包并创建串口对象
#include <QSerialPort>
QSerialPort *serialport;
serialport = new QSerialPort;
3、串口初始化代码
serialport->close();
serialport->setPortName("ttyAMA0");
serialport->setBaudRate(9600);
serialport->setDataBits(QSerialPort::Data8);
serialport->setParity(QSerialPort::NoParity);
serialport->setStopBits(QSerialPort::OneStop);
serialport->setFlowControl(QSerialPort::NoFlowControl);
if(serialport->open(QIODevice::ReadWrite))
qDebug()<<"Uart Init successful!";
else
qDebug()<<"Uart Init failed!";
connect(serialport,SIGNAL(readyRead()),
this,SLOT(uart_recv()));
4、串口发送代码
QString msg=ui->textEdit_write->toPlainText();
QByteArray array = msg.toUtf8();
serialport->write(array);
5、串口接收代码
QByteArray buf = serialPort->readAll();
由于串口每次是发送8个字节,由于分时操作系统的特性,如果一次发送的数据很大,上面那样操作会照成数据会分次接收,为了解决上面的问题,我们采用如下方案:
QByteArray buf = serialPort->readAll();
if(!buf.isEmpty())
{
M2=buf;
M1+=M2;
}
if(M1.contains("@",Qt::CaseSensitive) && M1.contains("#",Qt::CaseSensitive))
{
int s,q;
s=M1.indexOf("@");q=M1.indexOf("#");
QString M3=M1.mid(s+1,q-1);
QString M4=M1.mid(s,q+1);
M1="";M2="";
QStringList List=M3.split(";");
if(List.length()==11 && List[0]==QString::fromLocal8Bit("data"))
{
QByteArray tcp_data = M4.toUtf8();
tcpsocket->write(tcp_data);
QString D1,D2,D3,D4,D5,D61,D62,D63,D64;
D1=List[2];D2=List[3];D3=List[4];D4=List[5];D5=List[6];D61=List[7];D62=List[8];D63=List[9];D64=List[10];
ui->lineEdit_show_Heart_rate_2->setText(D1+" BPM");ui->lineEdit_show_Boold_oxygen_2->setText(D2+" %");ui->lineEdit_show_Alcoholic_2->setText(D3+" mg/mL");ui->lineEdit_show_Temperture_2->setText(D4+" ℃");
ui->lineEdit_show_Boold_press_2->setText(D5+" mmHg");ui->lineEdit_show_Boold_fat_1->setText(D61+" mmol/L");ui->lineEdit_show_Boold_fat_2->setText(D62+" mmol/L");
ui->lineEdit_show_Boold_fat_3->setText(D63+" mmol/L");ui->lineEdit_show_Boold_fat_4->setText(D64+" mmol/L");
//draw plot
CurrentData1=D1.toFloat(),CurrentData2=D2.toFloat(),CurrentData3=D3.toFloat();CurrentData4=D4.toFloat();
CurrentData5=D5.toFloat(),CurrentData61=D61.toFloat();CurrentData62=D62.toFloat();CurrentData63=D63.toFloat();CurrentData64=D64.toFloat();
ShowLine1(ui->Heart_rate);ShowLine2(ui->Boold_oxygen);ShowLine3(ui->Alcoholic_strength);
ShowLine4(ui->Temperture);ShowLine5(ui->Boold_pressure);ShowLine6(ui->Boold_fat);
}
}
这里M1和M2是两个全局变量
原理如下:
因为只要检测到有数据发送过来,就会有信号产生,然后就会执行槽函数。所以我把接收到的数据先暂时追加在一个缓冲区里,就是M1,然后当我检测到M1中以及有我自定义的报文:@data;xxx;xxx;xxx#,我就将我的报文从缓存区M1中截取出来,然后将缓存区清空,这样操作的话,无论数据有多长,都可以接收到完整的数据了。