物联网项目LoveTv实现web网页传输数据到单片机-(技术栈涉及web前端,php后端,c/c++ socket,嵌入式前后端)

*作者:小成Charles
商业工作,学习交流请添加Vx:Lcc-Triumph
原创作品
转载请标注原创文章地址:https://blog.csdn.net/weixin_42999453/article/details/113502220
github完整代码地址:https://github.com/xiaocheng99/transparent_display_GUI
*

一、前言

因为看了B站上稚晖君的嵌入式开发视频,搞得我这个软件开发的也想弄一弄嵌入式,然后就设计了一下,做了我这个第一个物联网项目,我称之为LoveTV,这个是做了送给女朋友的,为了方便控制它以及传输数据,这里想到就直接用网页传输数据,这样很方便!服务器是要搭建在我的腾讯云服务器,也就是理论上来说,可以在任何地方实现数据传输。话不多说,上项目图!
在这里插入图片描述

在这里插入图片描述

二、设计思路

上面只是雏形,后期会添加和美化更多功能!这里我实现网页控制换页的方法是网页通过点击按钮会执行相应的PHP文件,php后端会创建一个udp协议,然后将数据发送给用C++创建的Udp服务端,服务端收到消息后会把消息再转发给单片机创建的Udp客户端,单片机客户端收到数据后会做相应的处理。这就是大致的思路,为了方便理解,我大致的流程画个图。在这里插入图片描述

三、核心代码(非完整代码)

(1)php后端
这里就是创建socket,指定为udpsocket,然后直接将数据传输给指定的服务器IP端口,注意php使用socket要到php.ini文件里面把extension=sockets前面的分号去掉,这样才能使用socket。

<?php
$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
$msg = '1';
$len = strlen($msg);
socket_sendto($sock, $msg, $len, 0, serverIp,serverPort);
header("Location: http://lovetv/index.html");
socket_close($sock);
?>

(2)c++后端
这里主要就是实现数据的转发,基于C++的框架Qt写得
tvServer.h

#ifndef TVSERVER_H
#define TVSERVER_H

#include <QUdpSocket>
#include <QObject>
#include <QList>

class tvServer : public QObject
{
    Q_OBJECT
public:
    explicit tvServer(QObject *parent = nullptr);
    QUdpSocket *udpServer;
    void bindServer(quint16 port);
    quint16 port;

    QHostAddress tvAddr;
    quint16 tvPort;

    QHostAddress webAddr;
    quint16 webPort;

    bool enter;

signals:

public slots:
    void onReadyRead();
};

#endif // TVSERVER_H

tvServer.cpp

#include "tvserver.h"

tvServer::tvServer(QObject *parent) : QObject(parent)
{
    udpServer=new QUdpSocket ();
    //test ip
    tvAddr.setAddress("192.168.1.91");
    tvPort=1520;
    enter=false;
    bindServer(1520);
    connect(udpServer,&QUdpSocket::readyRead,this,&tvServer::onReadyRead);
}
void tvServer::bindServer(quint16 port)
{//bind value
//    QHostAddress addr;
//    addr.setAddress("192.168.1.110");

    if(udpServer->bind(port))
    {
        qDebug()<<"successful bind!";
    }else {
        qDebug()<<"falied to bind!";

    }



}
void tvServer::onReadyRead()
{//server to revecive
    QByteArray   datagram;
    datagram.resize(udpServer->pendingDatagramSize());
    QHostAddress    peerAddr;
    quint16 peerPort;
    udpServer->readDatagram(datagram.data(),datagram.size(),&peerAddr,&peerPort);
    if(QString(datagram.data()) =="tv"&&enter==false)
    {
       qDebug()<<datagram.data()<<peerAddr<<peerPort;
       tvAddr=peerAddr;
       tvPort=peerPort;
       udpServer->writeDatagram("replay tv",peerAddr,peerPort);
       enter=true;
    }
    if(QString(datagram.data()) =="web"){
        webAddr=peerAddr;
        webPort=peerPort;
        qDebug()<<datagram.data()<<peerAddr<<peerPort;
}
//send msg to tv;

    qDebug()<<datagram.data()<<peerAddr<<peerPort;
    udpServer->writeDatagram(datagram.data(),tvAddr,tvPort);

}

(3)嵌入式c后端
编程IDE用的是Arduino,然后主板用的是ESp32,屏幕就是透明的OLED屏幕,前端不多说了,主要是利用u8g2这个图形框架写得,后端先连接wifi,然后利用WiFiUDP这个库创建客户端,一直循环去监听消息,收到消息后做出相应的判断;

