本文來源電子發(fā)燒友社區(qū),作者:李元江, 帖子地址:https://bbs.elecfans.com/jishu_2028163_1_1.html
復(fù)制代碼
復(fù)制代碼
2、TCP數(shù)據(jù)接收和發(fā)送任務(wù)
復(fù)制代碼
3、連接服務(wù)器切換
復(fù)制代碼
三、演示情況
四、總結(jié)
今天的帖子是關(guān)于如何讓手機(jī)可以與wifiiot進(jìn)行遠(yuǎn)程通信。通過遠(yuǎn)程的TCP中轉(zhuǎn)服務(wù)端,讓手機(jī)與板子進(jìn)行可以進(jìn)行遠(yuǎn)程數(shù)據(jù)傳輸。
一、數(shù)據(jù)傳輸過程
該過程與局域網(wǎng)內(nèi)的TCP服務(wù)端與客戶端數(shù)據(jù)傳輸過程很類似。局域網(wǎng)內(nèi)是這樣的,兩個(gè)設(shè)備在同一個(gè)局域網(wǎng)內(nèi),一個(gè)作為TCP服務(wù)端,一個(gè)作為TCP客戶端,這樣這兩個(gè)設(shè)備就是進(jìn)行局域網(wǎng)內(nèi)的數(shù)據(jù)通信。但是兩個(gè)設(shè)備不在同一個(gè)網(wǎng)絡(luò)內(nèi),數(shù)據(jù)傳輸在上面的方法是行不通的。這時(shí)可以借助一個(gè)在公網(wǎng)的TCP中轉(zhuǎn)服務(wù)端,實(shí)現(xiàn)兩個(gè)設(shè)備的遠(yuǎn)程數(shù)據(jù)傳輸。數(shù)據(jù)傳輸過程為兩個(gè)設(shè)備都作為TCP客戶端,一個(gè)設(shè)備把數(shù)據(jù)傳輸?shù)椒?wù)端,然后服務(wù)端把數(shù)據(jù)傳輸?shù)搅硪粋€(gè)設(shè)備。但是這也要求,這兩個(gè)設(shè)備的網(wǎng)絡(luò)是可以連接到公網(wǎng)的,否則是無法連接到公網(wǎng)的TCP服務(wù)端。
二、軟件設(shè)計(jì)
首先我們需要一個(gè)在公網(wǎng)的TCP客戶端。如果各位自己有云服務(wù)器的,可以自行搭建一個(gè)TCP中轉(zhuǎn)服務(wù)端。我使用的客戶端是別人用于測(cè)試的客戶端。軟件方面需要考慮幾個(gè)問題:
-
連接服務(wù)器的切換在我的上幾個(gè)帖子上,需要連接其他服務(wù)器獲取時(shí)間數(shù)據(jù)或者獲取天氣數(shù)據(jù)。這時(shí),我們需要在進(jìn)行連接服務(wù)器切換,確保獲取的數(shù)據(jù)正常。
-
連接狀態(tài)檢測(cè)我們還需要進(jìn)行連接狀態(tài)檢查,如果與TCP服務(wù)端斷開,是無法正常進(jìn)行數(shù)據(jù)交互的。
-
連接重連如果檢查到連接斷開,或者沒有連接成功,需要重新嘗試進(jìn)行與服務(wù)端的連接。
新建tcp_connect.c tcp_connect.h文件,里面主要是與TCP連接、TCP連接斷開、TCP數(shù)據(jù)發(fā)送、數(shù)據(jù)接收相關(guān)的函數(shù)。注意:TCPIPADDR、TCPPORT是公網(wǎng)TCP客戶端IP地址和端口號(hào)。其實(shí)這幾個(gè)函數(shù)是在之前的tcp例程中拆分出來的,把一個(gè)函數(shù)劃分為四個(gè)函數(shù)而已。
-
設(shè)置接收超時(shí)之前的例程中,沒有加入接收超時(shí)機(jī)制,如果沒有接收到數(shù)據(jù),會(huì)一直呈現(xiàn)阻塞狀態(tài),其他任務(wù)可能會(huì)出現(xiàn)無法正常運(yùn)行的狀態(tài),所以我們需要加入超時(shí)機(jī)制,超過一定時(shí)間沒接收到數(shù)據(jù),也會(huì)推出退出接收過程。timeval 在頭文件中。//設(shè)置接收超時(shí)struct timeval timeout={2,0};//1sif (setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(struct timeval)) == -1){ printf("setsockopt failed!rn"); //goto do_cleanup;}
-
tcp_connect.c
- #include "tcp_connect.h"
- //#define TCPIPADDR "192.168.3.9"
- //#define TCPPORT 5678
- #define TCPIPADDR "115.29.109.104"
- #define TCPPORT 6545
- ?
- static int sockfd;
- static int netId;
- static struct sockaddr_in serverAddr = {0};
- ?
- TCP_STATIC connect_status = DISCONNECTED;
- //extern char sendData[30];
- ?
- bool TcpConnect(void)
- {
- bool connectflag = false;
- WifiDeviceConfig config = {0};
- ?
- // 準(zhǔn)備AP的配置參數(shù)
- strcpy(config.ssid, PARAM_HOTSPOT_SSID);
- strcpy(config.preSharedKey, PARAM_HOTSPOT_PSK);
- config.securityType = PARAM_HOTSPOT_TYPE;
- osDelay(10);
- netId= ConnectToHotspot(&config);
- ?
- sockfd = socket(AF_INET, SOCK_STREAM, 0); // TCP socket
- ?
- serverAddr.sin_family = AF_INET;// AF_INET表示IPv4協(xié)議
- serverAddr.sin_port = htons(TCPPORT);// 端口號(hào),從主機(jī)字節(jié)序轉(zhuǎn)為網(wǎng)絡(luò)字節(jié)序
- if (inet_pton(AF_INET, TCPIPADDR , &serverAddr.sin_addr) <= 0) {??// 將主機(jī)IP地址從“點(diǎn)分十進(jìn)制”字符串 轉(zhuǎn)化為 標(biāo)準(zhǔn)格式(32位整數(shù))
- printf("inet_pton failed!rn");
- goto do_cleanup;
- }
- ?
- //設(shè)置接收超時(shí)
- struct timeval timeout={2,0};//1s
- if (setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(struct timeval)) == -1)
- {
- printf("setsockopt failed!rn");
- //goto do_cleanup;
- }
- ?
- // 嘗試和目標(biāo)主機(jī)建立連接,連接成功會(huì)返回0 ,失敗返回 -1
- if (connect(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) {
- printf("connect failed!rn");
- goto do_cleanup;
- }
- printf("connect to server %s success!rn",TCPIPADDR);
- connectflag = true;
- connect_status = CONNECTED;
- do_cleanup:
- return connectflag;
- }
- ?
- bool TcpDisconnect(void){
- ?
- close(sockfd);
- DisconnectWithHotspot(netId);
- connect_status = DISCONNECTED;
- return true;
- }
- ?
- bool TcpSend(char *data,int len){
- // printf("send start!n");
- int retval = send(sockfd, data , len, 0);
- if (retval < 0) {
- //printf("send request failed!rn");
- return false;
- }
- else{
- // printf("send OK!n");
- return true;
- }
- }
- ?
- extern char revData[30];
- bool TcpRev(void){
- int retval =0;
- retval = recv(sockfd, &revData, sizeof(revData), 0);
- if (retval <= 0) {
- // printf("rev from server failed or done, %ld!rn", retval);
- return false;
- }
- revData[retval] = '';
- return true;
- }
-
tcp_connect.h
- #ifndef __TCP_CONNECT_H
- #define __TCP_CONNECT_H
- ?
- ?
- #include
- #include
- #include
- ?
- #include "net_demo.h"
- #include "net_common.h"
- #include "net_params.h"
- #include "wifi_connecter.h"
- #include "ohos_init.h"
- #include "cmsis_os2.h"
- ?
- typedef enum{
- DISCONNECTED = 0,
- CONNECTED,
- }TCP_STATIC;
- ?
- extern TCP_STATIC connect_status;
- ?
- bool TcpConnect(void);
- bool TcpDisconnect(void);
- bool TcpSend(char *data,int len);
- bool TcpRev(void);
- ?
- #endif/*__TCP_CONNECT_H*/
新建tcptask.c 這里面這要是新建兩個(gè)任務(wù),一個(gè)是數(shù)據(jù)發(fā)送任務(wù),一個(gè)是數(shù)據(jù)發(fā)送任務(wù)。
-
數(shù)據(jù)發(fā)送任務(wù)在數(shù)據(jù)發(fā)送任務(wù)中,如果與服務(wù)端連接狀態(tài)正常,會(huì)每隔兩秒發(fā)送一次數(shù)據(jù)到服務(wù)端。這里有連接狀態(tài)檢查和連接重連機(jī)制,如果數(shù)據(jù)發(fā)送不成功,則把連接狀態(tài)看為是未連接狀態(tài)。在未連接狀態(tài),每隔兩秒會(huì)嘗試重新連接服務(wù)端,直到再一次成功連接上服務(wù)端。
-
數(shù)據(jù)接收任務(wù)為了保證能夠隨時(shí)接收到服務(wù)端發(fā)送過來的數(shù)據(jù),該任務(wù)會(huì)每10ms調(diào)度一次。在連接狀態(tài)為已連接情況下,會(huì)執(zhí)行TCP數(shù)據(jù)接收函數(shù)。
- #include
- #include
- #include
- ?
- #include "tcp_connect.h"
- #include "ohos_init.h"
- #include "cmsis_os2.h"
- ?
- char sendData[]="hellow tcp!";
- char revData[30]="";
- typedef enum{
- GET_NORMAL =0 ,
- GET_PROPRESS,
- GET_SUC,
- GET_FAIL,
- }GET_STATUS;
- ?
- extern GET_STATUS Get_Status;
- ?
- static void TcpSendTask(void *arg)
- {
- sleep(3);
- uint8_t i = 0;
- while(1){
- if(TcpConnect())
- {
- printf("Tcp Connect Sucn");
- break;
- }
- else{
- i++;
- }
- if(i>10)
- break;
- }
- if(i>10)
- printf("Tcp Connect failn");
- ?
- (void)arg;
- while(1)
- {
- if(connect_status == CONNECTED)
- {
- if(!TcpSend(sendData,sizeof(sendData)-1)){
- connect_status = DISCONNECTED;
- TcpDisconnect();
- }
- }
- else{
- if(Get_Status == GET_NORMAL){
- if(TcpConnect()){
- printf("Tcp Connect Sucn");
- }
- }
- }
- sleep(2);
- }
- }
- ?
- static void TcpSendTaskHandle(void)
- {
- osThreadAttr_t attr;
- attr.name = "TcpSendTask";
- attr.attr_bits = 0U;
- attr.cb_mem = NULL;
- attr.cb_size = 0U;
- attr.stack_mem = NULL;
- attr.stack_size = 4096;
- attr.priority = osPriorityNormal;
- if (osThreadNew(TcpSendTask, NULL, &attr) == NULL) {
- printf("[TcpSendTaskHandle] Falied to create TcpSendTask!n");
- }
- }
- APP_FEATURE_INIT(TcpSendTaskHandle);
- ?
- ?
- static void TcpRevTask(void *arg){
- (void)arg;
- while(1)
- {
- if(connect_status == CONNECTED)
- {
- if(TcpRev()){
- printf("%s",revData);
- }
- }
- usleep(10000);
- }
- }
- ?
- static void TcpRevTaskHandle(void)
- {
- osThreadAttr_t attr;
- attr.name = "TcpRevTask";
- attr.attr_bits = 0U;
- attr.cb_mem = NULL;
- attr.cb_size = 0U;
- attr.stack_mem = NULL;
- attr.stack_size = 4096;
- attr.priority = osPriorityNormal;
- if (osThreadNew(TcpRevTask, NULL, &attr) == NULL) {
- printf("[TcpRevTaskHandle] Falied to create TcpRevTask!n");
- }
- }
- APP_FEATURE_INIT(TcpRevTaskHandle);
前面也說了,在獲取時(shí)間或者天氣數(shù)據(jù)時(shí),需要進(jìn)行連接服務(wù)端的切換,確保能接收到正確的數(shù)據(jù)。在keytask.c文件進(jìn)行修改。在獲取時(shí)間和天氣函數(shù)前加上TCP服務(wù)斷開函數(shù),獲取完之后,加上TCP連接函數(shù)。
- if((voltage>0.45 && voltage<0.65)&&(!keyflag))
- {
- keyflag = true;
- if(connect_status == CONNECTED)
- TcpDisconnect();
- //OledShowString(16,7,"Sync time...",1);
- //getNtpTime();
- //OledFillScreen(0);
- switch (Now_Screen){
- case TIMESCREEN:
- //OledShowString(16,7,"Sync time...",1);
- Get_Status = GET_PROPRESS;
- if(getNtpTime()){
- Get_Status = GET_SUC;
- }
- //OledFillScreen(0);
- else
- {
- //OledShowString(0,7,"Get fail...",1);
- Get_Status = GET_FAIL;
- }
- break;
- case NOWSCREEN:
- //OledShowString(0,7,"Get Weather...",1);
- Get_Status = GET_PROPRESS;
- if(getWeather())
- //OledFillScreen(0);
- Get_Status = GET_SUC;
- else
- {
- //OledShowString(0,7,"Get fail...",1);
- Get_Status = GET_FAIL;
- }
- break;
- case TOSCREEN:
- Get_Status = GET_PROPRESS;
- if(getWeather())
- Get_Status = GET_SUC;
- else
- {
- Get_Status = GET_FAIL;
- }
- break;
- case ATOSCREEN:
- Get_Status = GET_PROPRESS;
- if(getWeather())
- Get_Status = GET_SUC;
- else
- {
- Get_Status = GET_FAIL;
- }
- break;
- ?
- default:
- break;
- }
- TcpConnect();
- }
在手機(jī)端需要安裝網(wǎng)絡(luò)調(diào)試助手,附件里有我在大學(xué)時(shí)自己做的一個(gè)APP,里面包含網(wǎng)絡(luò)調(diào)試功能。感興趣的可以自己下載安裝,就是界面很丑,有時(shí)間再進(jìn)行好好進(jìn)行優(yōu)化。
連接到服務(wù)端,該服務(wù)端與wifiiot連接的服務(wù)端IP和端口一致。

