单片机设计系列1——ESP32网页控制
开坑说明()
从2502起,我将持续更新单片机设计系列,旨在分享简单的单片机设计思路和设计代码。至于单片机的型号,根据本人学习顺序而定,包括但不限于STC51系列、STM32系列、ESP系列等。
目录
开坑说明()
设计简介
开发准备
程序设计
设计简介
本文设计了一个
基于
ESP32
的智能控制系统的设计与实现。基础功能如下:
- 基本的ADC功能,检测引脚34的电压值;
- 当输入的模拟值 AD 转换后超过设定值(自定义),启动蜂鸣器报警, LED2 闪烁;
- 定时将 LED1、LED2 状态、蜂鸣器状态、峰峰值检测结果等(间隔5-10 秒)上传网页并显示;
- 在网页上控制 LED1、LED2、蜂鸣器状态。
网页状态显示与控制、实物图
开发准备
-
安装Arduino IDE
-
访问Arduino官网(Arduino – Home),下载并安装最新版本的Arduino IDE。
-
添加ESP32开发板支持
-
打开Arduino IDE,进入“文件”->“首选项”。
-
在“附加开发板管理器URL”中添加以下链接:
https://dl.espressif.com/dl/package_esp32_index.json
-
打开“工具”->“开发板”->“开发板管理器”,搜索“ESP32”,并安装。
-
选择开发板
-
安装完成后,在“工具”->“开发板”中选择对应的ESP32开发板
-
根据实际连接的端口,选择对应的串行端口(在“工具”->“端口”中)。
-
硬件材料准备: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 控制界面的功能:
- 可以通过网页按键控制 LED1、LED2 和蜂鸣器的开关。
- 可以通过网页按键切换到“检测模式”,在检测模式下,如果 ADC 采集到的电压值超过设定阈值(3.0V),LED2 和蜂鸣器会快速闪烁和报警,持续 2 秒后自动停止。
- 实时显示 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
作者:南檐巷上学