项目描述:
本项目采用485采集温湿度以及电压电流等,485模块分别为下图,串口转485模块采用自动收发模块,ESP32工作在AP热点模式,通过手机连接esp32的热点来和esp进行数据通讯,
使用esp32作为HTTP服务器
缺陷:
项目的最终HTML页面
代码
可发给AI让其写注释
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_mac.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include <string.h>
#include "lwip/err.h"
#include "lwip/sys.h"
#include <esp_http_server.h>
#include <stdio.h>
#include <string.h>
#include "freertos/queue.h"
#include "driver/uart.h"
#include "driver/gpio.h"
#include "cJSON.h"
#include <time.h>
/* 配置参数 */
#define EXAMPLE_ESP_WIFI_SSID "laotie666"
#define EXAMPLE_ESP_WIFI_PASS "12345678"
#define EXAMPLE_ESP_WIFI_CHANNEL 1
#define EXAMPLE_MAX_STA_CONN 4
#define EXAMPLE_HTTP_QUERY_KEY_MAX_LEN (64)
#define EX_UART_NUM UART_NUM_1
#define BUF_SIZE (1024)
#define RD_BUF_SIZE (BUF_SIZE)
/* 全局变量 */
uint8_t get_jsy_value[8] = {0x02, 0x03, 0x00, 0x48, 0x00, 0x05, 0x05, 0xEC};
uint8_t get_val[8] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x02, 0xC4, 0x0B};
uint16_t Hum = 255; // 湿度值 Hum = 实际值 * 10
int16_t Tem = 232; // 温度值 Tem = 实际值 * 10
uint16_t Voltage=24, Current=2;
float Power=2.3; // 功率
static QueueHandle_t uart0_queue;
static const char *TAG = "wifi softAP";
/* 美观的HTML页面模板 */
static const char *HTML_PAGE = R"rawliteral(
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ESP32 环境监测</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
.container {
background: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(10px);
border-radius: 20px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
width: 100%;
max-width: 500px;
padding: 30px;
color: white;
}
header {
text-align: center;
margin-bottom: 30px;
}
h1 {
font-size: 28px;
margin-bottom: 10px;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.status {
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
font-size: 16px;
}
.status-indicator {
width: 12px;
height: 12px;
border-radius: 50%;
background-color: #4CAF50;
box-shadow: 0 0 10px #4CAF50;
}
.sensors-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
margin-bottom: 30px;
}
.sensor-card {
background: rgba(255, 255, 255, 0.1);
border-radius: 15px;
padding: 20px;
text-align: center;
transition: transform 0.3s ease, box-shadow 0.3s ease;
cursor: pointer;
}
.sensor-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 15px rgba(0, 0, 0, 0.2);
background: rgba(255, 255, 255, 0.2);
}
.sensor-icon {
font-size: 40px;
margin-bottom: 15px;
}
.sensor-value {
font-size: 32px;
font-weight: bold;
margin: 10px 0;
}
.sensor-unit {
font-size: 16px;
opacity: 0.8;
}
.sensor-title {
font-size: 18px;
margin-bottom: 10px;
color: #FFD700;
}
.power-section {
background: rgba(0, 0, 0, 0.2);
border-radius: 15px;
padding: 20px;
margin-bottom: 25px;
}
.power-title {
text-align: center;
font-size: 20px;
margin-bottom: 15px;
color: #FFD700;
}
.power-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 15px;
}
.power-card {
background: rgba(255, 255, 255, 0.1);
border-radius: 10px;
padding: 15px;
text-align: center;
}
.power-value {
font-size: 24px;
font-weight: bold;
margin: 5px 0;
}
.power-label {
font-size: 14px;
opacity: 0.8;
}
.last-update {
text-align: center;
font-size: 14px;
opacity: 0.7;
margin-top: 20px;
}
.refresh-info {
text-align: center;
font-size: 14px;
margin-top: 10px;
opacity: 0.7;
}
footer {
text-align: center;
margin-top: 30px;
font-size: 14px;
opacity: 0.8;
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>ESP32 环境监测</h1>
<div class="status">
<div class="status-indicator"></div>
<span>设备在线</span>
</div>
</header>
<div class="sensors-grid">
<div class="sensor-card" style="border: 2px solid #FF5252;">
<div class="sensor-icon">🌡️</div>
<div class="sensor-title">温度</div>
<div class="sensor-value">%.1f</div>
<div class="sensor-unit">°C</div>
</div>
<div class="sensor-card" style="border: 2px solid #29B6F6;">
<div class="sensor-icon">💧</div>
<div class="sensor-title">湿度</div>
<div class="sensor-value">%.1f</div>
<div class="sensor-unit">%</div>
</div>
</div>
<div class="power-section">
<div class="power-title">电能参数</div>
<div class="power-grid">
<div class="power-card">
<div class="power-label">电压</div>
<div class="power-value">%d</div>
<div class="power-unit">V</div>
</div>
<div class="power-card">
<div class="power-label">电流</div>
<div class="power-value">%.1f</div>
<div class="power-unit">A</div>
</div>
<div class="power-card">
<div class="power-label">功率</div>
<div class="power-value">%.1f</div>
<div class="power-unit">W</div>
</div>
</div>
</div>
<div class="last-update">最后更新: %s</div>
<div class="refresh-info">页面每2秒自动刷新</div>
<footer>
ESP32 环境监测系统 | © 2025
</footer>
</div>
<script>
// 每2秒自动刷新页面
setTimeout(function() {
location.reload();
}, 2000);
</script>
</body>
</html>
)rawliteral";
/* 获取当前时间字符串 */
static const char *get_current_time() {
static char time_str[20];
time_t now = time(NULL);
struct tm *timeinfo = localtime(&now);
strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", timeinfo);
return time_str;
}
/* UART事件处理任务 */
static void uart_event_task(void *pvParameters) {
uart_event_t event;
size_t buffered_size;
uint8_t *dtmp = (uint8_t *)malloc(RD_BUF_SIZE);
for (;;) {
if (xQueueReceive(uart0_queue, (void *)&event, (TickType_t)portMAX_DELAY)) {
bzero(dtmp, RD_BUF_SIZE);
switch (event.type) {
case UART_DATA:
uart_read_bytes(EX_UART_NUM, dtmp, event.size, portMAX_DELAY);
if (event.size == 15) {
Voltage = dtmp[3];
Voltage = Voltage << 8;
Voltage |= dtmp[4];
Current = dtmp[5];
Current = Current << 8;
Current |= dtmp[6];
Power = (Voltage * Current) / 10.0f;
ESP_LOGI(TAG, "电能数据: %dV, %.1fA, %.1fW", Voltage, Current / 10.0f, Power);
} else if (event.size == 9) {
Hum = dtmp[3];
Hum = Hum << 8;
Hum |= dtmp[4];
Tem = dtmp[5];
Tem = Tem << 8;
Tem |= dtmp[6];
ESP_LOGI(TAG, "温湿度数据: %.1f°C, %.1f%%", Tem / 10.0f, Hum / 10.0f);
}
break;
case UART_FIFO_OVF:
ESP_LOGW(TAG, "UART FIFO溢出");
uart_flush_input(EX_UART_NUM);
xQueueReset(uart0_queue);
break;
case UART_BUFFER_FULL:
ESP_LOGW(TAG, "UART缓冲区满");
uart_flush_input(EX_UART_NUM);
xQueueReset(uart0_queue);
break;
case UART_BREAK:
ESP_LOGW(TAG, "UART线路断开");
break;
case UART_FRAME_ERR:
ESP_LOGW(TAG, "UART帧错误");
break;
default:
ESP_LOGW(TAG, "未知UART事件: %d", event.type);
break;
}
}
}
free(dtmp);
vTaskDelete(NULL);
}
/* 串口发送任务 */
void uart_T_task(void *p) {
while (1) {
uart_write_bytes(EX_UART_NUM, get_jsy_value, 8);
vTaskDelay(pdMS_TO_TICKS(300));
uart_write_bytes(EX_UART_NUM, get_val, 8);
vTaskDelay(pdMS_TO_TICKS(300));
}
}
/* WiFi事件处理 */
static void wifi_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data) {
if (event_id == WIFI_EVENT_AP_STACONNECTED) {
wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
ESP_LOGI(TAG, "设备连接: "MACSTR", AID=%d", MAC2STR(event->mac), event->aid);
} else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) {
wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
ESP_LOGI(TAG, "设备断开: "MACSTR", AID=%d, 原因=%d", MAC2STR(event->mac), event->aid, event->reason);
}
}
/* 初始化WiFi AP */
void wifi_init_softap(void) {
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_ap();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
ESP_EVENT_ANY_ID,
&wifi_event_handler,
NULL,
NULL));
wifi_config_t wifi_config = {
.ap = {
.ssid = EXAMPLE_ESP_WIFI_SSID,
.ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID),
.channel = EXAMPLE_ESP_WIFI_CHANNEL,
.password = EXAMPLE_ESP_WIFI_PASS,
.max_connection = EXAMPLE_MAX_STA_CONN,
.authmode = WIFI_AUTH_WPA2_PSK,
.pmf_cfg = {
.required = true,
},
},
};
if (strlen(EXAMPLE_ESP_WIFI_PASS) == 0) {
wifi_config.ap.authmode = WIFI_AUTH_OPEN;
}
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "WiFi AP启动完成. SSID:%s 密码:%s 信道:%d",
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS, EXAMPLE_ESP_WIFI_CHANNEL);
}
/* HTTP请求处理函数:处理根路径"/"的GET请求,返回带实时数据的HTML页面 */
static esp_err_t root_get_handler(httpd_req_t *req) {
// 分配内存存储HTML内容(长度为模板长度+200,预留数据填充空间)
char *html_content = (char *)malloc(strlen(HTML_PAGE) + 200);
if (!html_content) {// 若内存分配失败
httpd_resp_send_500(req);// 发送500(服务器内部错误)响应
return ESP_FAIL; // 返回失败
}
// 格式化HTML内容,将实时数据填充到HTML代码模板的占位符中
snprintf(html_content, strlen(HTML_PAGE) + 200, HTML_PAGE,
Tem / 10.0f, // 温度(实际值 = 存储值/10)
Hum / 10.0f,// 湿度(实际值 = 存储值/10)
Voltage,// 电压
Current / 10.0f, // 电流(实际值 = 存储值/10)
Power,// 功率
get_current_time());// 返回最后更新时间(字符串)
// 发送HTTP响应
httpd_resp_set_type(req, "text/html");
httpd_resp_send(req, html_content, strlen(html_content));
free(html_content); // 释放内存
return ESP_OK;
}
/* HTTP服务器URI配置:定义根路径"/"的处理规则 */
static httpd_uri_t root = {
.uri = "/",// 匹配的URI路径
.method = HTTP_GET,// 支持的HTTP方法(GET)
.handler = root_get_handler,//GET方法的 处理函数
.user_ctx = NULL // 用户上下文数据(无)
};
/* 启动HTTP服务器 */
static httpd_handle_t start_webserver(void) {
httpd_handle_t server = NULL; // 服务器句柄
httpd_config_t config = HTTPD_DEFAULT_CONFIG();// 默认服务器配置
config.lru_purge_enable = true; // 启用LRU(最近最少使用)缓存清理
// 启动HTTP服务器
if (httpd_start(&server, &config) == ESP_OK) {
// 注册根路径"/"的处理函数
httpd_register_uri_handler(server, &root);
ESP_LOGI(TAG, "HTTP服务器已启动,端口: %d", config.server_port);
return server;
}
ESP_LOGE(TAG, "HTTP服务器启动失败!");
return NULL;
}
void app_main(void) {
// 初始化NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
// 初始化UART
uart_config_t uart_config = {
.baud_rate = 9600,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_DEFAULT,
};
uart_driver_install(EX_UART_NUM, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart0_queue, 0);
uart_param_config(EX_UART_NUM, &uart_config);
uart_set_pin(EX_UART_NUM, GPIO_NUM_4, GPIO_NUM_5, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
// 创建任务
xTaskCreate(uart_event_task, "uart_event_task", 4046, NULL, 12, NULL);
xTaskCreate(uart_T_task, "uart_T_task", 4046, NULL, 10, NULL);
// 初始化时间
setenv("TZ", "CST-8", 1);
tzset();
// 初始化WiFi和HTTP服务器
ESP_LOGI(TAG, "初始化WiFi AP...");
wifi_init_softap();
ESP_LOGI(TAG, "启动HTTP服务器...");
httpd_handle_t server = start_webserver();
ESP_LOGI(TAG, "系统已启动完成");
ESP_LOGI(TAG, "请连接热点: %s", EXAMPLE_ESP_WIFI_SSID);
ESP_LOGI(TAG, "然后在浏览器访问: http://192.168.4.1");
}
上述代码时间显示有问题,下面是优化后的代码 显示时间为手机的时间与esp32无关
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_mac.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include <string.h>
#include "lwip/err.h"
#include "lwip/sys.h"
#include <esp_http_server.h>
#include <stdio.h>
#include <string.h>
#include "freertos/queue.h"
#include "driver/uart.h"
#include "driver/gpio.h"
#include "cJSON.h"
#include <time.h>
#include "esp_sntp.h"
/* 配置参数 */
#define EXAMPLE_ESP_WIFI_SSID "laotie666"
#define EXAMPLE_ESP_WIFI_PASS "12345678"
#define EXAMPLE_ESP_WIFI_CHANNEL 1
#define EXAMPLE_MAX_STA_CONN 4
#define EXAMPLE_HTTP_QUERY_KEY_MAX_LEN (64)
#define EX_UART_NUM UART_NUM_1
#define BUF_SIZE (1024)
#define RD_BUF_SIZE (BUF_SIZE)
/* 全局变量 */
uint8_t get_jsy_value[8] = {0x02, 0x03, 0x00, 0x48, 0x00, 0x05, 0x05, 0xEC};
uint8_t get_val[8] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x02, 0xC4, 0x0B};
uint16_t Hum = 255; // 湿度值 Hum = 实际值 * 10
int16_t Tem = 232; // 温度值 Tem = 实际值 * 10
uint16_t Voltage = 24, Current = 2;
float Power = 2.3; // 功率
static QueueHandle_t uart0_queue;
static const char *TAG = "wifi softAP";
/* 美观的HTML页面模板 */
static const char *HTML_PAGE = R"rawliteral(
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ESP32 环境监测</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
.container {
background: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(10px);
border-radius: 20px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
width: 100%;
max-width: 500px;
padding: 30px;
color: white;
}
header {
text-align: center;
margin-bottom: 30px;
}
h1 {
font-size: 28px;
margin-bottom: 10px;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.status {
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
font-size: 16px;
}
.status-indicator {
width: 12px;
height: 12px;
border-radius: 50%;
background-color: #4CAF50;
box-shadow: 0 0 10px #4CAF50;
}
.sensors-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
margin-bottom: 30px;
}
.sensor-card {
background: rgba(255, 255, 255, 0.1);
border-radius: 15px;
padding: 20px;
text-align: center;
transition: transform 0.3s ease, box-shadow 0.3s ease;
cursor: pointer;
}
.sensor-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 15px rgba(0, 0, 0, 0.2);
background: rgba(255, 255, 255, 0.2);
}
.sensor-icon {
font-size: 40px;
margin-bottom: 15px;
}
.sensor-value {
font-size: 32px;
font-weight: bold;
margin: 10px 0;
}
.sensor-unit {
font-size: 16px;
opacity: 0.8;
}
.sensor-title {
font-size: 18px;
margin-bottom: 10px;
color: #FFD700;
}
.power-section {
background: rgba(0, 0, 0, 0.2);
border-radius: 15px;
padding: 20px;
margin-bottom: 25px;
}
.power-title {
text-align: center;
font-size: 20px;
margin-bottom: 15px;
color: #FFD700;
}
.power-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 15px;
}
.power-card {
background: rgba(255, 255, 255, 0.1);
border-radius: 10px;
padding: 15px;
text-align: center;
}
.power-value {
font-size: 24px;
font-weight: bold;
margin: 5px 0;
}
.power-label {
font-size: 14px;
opacity: 0.8;
}
.last-update {
font-size: 16px;
margin-bottom: 8px;
color: #FFD700;
}
#current-time {
text-align: center;
font-size: 14px;
margin-top: 10px;
opacity: 0.7;
}
.refresh-info {
text-align: center;
font-size: 14px;
margin-top: 10px;
opacity: 0.7;
}
footer {
text-align: center;
margin-top: 30px;
font-size: 14px;
opacity: 0.8;
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>ESP32 环境监测</h1>
<div class="status">
<div class="status-indicator"></div>
<span>设备在线</span>
</div>
</header>
<div class="sensors-grid">
<div class="sensor-card" style="border: 2px solid #FF5252;">
<div class="sensor-icon">🌡️</div>
<div class="sensor-title">温度</div>
<div class="sensor-value">%.1f</div>
<div class="sensor-unit">°C</div>
</div>
<div class="sensor-card" style="border: 2px solid #29B6F6;">
<div class="sensor-icon">💧</div>
<div class="sensor-title">湿度</div>
<div class="sensor-value">%.1f</div>
<div class="sensor-unit">%%</div>
</div>
</div>
<div class="power-section">
<div class="power-title">电能参数</div>
<div class="power-grid">
<div class="power-card">
<div class="power-label">电压</div>
<div class="power-value">%d</div>
<div class="power-unit">V</div>
</div>
<div class="power-card">
<div class="power-label">电流</div>
<div class="power-value">%.1f</div>
<div class="power-unit">A</div>
</div>
<div class="power-card">
<div class="power-label">功率</div>
<div class="power-value">%.1f</div>
<div class="power-unit">W</div>
</div>
</div>
</div>
<div class="refresh-info">数据更新时间: <span id="current-time">正在获取...</span></div>
<div class="refresh-info">页面每秒自动刷新</div>
<footer>
ESP32 环境监测系统 | © 2025
</footer>
</div>
<script>
function updateSystemTime() {
const now = new Date();
const timeString = now.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false
});
document.getElementById('current-time').textContent = timeString;
}
updateSystemTime();
setInterval(updateSystemTime, 1000);
setTimeout(function() {
location.reload();
}, 1000);
</script>
</body>
</html>
)rawliteral";
/* UART事件处理任务 */
static void uart_event_task(void *pvParameters)
{
uart_event_t event;
size_t buffered_size;
uint8_t *dtmp = (uint8_t *)malloc(RD_BUF_SIZE);
for (;;)
{
if (xQueueReceive(uart0_queue, (void *)&event, (TickType_t)portMAX_DELAY))
{
bzero(dtmp, RD_BUF_SIZE);
switch (event.type)
{
case UART_DATA:
uart_read_bytes(EX_UART_NUM, dtmp, event.size, portMAX_DELAY);
if (event.size == 15)
{
Voltage = dtmp[3];
Voltage = Voltage << 8;
Voltage |= dtmp[4];
Current = dtmp[5];
Current = Current << 8;
Current |= dtmp[6];
Power = (Voltage * Current) / 10.0f;
ESP_LOGI(TAG, "电能数据: %dV, %.1fA, %.1fW", Voltage, Current / 10.0f, Power);
}
else if (event.size == 9)
{
Hum = dtmp[3];
Hum = Hum << 8;
Hum |= dtmp[4];
Tem = dtmp[5];
Tem = Tem << 8;
Tem |= dtmp[6];
ESP_LOGI(TAG, "温湿度数据: %.1f°C, %.1f%%", Tem / 10.0f, Hum / 10.0f);
}
break;
case UART_FIFO_OVF:
ESP_LOGW(TAG, "UART FIFO溢出");
uart_flush_input(EX_UART_NUM);
xQueueReset(uart0_queue);
break;
case UART_BUFFER_FULL:
ESP_LOGW(TAG, "UART缓冲区满");
uart_flush_input(EX_UART_NUM);
xQueueReset(uart0_queue);
break;
case UART_BREAK:
ESP_LOGW(TAG, "UART线路断开");
break;
case UART_FRAME_ERR:
ESP_LOGW(TAG, "UART帧错误");
break;
default:
ESP_LOGW(TAG, "未知UART事件: %d", event.type);
break;
}
}
}
free(dtmp);
vTaskDelete(NULL);
}
/* 串口发送任务 */
void uart_T_task(void *p)
{
while (1)
{
uart_write_bytes(EX_UART_NUM, get_jsy_value, 8);
vTaskDelay(pdMS_TO_TICKS(300));
uart_write_bytes(EX_UART_NUM, get_val, 8);
vTaskDelay(pdMS_TO_TICKS(300));
}
}
/* WiFi事件处理 */
static void wifi_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
if (event_id == WIFI_EVENT_AP_STACONNECTED)
{
wifi_event_ap_staconnected_t *event = (wifi_event_ap_staconnected_t *)event_data;
ESP_LOGI(TAG, "设备连接: " MACSTR ", AID=%d", MAC2STR(event->mac), event->aid);
}
else if (event_id == WIFI_EVENT_AP_STADISCONNECTED)
{
wifi_event_ap_stadisconnected_t *event = (wifi_event_ap_stadisconnected_t *)event_data;
ESP_LOGI(TAG, "设备断开: " MACSTR ", AID=%d, 原因=%d", MAC2STR(event->mac), event->aid, event->reason);
}
}
/* 初始化WiFi AP */
void wifi_init_softap(void)
{
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_ap();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
ESP_EVENT_ANY_ID,
&wifi_event_handler,
NULL,
NULL));
wifi_config_t wifi_config = {
.ap = {
.ssid = EXAMPLE_ESP_WIFI_SSID,
.ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID),
.channel = EXAMPLE_ESP_WIFI_CHANNEL,
.password = EXAMPLE_ESP_WIFI_PASS,
.max_connection = EXAMPLE_MAX_STA_CONN,
.authmode = WIFI_AUTH_WPA2_PSK,
.pmf_cfg = {
.required = true,
},
},
};
if (strlen(EXAMPLE_ESP_WIFI_PASS) == 0)
{
wifi_config.ap.authmode = WIFI_AUTH_OPEN;
}
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "WiFi AP启动完成. SSID:%s 密码:%s 信道:%d",
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS, EXAMPLE_ESP_WIFI_CHANNEL);
}
/* HTTP请求处理函数:处理根路径"/"的GET请求,返回带实时数据的HTML页面 */
static esp_err_t root_get_handler(httpd_req_t *req)
{
// 分配内存存储HTML内容(长度为模板长度+200,预留数据填充空间)
char *html_content = (char *)malloc(strlen(HTML_PAGE) + 200);
if (!html_content)
{ // 若内存分配失败
httpd_resp_send_500(req); // 发送500(服务器内部错误)响应
return ESP_FAIL; // 返回失败
}
// 格式化HTML内容,将实时数据填充到HTML代码模板的占位符中
snprintf(html_content, strlen(HTML_PAGE) + 200, HTML_PAGE,
Tem / 10.0f, // 温度(实际值 = 存储值/10)
Hum / 10.0f, // 湿度(实际值 = 存储值/10)
Voltage, // 电压
Current / 10.0f, // 电流(实际值 = 存储值/10)
Power); // 功率
// 发送HTTP响应
httpd_resp_set_type(req, "text/html");
httpd_resp_send(req, html_content, strlen(html_content));
free(html_content); // 释放内存
return ESP_OK;
}
/* HTTP服务器URI配置:定义根路径"/"的处理规则 */
static httpd_uri_t root = {
.uri = "/", // 匹配的URI路径
.method = HTTP_GET, // 支持的HTTP方法(GET)
.handler = root_get_handler, // GET方法的 处理函数
.user_ctx = NULL // 用户上下文数据(无)
};
/* 启动HTTP服务器 */
static httpd_handle_t start_webserver(void)
{
httpd_handle_t server = NULL; // 服务器句柄
httpd_config_t config = HTTPD_DEFAULT_CONFIG(); // 默认服务器配置
config.lru_purge_enable = true; // 启用LRU(最近最少使用)缓存清理
// 启动HTTP服务器
if (httpd_start(&server, &config) == ESP_OK)
{
// 注册根路径"/"的处理函数
httpd_register_uri_handler(server, &root);
ESP_LOGI(TAG, "HTTP服务器已启动,端口: %d", config.server_port);
return server;
}
ESP_LOGE(TAG, "HTTP服务器启动失败!");
return NULL;
}
void app_main(void)
{
// 初始化NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
{
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
// 初始化UART
uart_config_t uart_config = {
.baud_rate = 9600,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_DEFAULT,
};
uart_driver_install(EX_UART_NUM, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart0_queue, 0);
uart_param_config(EX_UART_NUM, &uart_config);
uart_set_pin(EX_UART_NUM, GPIO_NUM_4, GPIO_NUM_5, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
// 创建任务
xTaskCreate(uart_event_task, "uart_event_task", 4046, NULL, 12, NULL);
xTaskCreate(uart_T_task, "uart_T_task", 4046, NULL, 10, NULL);
// 初始化时间
setenv("TZ", "CST-8", 1);
tzset(); // 应用时区设置
// 初始化WiFi和HTTP服务器
ESP_LOGI(TAG, "初始化WiFi AP...");
wifi_init_softap();
ESP_LOGI(TAG, "启动HTTP服务器...");
httpd_handle_t server = start_webserver();
ESP_LOGI(TAG, "系统已启动完成");
ESP_LOGI(TAG, "请连接热点: %s", EXAMPLE_ESP_WIFI_SSID);
ESP_LOGI(TAG, "然后在浏览器访问: http://192.168.4.1");
}