手機(jī)數(shù)據(jù)接收情況,每隔兩秒會(huì)接收到wifiiot發(fā)送過來的“hello tcp!”信息。

手機(jī)端發(fā)送123456,wifiiot成功接收到數(shù)據(jù),并通過串口打印出來。

通過公網(wǎng)的TCP中轉(zhuǎn)服務(wù)端,實(shí)現(xiàn)兩個(gè)不同網(wǎng)絡(luò)的設(shè)備之間進(jìn)行遠(yuǎn)程數(shù)據(jù)傳輸,這只是兩個(gè)設(shè)備之間進(jìn)行遠(yuǎn)程通信的一種方式?,F(xiàn)在不能設(shè)置連接wifi和服務(wù)端的IP、端口,后面有時(shí)間再慢慢進(jìn)行改進(jìn)吧。
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。
舉報(bào)投訴
-
wi-fi
+關(guān)注
關(guān)注
15文章
2424瀏覽量
129539 -
HarmonyOS
+關(guān)注
關(guān)注
80文章
2153瀏覽量
36045 -
HiSpark
+關(guān)注
關(guān)注
1文章
156瀏覽量
7757
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
熱點(diǎn)推薦
技術(shù)資訊 I Wi-Fi 模塊設(shè)計(jì)
。Wi-Fi模塊可實(shí)現(xiàn)無縫連接和數(shù)據(jù)交換,對(duì)設(shè)備進(jìn)行遠(yuǎn)程控制和監(jiān)測(cè)。Wi-Fi模塊設(shè)計(jì)旨在打造一套緊湊且高效的軟硬件解決方案,使設(shè)備能夠通過Wi-Fi網(wǎng)絡(luò)
ESP32 Wi-Fi 控制 LED 燈的原理
在智能家居、物聯(lián)網(wǎng)設(shè)備中,用手機(jī)通過Wi-Fi控制燈光、風(fēng)扇或插座,已經(jīng)非常普遍。而在嵌入式開發(fā)中,ESP32是最常用的Wi-Fi模塊之一。本文將帶你系統(tǒng)理解:ESP32是如何通過Wi-Fi實(shí)現(xiàn)
Wi-Fi:無線連接的全球通用語
一、什么是Wi-Fi?Wi-Fi是Wi-Fi聯(lián)盟制造商的商標(biāo)認(rèn)證,是基于IEEE 802.11標(biāo)準(zhǔn)的無線局域網(wǎng)技術(shù)。它允許電子設(shè)備在特定范圍內(nèi)無線接入網(wǎng)絡(luò),實(shí)現(xiàn)高速數(shù)據(jù)交換與互聯(lián)網(wǎng)訪問,已成為
發(fā)表于 01-07 09:49
Nordic發(fā)布nRF7002 EBII 開發(fā)板, 支持Wi-Fi 6, 解鎖nRF54L新玩法
了 Wi-Fi 6 功能,幫助開發(fā)人員創(chuàng)建高性能、高能效的Wi-Fi 6 物聯(lián)網(wǎng)解決方案。
基于 Nordic 的 nRF7002 Wi-Fi 協(xié)同 IC,nRF7002 EBII幫助 采用
發(fā)表于 12-10 11:58
Wi-Fi模塊選型指南 | 低功耗藍(lán)牙/Wi-Fi 6模塊推薦 | 物聯(lián)網(wǎng)設(shè)備集成攻略
物聯(lián)網(wǎng)的快速發(fā)展,Wi-Fi技術(shù)的成熟的情況下,越來越多的場(chǎng)景需要用到Wi-Fi來無線傳輸數(shù)據(jù),尤其是移動(dòng)設(shè)備中,怎么再設(shè)備中選擇合適的Wi-Fi模塊呢?下面我們來介紹下Wi-Fi模塊
淺談Wi-Fi 6E與Wi-Fi 7的關(guān)鍵器件——BAW濾波器新技術(shù)
,美國聯(lián)邦通信委員會(huì)(FCC)投票通過將6GHz頻譜劃為免許可頻段供Wi-Fi使用,這標(biāo)志著Wi-Fi正式進(jìn)入“三頻”時(shí)代——除Wi-Fi 6及前代技術(shù)使用的2.4GHz和5GHz頻段
發(fā)表于 09-19 18:29
?2118次閱讀
LitePoint Wi-Fi測(cè)試軟件減輕客戶設(shè)計(jì)負(fù)擔(dān)
自Wi-Fi 7于一年多前獲得Wi-Fi聯(lián)盟認(rèn)證以來,作為最新一代通信技術(shù),Wi-Fi正逐步成為用戶實(shí)現(xiàn)無所不在無線連接的新選擇。隨著每一代Wi-F
Texas Instruments CC335x SimpleLink?雙頻Wi-Fi? 6配套IC數(shù)據(jù)手冊(cè)
) 和Wi-Fi 5 (802.11ac)。這些CC335x是Texas Instruments的第10代連接組合芯片。因此,CC335x基于成熟的技術(shù)設(shè)計(jì)而成。這些器件非常適合配備運(yùn)行TCP/IP的Linux或
Wi-Fi FEM價(jià)格戰(zhàn),真的不可避免嗎?
,康希通信是頭部公司;手機(jī)Wi-Fi FEM,唯捷創(chuàng)芯是頭部公司;IoT FEM,三伍微是頭部公司。三伍微為什么選擇I
Wi-Fi 8:開啟極高可靠性 (UHR) 連接的新紀(jì)元——1
。2021年,Wi-Fi 6E 橫空出世,憑借6GHz 頻帶的獨(dú)特優(yōu)勢(shì),使Wi-Fi 正式邁入真三頻 (Real Tri-Band) 共存的通信技術(shù)時(shí)代。2024年,科學(xué)家們?cè)俅螒{借著4096QAM
發(fā)表于 06-13 11:09
?迅通PTR7002 Wi-Fi 6模塊技術(shù)解析
驅(qū)動(dòng)庫?及AT指令集,支持通過SPI或UART與主控芯片通信。開發(fā)者可通過配套的?SDK 2.1.4版本?直接調(diào)用Wi-Fi 6的OFDMA和TWT(目標(biāo)喚醒時(shí)間)功能,實(shí)現(xiàn)多設(shè)備低延時(shí)調(diào)度。
根據(jù)
發(fā)表于 06-10 10:38
基于 Wi-Fi 的定位服務(wù)
以下捕獲使用 location_wifi_get 函數(shù)請(qǐng)求 Wi-Fi 定位服務(wù)。該事件的總功耗為 125.85mC,日志顯示精確度為 30.0m。
Got location:
method
發(fā)表于 04-17 15:16
nRF Cloud Wi-Fi 定位服務(wù)
、Predictive-GPS、Single-Cell、Multi-Cell 和 Wi-Fi 定位。通過利用 nRF Cloud 的優(yōu)化定位算法,基于 Nordic SoC 和 模組的產(chǎn)品可在定位用例
發(fā)表于 04-17 15:07
Wi-Fi 定位服務(wù)
Wi-Fi 是一種著名的無線網(wǎng)絡(luò)技術(shù),用于設(shè)備的局域網(wǎng)和互聯(lián)網(wǎng)接入。Wi-Fi 通過 Wi-Fi 網(wǎng)絡(luò)為家庭、辦公室和學(xué)校等環(huán)境提供便捷的無線互聯(lián)網(wǎng)接入服務(wù)。
Wi-Fi 定位是一種
發(fā)表于 04-17 15:01
【HarmonyOS HiSpark Wi-Fi IoT 套件試用連載】九:遠(yuǎn)程TCP通信
評(píng)論