小成開發日記----物聯網項目LoveTv實現web網頁傳輸數據到單片機(技術棧涉及web前端,php後端,c/c++ socket,嵌入式前後端)
作者:小成Charles
原創作品
轉載請標註原創文章地址:https://blog.csdn.net/weixin_42999453/article/details/113502220
一、前言
因為看了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
- 小成開發日記----物聯網項目LoveTv實現web網頁傳輸數據到單片機(技術棧涉及web前端,php後端,c/c socket,嵌入式前後端)
- STM32學習筆記(二十)
- mybatis中:returned more than one row, where no more than one was expected.異常
- SpringBoot SpringSecurity JWT實現認證和授權
- 引燃AI社區,不用跨界也能從文本生成圖像,OpenAI新模型打破自然語言與視覺次元壁2 - 知乎
- 手遊作弊(二)-內存讀寫實例
- [上海]景慄 (天使輪 A輪A B輪)CDP/MA 35-50K 年終獎
- idea控制枱亂碼(tomcat日誌亂碼)的解決辦法
- 【Linux】硬鏈接和軟鏈接
- Nginx負載均衡
- 他本碩博連跨3大專業,畢業後沒多久被破格聘為985高校教授!
- 真漲工資了:多所高校博士生資助標準大幅度提升
- ”12306“秒殺系統的設計藝術
- 實戰排查|為什麼遮擋推流攝像頭,會導致播放綠屏?
- 社區團購是騰訊的電商大賽馬,美團、京東、拼多多合圍買菜:戰無不勝的“流量 資本” - 知乎
- Covetrus完成與原母公司的分離
- 贈書 | 在Python領域,你與專家之間的距離只差這兩本書
- Adam真的是最好的優化器嗎?有人認為不過是神經網絡進化的結果 - 知乎
- Spring Cloud Alibaba 新一代微服務解決方案
- 深入解析 C# 的 String.Create 方法