这里是开启udp

  //开启udp工具
    if(udp.begin(WiFi.localIP(),udpLocalPort))
    {
      Serial.printf("现在收听IP:%s, UDP端口:%d\n", WiFi.localIP().toString().c_str(), udpLocalPort);
      //将wifi信息传输给服务器
      udp.beginPacket(udpServerAddr, udpServerPort);//配置远端ip地址和端口
      udp.print("tv");//把数据写入发送缓冲区
      udp.endPacket();//发送数据
     }else{
      Serial.println("监听失败");
      }

getUdpMsg()这里就是一直获得解析包,可以在loop里面去一直调用这个函数获得返回数据。

String Network::getUdpMsg()
{
//    udp.beginPacket(udpServerAddr, udpServerPort);//配置远端ip地址和端口
//    udp.print("mesg!");//把数据写入发送缓冲区
//    udp.endPacket();//发送数据

  int packetSize = udp.parsePacket();//获得解析包
  if (packetSize)//解析包不为空
  {
    //收到Udp数据包
    //Udp.remoteIP().toString().c_str()用于将获取的远端IP地址转化为字符串
    Serial.printf("收到来自远程IP:%s(远程端口:%d)的数据包字节数:%d\n", udp.remoteIP().toString().c_str(), udp.remotePort(), packetSize);
      
    // 解析UDP数据包中的所以数据,以字符串格式返回
    String udpStringVal = udp.readString(); 
    
    // 然后向串口打印返回的字符串
    Serial.print("开发板接收到UDP数据中的字符串 "); Serial.println(udpStringVal);

    return udpStringVal;
  }
   }

这里用了一个Chrono线程库,让这个函数一直处于一个单独的线程运行
hasPassed()里面给的参数越小,延迟就越小,单位为毫秒

  if (timeChrono.hasPassed(10) ) { // elapsed(1000) returns 1 if 1000ms have passed.
    timeChrono.restart();  // restart the Chrono 
   String msgVal= wifi.getUdpMsg();
   if(msgVal.toInt()!=0){ 
   nowPage=msgVal.toInt();
   Serial.println(nowPage);
}

四、总结和扩展

目前还处于雏形阶段,就是理论已经成型了,接下来就是完善和优化了,需要改进的就是Udp协议虽然面型无连接但是由于单片机的性能太低,网络信号差,特别容易丢包,导致数据接收不到,那么改进就是换成TCP协议或者对UDP协议做一个类似于TCp三次握手的数据是否接受的检测来保证数据传输到了。

作者:小成Charles
原创作品
转载请标注原创文章地址:[https://blog.csdn.net/weixin_42999453/article/details/113502220]
(https://blog.csdn.net/weixin_42999453/article/details/113502220)

商业工作,学习交流请添加Vx:Lcc-Triumph

  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
2022 / 01/ 30: 新版esptool 刷micropython固件指令不是 esptool.py cmd... 而是 esptool cmd... 即可;另外rshell 在 >= python 3.10 的时候出错解决方法可以查看:  已于2022年发布的: 第二章:修复rshell在python3.10出错 免费内容: https://edu.csdn.net/course/detail/29666 micropython语法和python3一样,编写起来非常方便。如果你快速入门单片机物联网而且像轻松实现各种功能,那绝力推荐使用micropython。方便易懂易学。 同时如果你懂C语音,也可以用C写好函数并编译进micropython固件里然后进入micropython调用(非必须)。 能通过WIFI联网(2.1章),也能通过sim卡使用2G/3G/4G/5G联网(4.5章)。 为实现语音控制,本教程会教大家使用tensorflow利用神经网络训练自己的语音模型并应用。为实现通过网页控制,本教程会教大家linux(debian10 nginx->uwsgi->python3->postgresql)网站前后台入门。为记录单片机传输过来的数据, 本教程会教大家入门数据库。  本教程会通过通俗易懂的比喻来讲解各种原理与思路,并手把手编写程序来实现各项功能。 本教程micropython版本是 2019年6月发布的1.11; 更多内容请看视频列表。  学习这门课程之前你需要至少掌握: 1: python3基础(变量, 循环, 函数, 常用库, 常用方法)。 本视频使用到的零件与淘宝上大致价格:     1: 超声波传感器(3)     2: MAX9814麦克风放大模块(8)     3: DHT22(15)     4: LED(0.1)     5: 8路5V低电平触发继电器(12)     6: HX1838红外接收模块(2)     7:红外发射管(0.1),HX1838红外接收板(1)     other: 电表, 排线, 面包板(2)*2,ESP32(28)  

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值