单片机设计系列1——ESP32网页控制

开坑说明()

从2502起,我将持续更新单片机设计系列,旨在分享简单的单片机设计思路和设计代码。至于单片机的型号,根据本人学习顺序而定,包括但不限于STC51系列、STM32系列、ESP系列等。


目录

开坑说明()

设计简介

开发准备

程序设计


设计简介

本文设计了一个
基于
ESP32
的智能控制系统的设计与实现。基础功能如下:

  1. 基本的ADC功能,检测引脚34的电压值;
  2. 当输入的模拟值 AD 转换后超过设定值(自定义),启动蜂鸣器报警, LED2 闪烁;
  3. 定时将 LED1、LED2 状态、蜂鸣器状态、峰峰值检测结果等(间隔5-10 秒)上传网页并显示;
  4. 在网页上控制 LED1、LED2、蜂鸣器状态。

网页状态显示与控制、实物图


开发准备

  1. 安装Arduino IDE

  2. 访问Arduino官网(Arduino – Home),下载并安装最新版本的Arduino IDE。

  3. 添加ESP32开发板支持

  4. 打开Arduino IDE,进入“文件”->“首选项”。

  5. 在“附加开发板管理器URL”中添加以下链接:

    https://dl.espressif.com/dl/package_esp32_index.json

  6. 打开“工具”->“开发板”->“开发板管理器”,搜索“ESP32”,并安装。

  7. 选择开发板

  8. 安装完成后,在“工具”->“开发板”中选择对应的ESP32开发板

  9. 根据实际连接的端口,选择对应的串行端口(在“工具”->“端口”中)。

  10. 硬件材料准备:USB Type-C
    数据线
    1
    根、面包板
    1
    块、公对公(公对母)杜邦线若干。

但是这里注意一下,由于Arduino开发板源的问题,通常会卡在下载ESP32开发板支持这一步,此时可以使用我上传的资源,一键安装开发板支持的程序。

不熟悉Arduino开发环境的朋友们可以先复刻简单的GPIO实验。简单实验的详细操作可以参考这个ESP开发网址:

ESP32 单片机 | 极客侠GeeksMan

ESP32引脚学习图

程序设计

1.建立WIFI连接

下面是一段简单的ESP32WIFI使用代码,以下代码实现了一个简单的Wi-Fi连接并打印设备的IP地址:

#include <WiFi.h>

const char* ssid = "your_SSID";
const char* password = "your_PASSWORD";

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  // 在这里添加代码
}

准备好代码之后,点击“上传”按钮(或按快捷键Ctrl+U),Arduino IDE会自动编译代码并将其上传到ESP32开发板。

2.程序库的选用

Web 控制界面的功能

  1. 可以通过网页按键控制 LED1、LED2 和蜂鸣器的开关。
  2. 可以通过网页按键切换到“检测模式”,在检测模式下,如果 ADC 采集到的电压值超过设定阈值(3.0V),LED2 和蜂鸣器会快速闪烁和报警,持续 2 秒后自动停止。
  3. 实时显示 ADC 测量的电压值。

  为了实现web控制界面,我选用 ESPAsyncWebServer 库来创建一个 Web 服务器,通过网页界面可以远程控制 ESP32 上的 LED、蜂鸣器,并读取 ADC 采集到的电压值。ADC的功能无需再引用其他程序库来实现。

3.Web 服务器设置

创建一个异步 Web 服务器 AsyncWebServer server(80)

定义多个 HTTP 请求的处理函数:

/:返回一个 HTML 页面,包含控制界面和实时数据显示。

/voltage:返回当前测量的电压值。

/state:返回设备状态的 JSON 数据。

/led1/led2/buzzer/detection:分别控制 LED、蜂鸣器和检测模式的开关状态。

在设计Web服务器时需要用到一些网页设计的知识,如HTTP,可以简单的学习一下,或者利用AI工具来完成网页设计。

4.其他硬件功能

// WiFi 配置
const char* ssid = "WiFi SSID"
const char* password = "PASSWORD"; 

