首页 > 其他分享 >WIFI连接与通信

WIFI连接与通信

时间:2025-01-19 17:10:50浏览次数:1  
标签:WiFi WIFI 通信 Wi char Fi Serial 连接

'' 不要等待运气降临, 应该去努力掌握知识 ''  ——  弗莱明

ESP32-S3 支持 2.4 GHz 的 Wi-Fi 4(802.11n)标准,提供高达 150 Mbps 的数据传输速率。它支持 STA(Station)模式、AP(Access Point)模式和 Wi-Fi 直连(Wi-Fi Direct)模式,可以灵活地连接到其他设备或创建自身的网络。ESP32-S3 还支持硬件加速的 Wi-Fi 加密算法,包括 WPA/WPA2-PSK 和 WPA3-SAE 加密。这使得加密和解密数据的速度更快,提高了系统的整体性能和安全性。

Wi-Fi 库支持配置及监控 ESP32 Wi-Fi 连网功能。

它有三种模式:

  • 基站模式(即 STA 模式或 Wi-Fi 客户端模式),此时 ESP32 连接到接入点 (AP)。
  • AP 模式(即 Soft-AP 模式或接入点模式),此时基站连接到 ESP32。
  • AP-STA 共存模式(ESP32 既是接入点,同时又作为基站连接到另外一个接入点)。

常用API介绍

下面是一些 ESP32S3 Arduino 库中常用的 Wi-Fi 相关函数的介绍:

  • WiFi.begin(ssid, password)
    

​ 该函数用于连接到已经存在的Wi-Fi 网络。需要提供要连接的网络的 SSID 和密码作为参数

  • WiFi.disconnect()
    

    ​ 该函数用于断开当前的 Wi-Fi 连接。

  • WiFi.status()
    

    ​ 该函数返回当前 Wi-Fi 连接的状态。返回值可能是以下之一: WL_CONNECTED:已连接到 Wi-Fi 网络。 WL_DISCONNECTED:未连接到 Wi-Fi 网络。 WL_IDLE_STATUS:Wi-Fi 处于空闲状态。 WL_NO_SSID_AVAIL:未找到指定的 Wi-Fi 网络。

  • WiFi.localIP()
    

    ​ 该函数返回 ESP32S3 设备在 Wi-Fi 网络中分配的本地 IP 地址

  • WiFi.macAddress()
    

    ​ 该函数返回 ESP32S3 设备的 MAC 地址

  • WiFi.scanNetworks()
    

    ​ 该函数用于扫描周围可用的 Wi-Fi 网络。它返回一个整数,表示扫描到的网络数量。可以使用其他函数(如WiFi.SSID() 和 WiFi.RSSI())来获取每个网络的详细信息。

  • WiFi.SSID(networkIndex)
    

    ​ 该函数返回指定索引的扫描到的 Wi-Fi 网络的 SSID。

  • WiFi.RSSI(networkIndex)
    

    ​ 该函数返回指定索引的扫描到的 Wi-Fi 网络的信号强度(RSSI)。

STA模式

STA 模式下,ESP32-S3会建立 Wi-Fi 连接,连接到一个已经建立好的 Wi-Fi 热点上,通过该热点来访问互联网。STA 模式使用的场景比较多,比如在智能家居、物联网设备以及工业控制等领域中,设备需要通过 Wi-Fi 连接到网络来传递数据。
示例:连接外部WIF,当连接成功时,通过Serial串口输出IP地址

#include <WiFi.h>
#define LED 48

// 定义 要连接的 Wi-Fi 名与密码
const char* ssid = "LEDC"; // 这是我手机热点
const char* password = "12345678"; // 热点的密码

void setup() {
    Serial.begin(115200);//串口调试
    // 先断开之前的连接
    WiFi.disconnect(true);
    // 连接 Wi-Fi
    WiFi.begin(ssid, password);
    Serial.print("正在连接 Wi-Fi");
    // 检测是否链接成功
    while (WiFi.status() != WL_CONNECTED) {
          delay(500);
          Serial.print(".");
    }
    Serial.println("连接成功");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
}

