任务概述
在本次“新冠疫情”的冲击下,某智能物联网工程师所在的小区需要监控人员体温,现新进了一批可以采集人体体温的智能体温计,但是小区有三个门:正门,侧门,后门,每个门都会有人员流动,物业希望能够在监控室查看相关人员的体温,可以做匹配记录。刚好该智能物联网工程师拥有该能力,需要完成以下有关需求:
(1) 每个智能体温计都能采集体温数据并自动上传该数据到监控平台
(2) 监控平台可以实时查看各门,各人员的体温
(3) 对于出现异常体温(超过 37.3℃)监控平台会发出报警
涉及知识点
1、C 语言与C++基础,QT基础界面开发
2、TCP 协议的客户端与服务器连接
3、QCharts 框架使用
4、多媒体播放
具体实现过程
注意点:采用QT5.9,编译器选择MinGW
第一步:体温采集(模拟)与数据发送
细节步骤:
1、制作温度传感器,产生源数据
2、制作 TCP 客户端程序 (控制台应用)
3、开启服务器
4、链接服务器并传输数据
5、验证传输是否能完成,数据是否正确
以下为实现代码:
/*模拟温度发生器*/
/*通过随机数的方式产生温度*/
#include<time.h>
#include<unistd.h>
#include<stdlib.h>
#include<iostream>
#include<bitset>
#include<QTcpSocket>
#include<QHostAddress>
#include<QDebug>
#include<QThread>
using namespace std;
short gTemp;
//产生16位数据,占两个字节,而short也占两字节 ,高8位整数 低8位小数
void makeTemp()
{
//配置随机种子,为了保证产生的数是相对随机的,避免随机数是固定的
srand(clock());
short temp = 0;
char high = 0;
char low = 0;
//模拟人的体温34-43
while(1)
{
usleep(100*1000); //100ms产生一个数据
high = 34 + rand() % 9; //34加上一个0-9的随机数
low = rand() % 100;
// cout << (int)high << endl;
// cout << (int)low << endl;
//将产生的数送到temp中,做位运算处理
temp = high;
temp = temp << 8;
//以16进制和二进制方式展示数据
// cout << hex << temp << endl;
// cout << bitset<16>(temp) << endl;
temp += low;
// cout << hex << temp << endl;
// cout << bitset<16>(temp) << endl;
gTemp = temp; //对数据进行存储
}
//return temp;
}
/*TCP代表的是一个传输控制协议,本质是一个传输控制的模块,包括一个IP地址和端口*/
int main(int argc, char *argv[])
{
//从哪里得到数据
//开启多线程 ,避免卡住没办法产生数据
QThread::create([](){
makeTemp();
})->start();
/*TCP连接服务器*/
QTcpSocket *client =new QTcpSocket; //建立一个socket对象
QHostAddress address("127.0.0.1"); //IP
client->connectToHost(address,8888); //端口
if(client->waitForConnected()) //监控真正拿到对应的地址和端口,在进行数据传输
{
//连接的对方的端口和地址
qDebug() << client->peerAddress();
qDebug() << client->peerPort();
//连接的自己的端口和地址
qDebug() << client->localAddress();
qDebug() << client->localPort();
//数据循环发送
while(1){
//write的用法 两个参数:char *的地址 数据的长度
//usleep(100*1000);
sleep(rand()%10);//10s钟之内发送一个数据
//cout << hex <<gTemp << endl;
qDebug() << client->write((char *)&gTemp,2);
client->flush();//缓冲区
}
}
return 0;
}
这里需要用到一个网络调试助手工具:SSokit
当我们完成制作模拟温度传感器产生数据,并完成了 TCP 客户端建立,需要验证我们制作的功能是否完善,那么就需要使用网络调试来判断。
首先编译运行QT的客户端程序,然后开启网络调试助手的服务器功能,输入IP地址和端口号,点击连接
即实现了模拟温度的产生,TCP客户端的建立,客户端采集到温度数据,并向模拟服务器发送的功能
第二步:数据接收及图表显示
细节步骤:
1、制作 TCP 服务器 (创建Qwidgets应用)
2、制作图表显示
3、创建 LCDNumber 对象并配置添加到界面上
4、开启服务器
5、链接服务器并传输数据
6、将数据传递给 LCDNumber 对象进行显示
7、验证数据显示是否正确
以下为实现代码:
#include "mainwidget.h"
#include<QDebug>
#include<QtCharts/QValueAxis>
#include<QTime>
void MainWidget::createChart()
{
//配置基础的图表数据
mainChart = new QChart();
dotSeries = new QScatterSeries;
//X、Y坐标系
QValueAxis *axisX = new QValueAxis;
QValueAxis *axisY = new QValueAxis;
//数值范围
axisX->setRange(0,60);
//数据形式
axisX->setLabelFormat("%.2f");
//是否显示表格分割虚线
axisX->setGridLineVisible(true);
//分割的格子数
axisX->setTickCount(7);
//最小分割
axisX->setMinorTickCount(1);
//坐标代表的含义标题
axisX->setTitleText("时间");
//数值范围
axisY->setRange(34,43);
//数据形式
axisY->setLabelFormat("%.2f");
//是否显示表格分割虚线
// axisY->setGridLineVisible(true);
//显示颜色
// axisY->setGridLineColor(Qt::red);
//分割的格子数
axisY->setTickCount(10);
//坐标代表的含义标题
axisY->setTitleText("体温");
mainChart->addAxis(axisX,Qt::AlignBottom);
mainChart->addAxis(axisY,Qt::AlignLeft);
mainChart->addSeries(dotSeries);
//隐藏图例
mainChart->legend()->hide();
//需要经坐标系和数值范围绑定在一起,否侧显示的数据不正确
//必须是将图类型添加到图表上之后
dotSeries->attachAxis(axisX);
dotSeries->attachAxis(axisY);
}
MainWidget::MainWidget(QWidget *parent)
: QWidget(parent),chartView(new QChartView(this)),currentTempLabel(new QLabel(this))
{
//对于绝大部分的界面元素,创建对象时,可以添加父元素的指针,代表加到父界面
// chartView = new QChartView(this);
// this->setGeometry(500,500,800,600);
this->setMinimumSize(800,600);
createChart();
chartView->setGeometry(200,0,600,400);
chartView->setChart(mainChart);
currentTempLabel->setGeometry(0,0,180,30);
currentTempLabel->setText("");
QFont f;
f.setBold(true);
f.setPointSize(10);
currentTempLabel->setFont(f);
currentTempLabel->setStyleSheet("color:red");
if(startSever())
{
qDebug()<<"等待连接";
connect(server,SIGNAL(newConnection()),this,SLOT(newConnectionAccept()));
}
}
MainWidget::~MainWidget()
{
}
bool MainWidget::startSever()
{
server = new QTcpServer();
return server->listen(QHostAddress("127.0.0.1"),8888); //监听IP和端口
}
void MainWidget::newConnectionAccept()
{
qDebug() <<"新连接已接入";
//获取当前传输套接字 可以进行数据的发送和接收
dataSocket = server->nextPendingConnection();
dataSocket->write("hello");
//客户端是否有新的数据发送
//有->触发readyRead信号
//可以对发送的数据进行处理
qreal passMinute = QTime::currentTime().minute();
connect(dataSocket,&QTcpSocket::readyRead,[=]()mutable{
//按照高8位和低8位数据转换成真正的温度数据
short temp = 0;
dataSocket->read((char *)&temp,2);
short t = temp >> 8;
float realTemp = t +(temp & 0x00ff) / 100.00;
qDebug() << realTemp;
//如果显示的点太多会混乱,所以每隔一分钟清除之前的那个点
if(passMinute != QTime::currentTime().minute())
{
dotSeries->clear();
passMinute = QTime::currentTime().minute();
}
dotSeries->append(QTime::currentTime().second(),realTemp);
QString tt("当前温度:");
tt += QString("%1").arg(realTemp);//转换数值
currentTempLabel->setText(tt);
});
}
以上代码实现了服务器端的建立,从客户端接收温度数据并以图表方式显示出来
首先编译运行服务器端的代码,然后编译运行客户端的代码,最后客户端和服务器会自动连接并显示采集到的温度数值,如下:
第三步:可视化展示及体温报警机制
细节步骤:
1、 QCharts 图表细节处理
2、 多媒体框架及音乐播放
经过以上两个步骤我们实现了体温监测显示的基本功能,还差一个报警功能未实现,即当采集到的温度超过37.3℃,监测平台会发出报警,图表的显示也不是很直观,需要设立一个警戒线,把所有的温度点连接起来
以下为具体代码实现:
#include "mainwidget.h"
#include<QDebug>
#include<QtCharts/QValueAxis>
#include<QTime>
#include <QApplication>
#include <QtGlobal>
void MainWidget::createChart()
{
//配置基础的图表数据
mainChart = new QChart();
dotSeries = new QScatterSeries;
alertLineSeries = new QLineSeries;
connectLineSeries = new QLineSeries;
//X、Y坐标系
QValueAxis *axisX = new QValueAxis;
QValueAxis *axisY = new QValueAxis;
//数值范围
axisX->setRange(0,60);
//数据形式
axisX->setLabelFormat("%.2f");
//是否显示表格分割虚线
axisX->setGridLineVisible(true);
//分割的格子数
axisX->setTickCount(7);
//最小分割
axisX->setMinorTickCount(1);
//坐标代表的含义标题
axisX->setTitleText("时间");
//数值范围
axisY->setRange(34,43);
//数据形式
axisY->setLabelFormat("%.2f");
axisY->setTickCount(10);
//坐标代表的含义标题
axisY->setTitleText("体温");
mainChart->addAxis(axisX,Qt::AlignBottom);
mainChart->addAxis(axisY,Qt::AlignLeft);
mainChart->addSeries(connectLineSeries);
mainChart->addSeries(alertLineSeries);
mainChart->addSeries(dotSeries); //注意这几条线的层次顺序,否则会覆盖住
//隐藏图例
mainChart->legend()->hide();
//需要经坐标系和数值范围绑定在一起,否侧显示的数据不正确
//必须是将图类型添加到图表上之后
dotSeries->setMarkerSize(15);
dotSeries->attachAxis(axisX);
dotSeries->attachAxis(axisY);
//警戒线
// alertLineSeries->setColor(Qt::red); //红色警戒线
alertLineSeries->setPen(QPen(Qt::red,5,Qt::DashDotLine));//设置红色同时设置线的粗细、样式
alertLineSeries->attachAxis(axisX);
alertLineSeries->attachAxis(axisY);
//连接线
connectLineSeries->setColor(Qt::blue);
connectLineSeries->attachAxis(axisX);
connectLineSeries->attachAxis(axisY);
alertLineSeries->append(0,37.3);
alertLineSeries->append(60,37.3);
}
MainWidget::MainWidget(QWidget *parent)
: QWidget(parent),
chartView(new QChartView(this)),
currentTempLabel(new QLabel(this)),
currentLcdnumber(new QLCDNumber(this))
{
//对于绝大部分的界面元素,创建对象时,可以添加父元素的指针,代表加到父界面
// chartView = new QChartView(this);
// this->setGeometry(500,500,800,600);
this->setMinimumSize(800,600);
createChart();
chartView->setGeometry(200,0,600,400);
chartView->setChart(mainChart);
currentTempLabel->setGeometry(0,0,180,30);
currentTempLabel->setText("");
QFont f;
f.setBold(true);
f.setPointSize(10);
currentTempLabel->setFont(f);
currentTempLabel->setStyleSheet("color:red");
//LCD显示数值
currentLcdnumber->setGeometry(0,50,180,50);
// currentLcdnumber->display("2020");
/*
1、设置播放器
2、配置多媒体资源
(1)是否能做为一个内部资源,不要放太大的资源,否则会导致编译时间过长
(2)是否能随着安装包发送
3、播放处理
*/
alertplayer = new QMediaPlayer;
// alertplayer -> setMedia(QUrl::fromLocalFile("/Users/KuGou/8069.mp3"));
//1、作为一个内部资源去播放
alertplayer->setMedia(QUrl("qrc:/8069.mp3"));
alertplayer->setVolume(50);
// alertplayer->play();
// qDebug() << qApp->applicationDirPath()<<endl;
//2、本地路径找寻播放那个文件,与Debug文件同级
// alertplayer->setMedia(QUrl::fromLocalFile(qApp->applicationDirPath() + "/" +"8069.mp3"));
if(startSever())
{
qDebug()<<"等待连接";
connect(server,SIGNAL(newConnection()),this,SLOT(newConnectionAccept()));
}
}
MainWidget::~MainWidget()
{
}
bool MainWidget::startSever()
{
server = new QTcpServer();
return server->listen(QHostAddress("127.0.0.1"),8888); //监听IP和端口
}
void MainWidget::newConnectionAccept()
{
qDebug() <<"新连接已接入";
//获取当前传输套接字 可以进行数据的发送和接收
dataSocket = server->nextPendingConnection();
dataSocket->write("hello");
//客户端是否有新的数据发送
//有->触发readyRead信号
//可以对发送的数据进行处理
qreal passMinute = QTime::currentTime().minute();
connect(dataSocket,&QTcpSocket::readyRead,[=]()mutable{
//按照高8位和低8位数据转换成真正的温度数据
short temp = 0;
dataSocket->read((char *)&temp,2);
short t = temp >> 8;
float realTemp = t +(temp & 0x00ff) / 100.00;
qDebug() << realTemp;
//如果显示的点太多会混乱,所以每隔一分钟清除之前的那个点
if(passMinute != QTime::currentTime().minute())
{
dotSeries->clear();
connectLineSeries->clear();
passMinute = QTime::currentTime().minute();
}
connectLineSeries->append(QTime::currentTime().second(),realTemp);
dotSeries->append(QTime::currentTime().second(),realTemp);
QString tt("当前温度:");
tt += QString("%1").arg(realTemp);//转换数值
currentTempLabel->setText(tt);
//LCD显示温度值
currentLcdnumber->display(realTemp);
if(realTemp >37.3)
{
if(alertplayer->state()==QMediaPlayer::PlayingState)
{
alertplayer->stop();
}
alertplayer->play();
}
});
}
经过以上步骤的细节处理,人体体温监测与报警项目就算是实现了,以下为现象:
备注:这是第二次做这个项目,之前可以完美运行,这次有点小问题,音乐暂时不能播放,最近也没时间弄了,以后有时间了在搞吧。。。
最后附上源码连接:
https://download.csdn.net/download/weixin_44618297/86415730