网上的SPIFFS看了好多没看到具体的SPIFFS文件配置 找了半天给我找红温了
SPIFFS
它是ESP32的一个文件系统 VSCODE的IDF是自带的,但是需要配置,搞得不是很明白但是最后还是能跑了 以后再细研究.
用这个的目的主要是需要搞一个网页配网的功能,因为HTML的功能很少只用写个ssid和password就能行,所以ChatGPT给我写的是字符串格式的HTML
const char *html_content = "<!DOCTYPE html>\
<html>\
<head><title>WiFi Setup</title></head>\
<body>\
<h2>WiFi Configuration</h2>\
<form method=\"POST\" action=\"/config\">\
<label for=\"ssid\">SSID:</label><br>\
<input type=\"text\" id=\"ssid\" name=\"ssid\" required><br><br>\
<label for=\"password\">Password:</label><br>\
<input type=\"password\" id=\"password\" name=\"password\" required><br><br>\
<input type=\"submit\" value=\"Submit\">\
</form>\
</body>\
</html>";
这么写肯定不利于维护啊,我以后想加个图片都费劲,所以就要给他搞成一个文件,SPIFFS就可以将这些静态文件写入ESP32的flash里
一开始查的是要配置镜像啥的
后来一查发现
如果是我自己创建好的一个.bin文件, 那就不用创建
如果是我要再构建过程中,我才要创建镜像
所以我们是要创建这个镜像的
这个镜像需要在CMakeLists里写的 我是写在main文件夹里注意路径名称
spiffs_create_partition_image(spiffs ../Web FLASH_IN_PROJECT)
这个也是有讲究的 他是需要一个分区表
partitions1.csv
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 24K,
phy_init, data, phy, 0xf000, 4K,
factory, app, factory, 0x10000, 1M,
spiffs, data, spiffs, 0x110000, 512K,
当然 这也是ChatGPT生成的
这个spiffs一定要对着下面的这个分区表
然后我们要在menuconfig里面找到这个分区表的配置
配好之后我们要进行build啦 先build一下源代码
然后在终端上写 idf.py -p COM4 spiffs-flash 这个COM4是我当前的端口 Linux和MAC都不一样的 这个就是将镜像部署到固件里 (现在我发现不写也没事)
最后就烧录主程序就成拉
一开始我连idf.py都打不了 后来才知道要去把IDF配置一下环境变量
差点忘记写源码了
#include <string.h>
#include <stdio.h>
#include "esp_log.h"
#include "esp_http_server.h"
#include "esp_wifi.h"
#include "esp_system.h"
#include "esp_event.h"
#include "nvs_flash.h"
#include "esp_err.h"
#include "esp_spiffs.h"
esp_err_t init_spiffs() ;
void wifi_event_handler(void* event_handler_arg,esp_event_base_t event_base,int32_t event_id,void* event_data);
esp_err_t root_get_handler(httpd_req_t *req) ;
void start_sta_mode(const char *ssid, const char *password) ;
esp_err_t form_post_handler(httpd_req_t *req);
void create_httpd_server();
void start_ap_mode();
esp_err_t root_get_handler(httpd_req_t *req);
static const char *AP_TAG = "WIFI_AP";
static const char *STA_TAG = "WIFI_STA";
httpd_handle_t server = NULL;
esp_err_t init_spiffs() {
esp_vfs_spiffs_conf_t conf = {
.base_path = "/Web",
.partition_label = NULL,
.max_files = 5,
.format_if_mount_failed = true
};
esp_err_t ret = esp_vfs_spiffs_register(&conf);
if (ret != ESP_OK) {
ESP_LOGE(AP_TAG, "Failed to mount or format SPIFFS");
return ret;
}
return ESP_OK;
}
esp_err_t root_get_handler(httpd_req_t *req) {
ESP_LOGI(AP_TAG, "Serving HTML page");
// 打开 SPIFFS 中的 HTML 文件
FILE* f = fopen("/Web/DistributeWifi.html", "r");
if (f == NULL) {
ESP_LOGE(AP_TAG, "Failed to open file for reading");
return ESP_FAIL;
}
// 计算文件的大小
fseek(f, 0, SEEK_END);
size_t file_size = ftell(f);
fseek(f, 0, SEEK_SET);
// 读取文件内容并发送到客户端
char* buf = malloc(file_size + 1);
fread(buf, 1, file_size, f);
fclose(f);
buf[file_size] = '\0'; // 确保字符串结尾
httpd_resp_send(req, buf, file_size);
free(buf);
return ESP_OK;
}
// WiFi事件处理函数
void wifi_event_handler(void* event_handler_arg,esp_event_base_t event_base,int32_t event_id,void* event_data)
{
if(event_base == WIFI_EVENT)
{
switch(event_id)
{
case WIFI_EVENT_STA_START:
esp_wifi_connect(); // 连接wifi
break;
case WIFI_EVENT_STA_CONNECTED:
ESP_LOGI(STA_TAG,"esp32 connected to sta!");
break;
case WIFI_EVENT_STA_DISCONNECTED:
ESP_LOGI(STA_TAG,"esp32 connect fail please retry~~~");
vTaskDelay(1000 / portTICK_PERIOD_MS); // 1秒后重试
esp_wifi_connect(); // 重试连接wifi
break;
default:
break;
}
}
else if(event_base == IP_EVENT){
switch(event_id){
case IP_EVENT_STA_GOT_IP:
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
ESP_LOGI(STA_TAG, "STA Got IP: "IPSTR, IP2STR(&event->ip_info.ip));
if(server != NULL)
{
httpd_stop(server);
server = NULL;
}
create_httpd_server();
break;
}
}
}
void start_sta_mode(const char *ssid, const char *password) {
esp_wifi_stop();
esp_wifi_deinit();
// 配置STA模式
ESP_ERROR_CHECK(esp_netif_init());//初始化TCP / IP堆栈和esp-netif
esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
// 检查是否已经注册了事件处理器,避免重复注册
static bool handler_registered = false;
if (!handler_registered) {
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, NULL));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL, NULL));
handler_registered = true;
}
wifi_config_t wifi_config = {
.sta = {
.ssid = {0},
.password = {0},
.threshold = {
.authmode = WIFI_AUTH_WPA2_PSK
},
},
};
// 设置WiFi配置
strncpy((char *)wifi_config.sta.ssid, ssid, sizeof(wifi_config.sta.ssid) - 1);
strncpy((char *)wifi_config.sta.password, password, sizeof(wifi_config.sta.password) - 1);
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGE(STA_TAG, "Connecting to WiFi SSID: %s", ssid);
}
// 处理POST请求,解析WiFi配置数据
esp_err_t form_post_handler(httpd_req_t *req) {
char buf[512]; // 假设请求体最大长度为512字节
int ret, remaining = req->content_len;
memset(buf, 0, sizeof(buf));
// 检查请求的内容长度
if (remaining > sizeof(buf)) {
ESP_LOGE(AP_TAG, "Content too long");
return ESP_ERR_HTTPD_INVALID_REQ;
}
// 读取HTTP请求的内容
ret = httpd_req_recv(req, buf, remaining);
if (ret < 0) {
ESP_LOGE(AP_TAG, "Failed to read the request body");
return ESP_FAIL;
}
// 打印接收到的请求内容,方便调试
ESP_LOGI(AP_TAG, "Received POST data: %s", buf);
// 解析表单数据
char ssid[32] = {0};
char password[10] = {0};
// 使用简单的字符串处理来解析数据
char *ssid_start = strstr(buf, "ssid=");
char *password_start = strstr(buf, "password=");
if (ssid_start != NULL && password_start != NULL) {
// 获取SSID值
ssid_start += strlen("ssid="); // 跳过"ssid="部分
char *ssid_end = strchr(ssid_start, '&');
if (ssid_end != NULL) {
strncpy(ssid, ssid_start, ssid_end - ssid_start);
} else {
strcpy(ssid, ssid_start);
}
// 获取Password值
password_start += strlen("password="); // 跳过"password="部分
char *password_end = strchr(password_start, '&');
if (password_end != NULL) {
strncpy(password, password_start, password_end - password_start);
} else {
strcpy(password, password_start);
}
ESP_LOGI(AP_TAG, "Received SSID: %s", ssid);
ESP_LOGI(AP_TAG, "Received Password: %s", password);
// 将接收到的SSID和Password用于WiFi连接
start_sta_mode(ssid, password);
} else {
ESP_LOGE(AP_TAG, "Invalid data format");
return ESP_ERR_HTTPD_INVALID_REQ;
}
// 回应客户端,告知配置完成
const char *resp_str = "WiFi configuration complete! Rebooting...";
httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);
return ESP_OK;
}
void create_httpd_server() {
// 启动Web服务器
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.uri_match_fn = httpd_uri_match_wildcard;
if (httpd_start(&server, &config) == ESP_OK) {
httpd_uri_t root_uri = {
.uri = "/",
.method = HTTP_GET,
.handler = root_get_handler,
.user_ctx = NULL
};
httpd_register_uri_handler(server, &root_uri);
httpd_uri_t post_uri = {
.uri = "/config",
.method = HTTP_POST,
.handler = form_post_handler,
.user_ctx = NULL
};
httpd_register_uri_handler(server, &post_uri);
}
}
// 配置AP模式并启动Web服务器
void start_ap_mode() {
ESP_ERROR_CHECK(esp_netif_init());//初始化TCP / IP堆栈和esp-netif
ESP_ERROR_CHECK(esp_event_loop_create_default()); //创建默认event loop
esp_netif_create_default_wifi_ap();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
wifi_config_t ap_config = {
.ap = {
.ssid = "ESP32",
.ssid_len = strlen("ESP32"),
.password = "123456789",
.max_connection = 4,
.authmode = WIFI_AUTH_WPA2_PSK
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &ap_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(AP_TAG, "AP mode started. SSID: ESP32_Config, password: 123456789");
create_httpd_server();
}
void app_main() {
ESP_LOGI(AP_TAG, "Starting WiFi Config AP mode...");
// 初始化NVS(用于存储WiFi配置等)
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);
ESP_ERROR_CHECK(init_spiffs());
// 启动AP模式并启动Web服务器
start_ap_mode();
}
全都糊在一个文件上 看懂可太费劲了
发布评论