// ADC 配置
const int adcPin = 34;   // ADC 引脚(GPIO34 是 ADC1 通道6)
const float voltageRef = 3.3; // ESP32 的 ADC 参考电压(3.3V)
const int adcResolution = 4095; // ADC 分辨率(12 位,值范围为 0-4095)

// LED 和蜂鸣器引脚
const int led1Pin = 25;     // GPIO2 接 LED1
const int led2Pin = 33;    // GPIO33 接 LED2
const int buzzerPin = 26;  // GPIO15 接蜂鸣器

注意,ESP32的ADC电压输入标准值是1V,在这里我们使用了衰减,将输入范围扩大到3.3V。

5.变量设计

// 状态变量
bool led1State = false;    // LED1 状态
bool led2State = false;    // LED2 状态
bool buzzerState = false;  // 蜂鸣器状态
bool detectionMode = false; // 检测模式状态

// 定时器变量
unsigned long blinkStartTime = 0;
unsigned long alarmStartTime = 0;
bool isAlarmActive = false; // 标记当前是否在报警过程中
bool ledBlinkState = false;

6.基本函数

// 读取电压值并转换为字符串
String getVoltage() {
  int adcValue = analogRead(adcPin); // 读取 ADC 值
  float voltage = (adcValue * voltageRef) / adcResolution; // 转换为电压
  return String(voltage, 2); // 返回字符串,保留两位小数
}

// 获取设备状态
String getDeviceState() {
  String state = "{";
  state += "\"led1\":\"" + String(led1State ? "ON" : "OFF") + "\",";
  state += "\"led2\":\"" + String(led2State ? "ON" : "OFF") + "\",";
  state += "\"buzzer\":\"" + String(buzzerState ? "ON" : "OFF") + "\",";
  state += "\"detectionMode\":\"" + String(detectionMode ? "ON" : "OFF") + "\"";
  state += "}";
  return state;
}

7.程序初始化

