当前位置:   article > 正文

基于QT+树莓派实现智能家居系统_树莓派 qt

树莓派 qt

一、环境条件

上位机开发环境:Qt Creator 4.8.1

下位机开发环境:树莓派4b

此处省略Qt前端设计,只阐述后端逻辑实现

二、框架构建

上位机:

 下位机:

 三、程序编写(Qt)

1.程序初始界面

初始界面包含登录,网络控制,串口控制三个按钮。此时为未登录状态,登录标志按钮flag=0,此时点击其中的任意按钮,都会跳转到登录按钮。登录成功后,标志按钮flag=1,此时再点击登录按钮,只会弹出QMessageBox消息框提示登录成功,点击网络控制按钮则跳转到网络控制界面,点击串口控制按钮则会跳转到串口控制页面。

.h文件:

  1. #ifndef WIDGET_H
  2. #define WIDGET_H
  3. #include <QWidget>
  4. namespace Ui {
  5. class Widget;
  6. }
  7. class Widget : public QWidget
  8. {
  9. Q_OBJECT
  10. public:
  11. explicit Widget(QWidget *parent = nullptr);
  12. ~Widget();
  13. private slots:
  14. void on_logButton_clicked();
  15. void on_networkButton_clicked();
  16. void on_serialButton_clicked();
  17. private:
  18. Ui::Widget *ui;
  19. };
  20. #endif // WIDGET_H

.c文件:

  1. #include "widget.h"
  2. #include "ui_widget.h"
  3. #include "login.h"
  4. #include "QMessageBox"
  5. #include <network.h>
  6. #include <serial.h>
  7. extern int flag;
  8. Widget::Widget(QWidget *parent) :
  9. QWidget(parent),
  10. ui(new Ui::Widget)
  11. {
  12. ui->setupUi(this);
  13. }
  14. Widget::~Widget()
  15. {
  16. delete ui;
  17. }
  18. void Widget::on_logButton_clicked()
  19. {
  20. if(flag==0)//登录标志位flag=0
  21. {
  22. login *lg=new login;
  23. lg->setGeometry(this->geometry());
  24. lg->show();
  25. this->close();
  26. }
  27. else if (flag==1) {
  28. QMessageBox::information(this,"提示","您已成功登录");
  29. }
  30. }
  31. void Widget::on_networkButton_clicked()
  32. {
  33. if(flag==0)
  34. {
  35. login *lg=new login;
  36. lg->setGeometry(this->geometry());
  37. lg->show();
  38. this->close();
  39. }
  40. else if (flag==1) {
  41. network *net=new network;
  42. net->setGeometry(this->geometry());
  43. net->show();
  44. }
  45. }
  46. void Widget::on_serialButton_clicked()
  47. {
  48. if(flag==0)
  49. {
  50. login *lg=new login;
  51. lg->setGeometry(this->geometry());
  52. lg->show();
  53. this->close();
  54. }
  55. else if (flag==1) {
  56. serial *se=new serial;
  57. se->setGeometry(this->geometry());
  58. se->show();
  59. this->close();
  60. }
  61. }

2.登录界面

登录框输入账号密码,点击"登录",拉取账号密码与数据库进行比对。若对比成功,登录标志flag置1,定时器启动,弹出QMessageBox消息框提示登录成功,保持1.5s,后自动关闭。若失败,登录标志不改变,弹出QMessageBox消息框提示登录失败。

.h文件

  1. #ifndef LOGIN_H
  2. #define LOGIN_H
  3. #include <QWidget>
  4. namespace Ui {
  5. class login;
  6. }
  7. class login : public QWidget
  8. {
  9. Q_OBJECT
  10. public:
  11. explicit login(QWidget *parent = nullptr);
  12. ~login();
  13. private slots:
  14. void on_pushButton_clicked();
  15. void on_backButton_clicked();
  16. private:
  17. Ui::login *ui;
  18. };
  19. #endif // LOGIN_H