void loop() {
	delay(1000);
}

在 C 和 C++ 编程语言中,const char* 是一种常见的类型声明,以下是对其各个部分的详细阐释:

  • const关键字
    • const是一个修饰符,它限定了该声明的某种属性。当它出现在 const char* 这样的组合中时,其主要作用是保护指针所指向的数据。这意味着,一旦你使用 const char* 声明了一个指针,你就不能通过这个指针去修改其所指向的数据。它就像一个保护罩,确保数据在使用这个指针操作时不会被意外地篡改,从而增强了程序的安全性和可靠性。
  • char类型关键字
    • char 是 C 和 C++ 中用于表示字符的数据类型。字符可以是单个的英文字母、数字、标点符号或者其他字符,并且在存储和处理文本数据时,我们通常会使用 char 类型。例如,存储字符 'a' 或者 '1' 时,会使用 char 类型。
  • * 指针声明符
    • * 这个符号在 C 和 C++ 中是专门用来声明指针的。当它和 char 组合在一起时,就表示我们要声明的是一个指针,而且这个指针指向的数据类型是 char。简单来说,这个指针将存储一个内存地址,而该内存地址所存储的是 char 类型的数据。

​ 当我们把 constchar* 组合在一起形成 const char* 时,它的完整含义是:我们正在声明一个指针,这个指针指向的是 char 类型的数据,并且这些数据是不可修改的常量。

我们可以通过以下代码示例来进一步理解:

const char *str = "Hello, world!";

​ 在这个例子中,我们声明了一个名为 str 的变量,它的类型是 const char*str 指向了一个存储在内存中的字符串 "Hello, world!"。这里的 const 关键字保证了我们不能通过 str 指针去修改 "Hello, world!" 这个字符串的内容。例如,以下操作是不允许的:

str[0] = 'h'; // 错误:尝试修改 const 指针指向的数据

​ 因为 strconst char* 类型,通过它修改所指向的数据是不合法的,编译器会报错,以防止我们不小心修改了不应该修改的数据。

​ 总之,使用 const char* 可以有效地防止在程序中意外修改常量字符串,提高代码的健壮性和可维护性,同时也明确了该指针的操作范围和限制,使代码的意图更加清晰,让其他开发者一看便知,这个指针只能用来读取数据,而不能用于修改数据。

​ 这样的声明在处理字符串常量、函数参数传递(当不希望函数修改字符串内容时)以及许多其他场景中都非常有用,因为它清晰地表明了指针所指向的数据是只读的,避免了潜在的数据修改错误。

AP模式

接入点(AP)是一种提供 Wi-Fi 网络访问的设备,并将其连接到有线网络的装置。ESP32S3除了不具有与有线网络的接口外,还可以提供类似的功能。这种操作模式称为软接入点(soft-AP)。可以同时连接到soft-AP的最大站数可以设置4,默认为4。

当ESP32S3单独处于AP模式下时,可以被认为是一个无法访问外网的局域网WiFi路由器节点,它可以接受各类设备的连接请求。并可以和连接设备进行TCP、UDP连接,实现数据流。在局域物联网的设计中可以承担数据收发节点的作用。

Q:可以简单理解为一个不能上网的热点?
A:这种理解基本正确。ESP32S3 在 AP 模式下可以被视为一个热点,其他设备可以搜索并连接到这个热点,但这个热点不会像家庭 Wi-Fi 路由器那样可以将设备连接到互联网,而只是创建了一个本地的无线网络环境,供连接的设备之间进行通信。

示例:当ESP32S3 在 AP 模式下运行时,它将创建一个名为“ESP32S3”的无线网络,并分配一个 IP 地址。其他设备可以搜索并连接到这个热点,但无法通过这个热点上网。

#include <WiFi.h>

// 设置要创建的热点名与密码
const char* ssid = "ESP32S3";
const char* password = "12345678";

void setup()
{
    Serial.begin(115200);
    // 创建热点
    WiFi.softAP(ssid, password);
    // 打印热点 IP
    Serial.print("Wi-Fi 接入的 IP:");
    Serial.println(WiFi.softAPIP());
}