void setup() {
  // 初始化串口
  Serial.begin(115200);

  // 初始化 WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  Serial.println("Connected to WiFi");
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

  // 配置 ADC 和控制引脚
  pinMode(adcPin, INPUT);
  pinMode(led1Pin, OUTPUT);
  pinMode(led2Pin, OUTPUT);
  pinMode(buzzerPin, OUTPUT);

  // 确保初始状态关闭
  digitalWrite(led1Pin, LOW);
  digitalWrite(led2Pin, LOW);
  digitalWrite(buzzerPin, LOW);

  // 设置 Web 页面响应
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", R"rawliteral(
      <!DOCTYPE html>
      <html>
      <head>
        <title>ESP32 Control</title>
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style>
          body { font-family: Arial, sans-serif; text-align: center; margin: 0; padding: 0; }
          .container { padding: 20px; }
          .button { padding: 15px 25px; font-size: 16px; margin: 10px; cursor: pointer; border: none; }
          .button-led { background-color: #4CAF50; color: white; }
          .button-buzzer { background-color: #FF5722; color: white; }
          .button-detect { background-color: #03A9F4; color: white; }
        </style>
      </head>
      <body>
        <div class="container">
          <h1>ESP32 Control</h1>
          <p>Voltage: <span id="voltage">0.00</span> V</p>
          <p>LED1 State: <span id="led1">OFF</span></p>
          <p>LED2 State: <span id="led2">OFF</span></p>
          <p>Buzzer State: <span id="buzzer">OFF</span></p>
          <p>Detection Mode: <span id="detectionMode">OFF</span></p>
          <button class="button button-led" onclick="toggleLED1()">Toggle LED1</button>
          <button class="button button-led" onclick="toggleLED2()">Toggle LED2</button>
          <button class="button button-buzzer" onclick="toggleBuzzer()">Toggle Buzzer</button>
          <button class="button button-detect" onclick="toggleDetection()">Toggle Detection Mode</button>
        </div>
        <script>
          function updateVoltage() {
            fetch('/voltage')
              .then(response => response.text())
              .then(data => {
                document.getElementById('voltage').innerText = data;
              });
          }

          function updateState() {
            fetch('/state')
              .then(response => response.json())
              .then(data => {
                document.getElementById('led1').innerText = data.led1;
                document.getElementById('led2').innerText = data.led2;
                document.getElementById('buzzer').innerText = data.buzzer;
                document.getElementById('detectionMode').innerText = data.detectionMode;
              });
          }

          function toggleLED1() {
            fetch('/led1');
          }

          function toggleLED2() {
            fetch('/led2');
          }

          function toggleBuzzer() {
            fetch('/buzzer');
          }

          function toggleDetection() {
            fetch('/detection');
          }

          // 每 1 秒更新一次电压值和设备状态
          setInterval(updateVoltage, 1000);
          setInterval(updateState, 1000);
        </script>
      </body>
      </html>
    )rawliteral");
  });

  // 提供实时电压值
  server.on("/voltage", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/plain", getVoltage());
  });

  // 提供设备状态
  server.on("/state", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "application/json", getDeviceState());
  });

  // 控制 LED1
  server.on("/led1", HTTP_GET, [](AsyncWebServerRequest *request){
    if (!detectionMode) {
      led1State = !led1State;
      digitalWrite(led1Pin, led1State ? HIGH : LOW);
    }
    request->send(200, "text/plain", led1State ? "LED1 ON" : "LED1 OFF");
  });

  // 控制 LED2
  server.on("/led2", HTTP_GET, [](AsyncWebServerRequest *request){
    if (!detectionMode) {
      led2State = !led2State;
      digitalWrite(led2Pin, led2State ? HIGH : LOW);
    }
    request->send(200, "text/plain", led2State ? "LED2 ON" : "LED2 OFF");
  });

  // 控制蜂鸣器
  server.on("/buzzer", HTTP_GET, [](AsyncWebServerRequest *request){
    if (!detectionMode) {
      buzzerState = !buzzerState;
      digitalWrite(buzzerPin, buzzerState ? HIGH : LOW);
    }
    request->send(200, "text/plain", buzzerState ? "Buzzer ON" : "Buzzer OFF");
  });

  // 控制检测模式
  server.on("/detection", HTTP_GET, [](AsyncWebServerRequest *request){
    detectionMode = !detectionMode;
    if (!detectionMode) {
      digitalWrite(led1Pin, LOW);
      digitalWrite(led2Pin, LOW);
      digitalWrite(buzzerPin, LOW);
    }
    request->send(200, "text/plain", detectionMode ? "Detection Mode ON" : "Detection Mode OFF");
  });

  // 启动服务器
  server.begin();
}

8.循环主体

void loop() {
  if (detectionMode) {
    float voltage = getVoltage().toFloat();
    if (!isAlarmActive && voltage > 3.0) {
      // 启动报警逻辑
      isAlarmActive = true;
      blinkStartTime = millis();
      alarmStartTime = millis();
    }

    if (isAlarmActive) {
      unsigned long currentTime = millis();

      // 快速闪烁 LED 和蜂鸣器报警
      if (currentTime -
 blinkStartTime >= 100) {
        ledBlinkState = !ledBlinkState;
        digitalWrite(led2Pin, ledBlinkState ? HIGH : LOW);
        blinkStartTime = currentTime;
      }
      digitalWrite(buzzerPin, HIGH); // 蜂鸣器保持报警

      // 2 秒后停止报警
      if (currentTime - alarmStartTime >= 2000) {
        isAlarmActive = false;
        digitalWrite(led2Pin, LOW);
        digitalWrite(buzzerPin, LOW);
      }
    }
  }
}

至此,所有硬件调用以及网页服务器的代码已经全部封装完毕,已经完成了以上所有功能。

实物展示


总结与其他

本项目完整的控制代码以及引脚映射文件已上传。

Arduino IDE的ESP32环境一键配置程序:通过网盘分享的文件:esp32_package_2.0.9_arduinome.exe
链接: https://pan.baidu.com/s/1wrxjHK3tRpKS8Ud67nm1OQ 提取码: FZDX 

作者:南檐巷上学

物联沃分享整理
物联沃-IOTWORD物联网 » 单片机设计系列1——ESP32网页控制

发表回复