.c文件

  1. #include "login.h"
  2. #include "ui_login.h"
  3. #include "QString"
  4. #include "widget.h"
  5. #include "QMessageBox"
  6. #include "QTimer"
  7. login::login(QWidget *parent) :
  8. QWidget(parent),
  9. ui(new Ui::login)
  10. {
  11. ui->setupUi(this);
  12. setWindowIcon(QIcon(":/home.ico"));
  13. }
  14. login::~login()
  15. {
  16. delete ui;
  17. }
  18. extern int flag=0;
  19. void login::on_pushButton_clicked()
  20. {
  21. QString username=ui->countEdit->text();
  22. QString passwd=ui->passwdEdit->text();
  23. if(username=="8888"&&passwd=="6688")
  24. {
  25. Widget *wd=new Widget;
  26. wd->setGeometry(this->geometry());
  27. wd->show();
  28. flag=1;
  29. QMessageBox *box=new QMessageBox(QMessageBox::Information,"提示","登录成功");
  30. QTimer::singleShot(1500,box,SLOT(close()));
  31. this->close();
  32. }
  33. else {
  34. QMessageBox::critical(this,"提示","密码或用户名错误");
  35. }
  36. }
  37. void login::on_backButton_clicked()
  38. {
  39. Widget *wd=new Widget;
  40. wd->setGeometry(this->geometry());
  41. wd->show();
  42. this->close();
  43. }

3.网络控制界面

TCP连接与发送:界面初始化时,就已经初始化好tcpSocket,输入目的ip地址,目的端口后,点击连接,TCP开始与树莓派服务器连接,若连接成功,会接收到连接成功信号,触发绑定的槽函数并弹出QMessageBox消息框提示登录成功,并建立新的TCP连接。随后调节智能家电的参数,点击发送按钮,会将参数打包成TCP数据包,发送到树莓派控制硬件。

UDP连接与发送:网络控制界面开启时,就已经初始化好udpSocket,输入本地端口,点击接收开启连接,若连接成功弹出QMessageBox消息框,若此时有数据传输,则触发接收槽函数,并将接收到的内容显示到lable框中。

.h文件

  1. #ifndef NETWORK_H
  2. #define NETWORK_H
  3. #include <QWidget>
  4. #include <QTcpServer>
  5. #include <QTcpSocket>
  6. #include <QUdpSocket>
  7. namespace Ui {
  8. class network;
  9. }
  10. class network : public QWidget
  11. {
  12. Q_OBJECT
  13. public:
  14. explicit network(QWidget *parent = nullptr);
  15. ~network();
  16. QTcpSocket *tcpSocket;
  17. QUdpSocket *udpSocket;
  18. private slots:
  19. void on_horizontalSlider_valueChanged(int value);
  20. void on_spinBox_valueChanged(int arg1);
  21. void on_openTVButton_clicked();
  22. void on_upButton_clicked();
  23. void on_nextButton_clicked();
  24. void on_TCPconnectButton_clicked();
  25. void connect_slot();
  26. void readyRead_slot();
  27. void readyReadUDP_slot();
  28. void on_TCPcloseButton_clicked();
  29. void on_sendButton_clicked();
  30. void on_UDPconnectButton_clicked();
  31. void on_UDPcloseButton_clicked();
  32. private:
  33. Ui::network *ui;
  34. };
  35. #endif // NETWORK_H