void loop()
{
    delay(500);
}

到此,你应该已经知道如何使用STA 和 AP 模式了,但是,我们使用WIFI最主要的目的是数据的传输,所以接下来我会介绍如何使用WIFI进行数据传输。

TCP与UDP协议

请先确保WIFI已经连接,接下来的代码将以STA模式为例子

TCP(Transmission Control Protocol)

  • 连接性
    • TCP 是一种面向连接的协议。在进行数据传输之前,发送方和接收方需要通过三次握手建立一个可靠的连接。这个过程确保双方都准备好进行数据传输,并且在传输结束后,会通过四次挥手来关闭连接。
    • 三次握手的过程如下:
      1. 客户端发送一个 SYN(同步)数据包给服务器,表示客户端想要建立连接。
      2. 服务器收到 SYN 后,回复一个 SYN-ACK(同步 - 确认)数据包给客户端,表示服务器已经收到请求,并同意建立连接。
      3. 客户端收到 SYN-ACK 后,发送一个 ACK(确认)数据包给服务器,至此连接建立成功。
  • 可靠性
    • TCP 提供高度可靠的数据传输服务。它使用序列号和确认应答机制,确保数据按序、完整地到达接收方。
    • 发送方会将数据分割成多个数据包,并为每个数据包分配一个序列号。接收方收到数据包后,会向发送方发送确认应答(ACK),告知发送方已收到哪些数据包。
    • 如果发送方在一定时间内没有收到确认应答,它会认为数据包丢失或损坏,将重新发送该数据包。
    • TCP 还采用流量控制和拥塞控制机制,以防止发送方发送过多的数据,避免网络拥塞或接收方缓冲区溢出。
  • 数据传输顺序
    • 由于使用序列号,接收方可以将接收到的数据包按照正确的顺序重新组装,保证了数据的顺序性,即使数据包在网络中经过不同的路径传输,最终也能以正确的顺序到达接收方。
  • 头部开销
    • TCP 的头部通常为 20 字节,包含序列号、确认应答号、窗口大小、数据偏移量、标志位等信息,这些信息用于保证数据的可靠性和进行流量控制。
  • 应用场景
    • 适用于对数据可靠性和完整性要求较高的应用,例如文件传输(FTP、HTTP)、电子邮件(SMTP、POP3)、远程登录(SSH、Telnet)等。这些应用不容许数据丢失或乱序,需要确保数据准确无误地到达目的地。

UDP(User Datagram Protocol)

  • 连接性
    • UDP 是一种无连接的协议。发送方在发送数据前不需要与接收方建立连接,只需要知道接收方的 IP 地址和端口号,就可以直接发送数据。
    • 因此,使用 UDP 发送数据的速度更快,但没有像 TCP 那样的连接建立和关闭过程,也就减少了额外的开销和延迟。
  • 可靠性
    • UDP 不提供可靠性保证。如果数据在传输过程中丢失、损坏或乱序,UDP 不会进行重传,接收方也不会得到通知。
    • 对于一些对实时性要求高、能够容忍一定程度的数据丢失的应用,这种特性可以换取更快的传输速度和更低的延迟。
  • 数据传输顺序
    • UDP 不保证数据的顺序性。由于没有序列号和确认应答机制,数据包可能会乱序到达接收方,接收方接收到的数据包顺序可能与发送方发送的顺序不同。
  • 头部开销
    • UDP 的头部相对简洁,只有 8 字节,包含源端口、目的端口、长度和校验和等信息,传输效率相对较高。
  • 应用场景
    • 适用于对实时性要求高的应用,如实时视频会议(Skype、Zoom 等)、在线游戏、流媒体(实时视频流、音频流)等。这些应用更注重数据的实时传输,少量的数据丢失不会对整体体验产生严重影响,但对延迟非常敏感,需要尽快将数据发送出去。

总结

  • TCP 以可靠性为核心,通过复杂的连接管理和确认机制保证数据的准确传输,适用于可靠性优先的场景;而 UDP 以速度和低延迟为优势,适合对实时性要求高、对数据丢失有一定容忍度的场景。在选择使用 TCP 还是 UDP 时,需要根据具体的应用需求和网络环境来决定。例如,在物联网设备中,如果需要可靠的数据采集和控制,可能会选择 TCP;而对于实时的传感器数据传输,为了减少延迟,可能会使用 UDP。

TCP例程

首先将两块ESP32一个作为服务器端,一个作为客户端。

先讲服务器端的代码

// 这个是一个简单的服务端,用于接收客户端发送的字符串,并回复一个固定的字符串
#include <WiFi.h>
#include <WiFiClient.h>// 引入 WiFiClient 类
#include <WiFiServer.h>// 引入 WiFiServer 类,服务器端必须有

// 定义 Wi-Fi 网络的 SSID 和密码
const char *ssid = "LEDC";
const char *password = "12344567";
// 定义服务器监听的端口号
const int serverPort = 6700;
WiFiServer server(serverPort);// 创建服务器对象
WiFiClient client; // 创建客户端对象

void setup()
{
    // 连接到 Wi-Fi 网络
    WiFi.disconnect(true); // 先断开之前的 Wi-Fi 连接
    WiFi.begin(ssid, password); // 连接到 我的手机热点 
    delay(1000);
    while (WiFi.status() != WL_CONNECTED)
    {
        delay(1000);
        Serial.println("Connecting to WiFi...");
    }
    Serial.println("Connectedヾ(≧▽≦*)o");
    // 启动服务器
    server.begin();
    Serial.println("Server started");
    Serial.print("IP Address: ");
    Serial.println(WiFi.localIP());// 获取手机热点分配给ESP32的IP地址并打印到串口
    delay(2000);
}

void loop()
{
    // 检查是否有新的客户端连接
    client = server.available();
    if (client)
    {
        Serial.println("Client connected");
        while (client.connected())
        {
            if (client.available())
            {
                // 读取客户端发送的字符串,一直读取直到遇到换行符
                String receivedString = client.readStringUntil('\n');
                Serial.println("Rec from client: " + receivedString);
                // 发送响应字符串
                client.println("Message received by Server");
            }
        }
        Serial.println("Client disconnected");
        client.stop();
    }
}

接下来是是客户端的代码

#include <WiFi.h>
#include <WiFiClient.h>
//客户端就不需要WiFiServer库了

// 定义 Wi-Fi 网络的 SSID 和密码
const char* ssid = "";
const char* password = "";
// 定义服务器的 IP 地址和端口号
const char* serverIP = "这个需要先看看服务器端串口调输出的IP地址是多少"; 
const int serverPort = 6700; //双方通信,监听的端口号要相同

WiFiClient client;