.c文件

  1. #include "network.h"
  2. #include "ui_network.h"
  3. #include <widget.h>
  4. #include <iostream>
  5. #include "QMessageBox"
  6. #include "QString"
  7. using namespace std;
  8. static int lightnum;//灯的数值
  9. static int airnum=15;//空调的数值
  10. static int TVon=0;//0表示电视关闭
  11. static int TVchannle=35;//表示电视频道
  12. network::network(QWidget *parent) :
  13. QWidget(parent),
  14. ui(new Ui::network)
  15. {
  16. ui->setupUi(this);
  17. setWindowIcon(QIcon(":/home.ico"));
  18. tcpSocket=new QTcpSocket(this);
  19. udpSocket=new QUdpSocket(this);
  20. }
  21. network::~network()
  22. {
  23. delete ui;
  24. Widget *wd=new Widget;
  25. wd->setGeometry(this->geometry());
  26. wd->show();
  27. }
  28. void network::on_horizontalSlider_valueChanged(int value)
  29. {
  30. lightnum=ui->horizontalSlider->value();
  31. ui->light_value_label->setText(QString::number(lightnum));
  32. }
  33. void network::on_spinBox_valueChanged(int arg1)
  34. {
  35. airnum=ui->spinBox->value();
  36. cout<<airnum<<endl;
  37. }
  38. void network::on_openTVButton_clicked()
  39. {
  40. if(TVon==0)
  41. {
  42. TVon=1;
  43. ui->openTVButton->setText("关");
  44. }
  45. else if (TVon==1) {
  46. TVon=0;
  47. ui->openTVButton->setText("开");
  48. }
  49. }
  50. void network::on_upButton_clicked()
  51. {
  52. if(TVon==1)
  53. {
  54. TVchannle=TVchannle+1;
  55. if(TVchannle=100)
  56. {
  57. TVchannle=10;
  58. }
  59. cout<<TVchannle<<endl;
  60. }
  61. }
  62. void network::on_nextButton_clicked()
  63. {
  64. if(TVon==1)
  65. {
  66. TVchannle=TVchannle-1;
  67. if(TVchannle==10)
  68. {
  69. TVchannle=99;
  70. }
  71. cout<<TVchannle<<endl;
  72. }
  73. }
  74. void network::on_TCPconnectButton_clicked()
  75. {
  76. //tcpSocket->connectToHost(ui->ipaddrEdit->text(),ui->aimportEdit->text().toUInt());
  77. tcpSocket->connectToHost("192.168.43.146",50001);
  78. connect(tcpSocket,SIGNAL(connected()),this,SLOT(connect_slot()));
  79. }
  80. void network::connect_slot()
  81. {
  82. QMessageBox(QMessageBox::Information,"提示","连接成功");
  83. connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readyRead_slot()));
  84. }
  85. void network::readyRead_slot()
  86. {
  87. cout<<"TCP数据来喽!!"<<endl;
  88. }
  89. void network::on_TCPcloseButton_clicked()
  90. {
  91. tcpSocket->close();
  92. }
  93. void network::on_sendButton_clicked()
  94. {
  95. QString temp;
  96. if(lightnum>9)
  97. {
  98. temp.sprintf("%d%d%d%d",lightnum,airnum,TVon,TVchannle);
  99. }
  100. else if (0<=lightnum<=9) {
  101. temp.sprintf("0%d%d%d%d",lightnum,airnum,TVon,TVchannle);
  102. }
  103. tcpSocket->write(temp.toLocal8Bit().data());
  104. }
  105. void network::on_UDPconnectButton_clicked()
  106. {
  107. if(udpSocket->bind(5554))
  108. {
  109. QMessageBox::information(this,"提示","UDP打开成功");
  110. }
  111. else {
  112. QMessageBox::critical(this,"提示","UDP打开失败");
  113. }
  114. connect(udpSocket,SIGNAL(readyRead()),SLOT(readyReadUDP_slot()));
  115. }
  116. void network::readyReadUDP_slot()
  117. {
  118. cout<<"UDP数据来咯!"<<endl;
  119. while (udpSocket->hasPendingDatagrams()) {
  120. QByteArray array;
  121. array.resize(udpSocket->pendingDatagramSize());
  122. udpSocket->readDatagram(array.data(),array.size());
  123. QString buf;
  124. buf=array.data();
  125. ui->plainTextEdit->appendPlainText(buf);
  126. }
  127. }
  128. void network::on_UDPcloseButton_clicked()
  129. {
  130. udpSocket->close();
  131. }

4.串口控制界面

串口界面打开时,使用foreach函数将可用的串口查找出来,保存到QStringList的变量中并在界面上显示,将串口各个参数配置好后,点击"打开",配置的参数被赋给serialPort结构体的各个参数,并触发serialPort的open函数打开串口,若打开成功,QMessageBox弹窗提示打开成功。若打开失败,QMessageBox弹窗提示。