void setup() {
  Serial.begin(115200);
  delay(1000);

  // 连接到 Wi-Fi 网络
  WiFi.begin(ssid, password);
  while (WiFi.status()!= WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  Serial.println("Connectedヾ(≧▽≦*)o");

  // 尝试连接到服务器
  if (!client.connect(serverIP, serverPort)) {
    Serial.println("Connection to server failed");
    return;
  }
  Serial.println("Connected to server");
}

void loop() {
  if (client.connected()) {
    // 发送字符串
    client.println("Elaina is fine, very fine.");
    Serial.println("String sent: Elaina is fine, very fine.");
    // 检查是否有服务器的响应
    if (client.available()) {
      String response = client.readStringUntil('\n');
      Serial.println("Received from server: " + response);
    }
  } else {
    Serial.println("Not connected to server");
  }
  // 可以根据需要调整发送间隔
  delay(3000); 
}

标签:WiFi,WIFI,通信,Wi,char,Fi,Serial,连接
From: https://www.cnblogs.com/ouyanglingle/p/18679721

相关文章

  • 树莓派串口通信开发记录
    树莓派开发记录:开发系统及代码编辑软件安装1.通过安装软件RasperryPiImager实现系统镜像流程化烧写进SD卡2.在VScode官网选择相对应的基于树莓派ARM64或32架构的版本,下载相应的deb文件:sudodpkg-iDesktop/code_1.60.2-1632316275_armhf.deb(替换为自己的路径)3.在命......
  • 前端必知必会-Node.js连接MongoDB 创建集合
    文章目录Node.js连接MongoDB创建集合创建集合总结Node.js连接MongoDB创建集合MongoDB中的集合与MySQL中的表相同创建集合要在MongoDB中创建集合,请使用createCollection()方法:示例获取您自己的Node.js服务器创建一个名为“customers”的集合:varMon......
  • 前端必知必会-Node.js连接MongoDB 删除集合
    文章目录Node.js连接MongoDB删除集合删除集合db.dropCollection总结Node.js连接MongoDB删除集合删除集合您可以使用drop()方法删除表或MongoDB中所谓的集合。drop()方法采用包含错误对象和结果参数的回调函数,如果成功删除集合,则返回true,否则返回false。......
  • (原创)[开源][.Net Standard 2.0] SimpleMMF (进程间通信框架)更新 v1.1,极低CPU占用
    一、前言在上一篇(原创)[.Net]进程间通信框架(基于共享内存)——SimpleMMF中,发布了v1.0版,最大的问题是:CPU占用较高,至少40-50%。这既与我的开发水平有关,也与SimpleMMF诞生环境有关,这个主要是用在数字孪生各软件之间同步数据,而部署软件的工作站性能都强悍,像我常用的便是一个有着19......
  • Mysql--实战篇--连接池(连接池原理,HikariCP、C3P0、Druid和DBCP等)
    连接池(ConnectionPool)是数据库应用程序中的一种优化技术,用于管理和复用数据库连接。通过连接池,应用程序可以避免频繁创建和销毁数据库连接的开销,从而提高性能和资源利用率。在Java应用程序中,常用的MySQL连接池实现包括HikariCP、C3P0、Druid和DBCP等。1、连接池的工作原理......
  • 【Linux探索学习】第二十六弹——进程通信:深入理解Linux中的进程通信
    Linux探索学习:https://blog.csdn.net/2301_80220607/category_12805278.html?spm=1001.2014.3001.5482前言:在Linux操作系统中,进程通信(IPC)是操作系统的一项核心功能,用于在不同进程之间交换数据或信号。这种能力在多任务操作系统中尤为重要,因为进程之间通常需要协作完成复杂......
  • 低功耗蓝牙BLE连接建立的过程分析
    文章目录概要CoreSpec描叙要点空口包抓包分享小结概要本文章主要根据《BLUETOOTHCORESPECIFICATIONVersion5.2》规范描叙来分析BLE连接建立的过程;分享抓取的空口包(Airpackage)来进一步分析。CoreSpec描叙要点空口包抓包分享小结仅供参考,谢谢......
  • 操作系统进程-进程间通信的概述、匿名管道pipe和有名管道mkfifo函数的介绍及应用
    进程间通信(IPC)概述进程间通信(InterProcessCommunication)是指在两个或多个不同的进程间传递或者交换信息。进程是一个独立的资源管理单元,不同的进程之间资源是独立的,不能在一个进程中直接访问另一个进程的资源,但是进程间不是孤立的,也需要一些信息的交互和状态传递,所以就......
  • 由单个神经元到神经网络,简单全连接神经网络工作解析(李哥 lesson1)
    一.由单个神经元到神经网络:    在上个文章我们知道了单个神经元的具体架构,这次我们将从单个神经元出发,探寻简单全连接神经网络的工作过程。    单个神经元其实就是一个函数,现在我们假设单个神经元的结构都为线性结构(即=wx+b)如图:    多个神经元相互......
  • (2): MATLAB连接EPICS
    发现有个工具MATPVA,可以结合python的P4P库在MATLAB里读PV,就是需要python过一道手发现Spyder可以使用我自己装的python解释器(python312),换了之后要下控制台相关的库,下之安装P4P库在Spyder中读PV,可读试图在MATLAB采用MATPVA代码,结果要先指定MATLAB采用的python解释器,指定后,说不......