.h文件

  1. #ifndef SERIAL_H
  2. #define SERIAL_H
  3. #include <QWidget>
  4. #include <QSerialPortInfo>
  5. #include <QSerialPort>
  6. #include <QTimer>
  7. #include <QTime>
  8. namespace Ui {
  9. class serial;
  10. }
  11. class serial : public QWidget
  12. {
  13. Q_OBJECT
  14. public:
  15. explicit serial(QWidget *parent = nullptr);
  16. ~serial();
  17. QSerialPort *serialPort;
  18. QTimer timer;
  19. private slots:
  20. void on_openButton_clicked();
  21. void on_closeButton_clicked();
  22. void serialPort_ReadyRead_slot();
  23. void timeout_slot();
  24. void on_snedButton_clicked();
  25. void on_clearButton_clicked();
  26. void on_backButton_clicked();
  27. private:
  28. Ui::serial *ui;
  29. };
  30. #endif // SERIAL_H

.c文件

  1. #include "serial.h"
  2. #include "ui_serial.h"
  3. #include "QMessageBox"
  4. #include "widget.h"
  5. serial::serial(QWidget *parent) :
  6. QWidget(parent),
  7. ui(new Ui::serial)
  8. {
  9. ui->setupUi(this);
  10. setWindowIcon(QIcon(":/home.ico"));
  11. QStringList serialNamePort;
  12. foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
  13. {
  14. serialNamePort<<info.portName();
  15. }
  16. ui->serialcomboBox->addItems(serialNamePort);
  17. connect(&timer,SIGNAL(timeout()),this,SLOT(timeout_slot()));
  18. }
  19. serial::~serial()
  20. {
  21. delete ui;
  22. }
  23. void serial::serialPort_ReadyRead_slot()
  24. {
  25. QString buf;
  26. QTime time=QTime::currentTime();
  27. buf=QString(serialPort->readAll());
  28. ui->revcTextEdit->appendPlainText(time.toString("hh:mm:ss"));
  29. ui->revcTextEdit->appendPlainText(buf);
  30. }
  31. void serial::timeout_slot()
  32. {
  33. }
  34. void serial::on_openButton_clicked()
  35. {
  36. serialPort=new QSerialPort(this);
  37. QSerialPort::BaudRate buadRate;
  38. QSerialPort::DataBits dataBits;
  39. QSerialPort::StopBits stopBits;
  40. QSerialPort::Parity checkBits;
  41. if(ui->botecomboBox->currentText()=="4800")
  42. {
  43. buadRate=QSerialPort::Baud4800;
  44. }
  45. else if (ui->botecomboBox->currentText()=="9600") {
  46. buadRate=QSerialPort::Baud9600;
  47. }
  48. else if (ui->botecomboBox->currentText()=="19200") {
  49. buadRate=QSerialPort::Baud19200;
  50. }
  51. else if (ui->botecomboBox->currentText()=="115200") {
  52. buadRate=QSerialPort::Baud115200;
  53. }
  54. if(ui->datacomboBox->currentText()=="5")
  55. {
  56. dataBits=QSerialPort::Data5;
  57. }
  58. else if (ui->datacomboBox->currentText()=="6") {
  59. dataBits=QSerialPort::Data6;
  60. }
  61. else if (ui->datacomboBox->currentText()=="7") {
  62. dataBits=QSerialPort::Data7;
  63. }
  64. else if (ui->datacomboBox->currentText()=="8") {
  65. dataBits=QSerialPort::Data8;
  66. }
  67. if(ui->stopcomboBox->currentText()=="1")
  68. {
  69. stopBits=QSerialPort::OneStop;
  70. }
  71. else if (ui->stopcomboBox->currentText()=="3") {
  72. stopBits=QSerialPort::OneAndHalfStop;
  73. }
  74. else if (ui->stopcomboBox->currentText()=="2") {
  75. stopBits=QSerialPort::TwoStop;
  76. }
  77. if(ui->jiaoyancomboBox->currentText()=="none")
  78. {
  79. checkBits=QSerialPort::NoParity;
  80. }
  81. serialPort->setPortName(ui->serialcomboBox->currentText());
  82. serialPort->setBaudRate(buadRate);
  83. serialPort->setDataBits(dataBits);
  84. serialPort->setStopBits(stopBits);
  85. serialPort->setParity(checkBits);
  86. if(serialPort->open(QIODevice::ReadWrite)==true)
  87. {
  88. QMessageBox::information(this,"提示","成功");
  89. connect(serialPort,SIGNAL(readyRead()),this,SLOT(serialPort_ReadyRead_slot()));
  90. }
  91. else {
  92. QMessageBox::critical(this,"提示","失败");
  93. }
  94. }
  95. void serial::on_closeButton_clicked()
  96. {
  97. serialPort->close();
  98. }
  99. void serial::on_snedButton_clicked()
  100. {
  101. serialPort->write(ui->snedlineEdit->text().toLocal8Bit().data());
  102. }
  103. void serial::on_clearButton_clicked()
  104. {
  105. ui->revcTextEdit->clear();
  106. ui->snedlineEdit->clear();
  107. }
  108. void serial::on_backButton_clicked()
  109. {
  110. Widget *wd=new Widget;
  111. wd->setGeometry(this->geometry());
  112. wd->show();
  113. this->close();
  114. }

四、程序编写(树莓派wiringPi)

程序启动后,首先调用pthread_create创建2个线程tcp\serial,并使用pthread_detach分离线程。串口线程创建成功后,使用serialOpen打开串口,配置参数,发送验证性字符随后进入while(1)采集并发送环境信息。tcp线程创建后等待客户端连接,客户端连接成功后,创建第3个udp线程,随后进入while(1)等待tcp数据并处理。udp线程创建成功后,创建套接字,绑定端口和ip地址,等待连接,连接成功后进入while(1)进入发送

  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <netinet/in.h>
  7. #include <arpa/inet.h>
  8. #include <unistd.h>
  9. #include <time.h>
  10. #include <wiringPi.h>
  11. #include <wiringSerial.h>
  12. #include <sys/wait.h>
  13. #include <signal.h>
  14. #include <pthread.h>
  15. #include <stdio.h>
  16. #include <time.h>
  17. #include <sys/time.h>
  18. #include <stdlib.h>
  19. #include <signal.h>
  20. char msg[20];
  21. void *UDP(void)
  22. {
  23. pthread_detach(pthread_self());//将当前线程分离
  24. //创建套接字
  25. int sock_fd = socket(AF_INET,SOCK_DGRAM,0);
  26. //绑定地址(IP+PORT)
  27. struct sockaddr_in srvaddr,ciladdr;
  28. srvaddr.sin_family = AF_INET;//地址族
  29. //端口
  30. srvaddr.sin_port = htons(5554); //端口一般取50000以上
  31. //IP地址
  32. srvaddr.sin_addr.s_addr = inet_addr("192.168.43.210");//将文本字符串转换为32位无符号网络地址
  33. char buf[100];
  34. int len = sizeof(ciladdr);
  35. while(1)
  36. {
  37. bzero(buf,100);
  38. fgets(buf,100,stdin); //从键盘输入数据
  39. sendto(sock_fd,buf,100,0,(struct sockaddr *)&srvaddr,sizeof(srvaddr));
  40. }
  41. //关闭套接字
  42. close(sock_fd);
  43. }
  44. int light;
  45. int airnum;
  46. int TVon;
  47. int TVchannel;
  48. void *TCPServer(void)
  49. {
  50. pthread_detach(pthread_self());//将当前线程分离
  51. //创建套接字
  52. int sock_fd = socket(PF_INET,SOCK_STREAM,0);
  53. //绑定地址(IP+PORT)
  54. struct sockaddr_in srvaddr;
  55. srvaddr.sin_family = PF_INET;//地址族
  56. //端口
  57. srvaddr.sin_port = htons(50001); //端口一般取50000以上
  58. //IP地址
  59. srvaddr.sin_addr.s_addr = inet_addr("192.168.43.146");//将文本字符串转换为32位无符号网络地址
  60. bind(sock_fd,(struct sockaddr *)&srvaddr,sizeof(srvaddr));
  61. //设置监听套接字
  62. listen(sock_fd,4);
  63. //等待客户端连接
  64. printf("等待连接\n");
  65. int conn_fd = accept(sock_fd,NULL,NULL);
  66. printf("连接成功\n");
  67. pthread_t th3;
  68. pthread_create(&th3,NULL,UDP,NULL);
  69. while(1)
  70. {
  71. bzero(msg,20);
  72. recv(conn_fd,msg,20,0);
  73. printf("recv:%s\n",msg);
  74. light=(msg[0]-48)*10+(msg[1]-48);
  75. airnum=(msg[2]-48)*10+(msg[3]-48);
  76. TVon=msg[4]-48;
  77. TVchannel=(msg[5]-48)*10+(msg[6]-48);
  78. }
  79. //关闭套接字
  80. close(conn_fd);
  81. close(sock_fd);
  82. }
  83. void *serial()
  84. {
  85. pthread_detach(pthread_self());//将当前线程分离
  86. int fd;
  87. int cmd;
  88. int i=0;
  89. if(wiringPiSetup()==-1)
  90. {
  91. printf("setup wiringPi failed!\n");
  92. return 1;
  93. }
  94. fd=serialOpen("/dev/ttyAMA0",115200);
  95. if(-1==fd)
  96. {
  97. printf("ttyAMA open error!\n");
  98. }
  99. serialPuts(fd,"message from uart\r\n");
  100. printf("uart send finish\n");
  101. delay(1000);
  102. while(1)
  103. {
  104. serialPuts(fd,"Temp: Lum:\0");
  105. delay(3000);
  106. serialPrintf(fd,"%d %.1f\r\n",(airnum+5),light*0.657);
  107. delay(3000);
  108. // serialFlush(fd);
  109. }
  110. serialClose(fd);
  111. }
  112. void signal_handler()
  113. {
  114. static int i=0;
  115. i++;
  116. if(i<=light)
  117. {
  118. digitalWrite(7,HIGH);
  119. }
  120. else if(light<i<100)
  121. {
  122. digitalWrite(7,LOW);
  123. }
  124. if(100==i)
  125. {
  126. i=0;
  127. }
  128. }
  129. int main()
  130. {
  131. pthread_t th1,th2;
  132. pthread_create(&th1,NULL,TCPServer,NULL);
  133. pthread_create(&th2,NULL,serial,NULL);
  134. if(wiringPiSetup()==-1)
  135. {
  136. printf("setup wiringPi faild!");
  137. return 1;
  138. }
  139. struct itimerval itv;
  140. itv.it_interval.tv_sec=0;
  141. itv.it_interval.tv_usec=500;
  142. itv.it_value.tv_sec=1;
  143. itv.it_value.tv_usec=0;
  144. pinMode(7,OUTPUT);
  145. pinMode(1,OUTPUT);
  146. pinMode(0,OUTPUT);
  147. setitimer(ITIMER_REAL,&itv,NULL);
  148. signal(SIGALRM,signal_handler);
  149. while(1)
  150. {
  151. if(airnum==15)
  152. {
  153. digitalWrite(1,LOW);
  154. }
  155. else if(airnum>16)
  156. {
  157. digitalWrite(1,HIGH);
  158. }
  159. if(TVon==0)
  160. {
  161. digitalWrite(0,LOW);
  162. }
  163. else if(TVon==1)
  164. {
  165. digitalWrite(0,HIGH);
  166. }
  167. };
  168. return 0;
  169. }

五、结语

        这个项目做的马马虎虎,很多设想的功能都是通过模拟的方式实现,还有许多不足之处需要好好打磨斟酌。因此有错误之处,还请批评指正。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/232166
推荐阅读
相关标签
  

闽ICP备14008679号