- /*!
- \file main.c
- \brief GD32VW553 智能浇水系统 - SoftAP + 远程控制
- \author 我爱小易
- \company 萤火工场
- */
- #include <stdint.h>
- #include <stdio.h>
- #include <string.h>
- #include "gd32vw55x.h"
- #include "app_cfg.h"
- #include "gd32vw55x_platform.h"
- #include "lwip/sockets.h"
- #include "lwip/priv/sockets_priv.h"
- #include "wifi_management.h"
- #include "wifi_init.h"
- #include "gd32vw55x_adc.h"
- /* 硬件引脚定义 - 请根据实际硬件调整 */
- #define WATER_PUMP_PORT GPIOB
- #define WATER_PUMP_PIN GPIO_PIN_2
- #define SOIL_MOISTURE_ADC_CHANNEL ADC_CHANNEL_0
- #define WATER_LEVEL_PORT GPIOA
- #define WATER_LEVEL_PIN GPIO_PIN_1
- #define SYSTEM_LED_PORT GPIOB
- #define SYSTEM_LED_PIN GPIO_PIN_0
- #define AP_SSID "SmartWatering_AP"
- #define AP_PASSWORD "12345678"
- #define HTTP_PORT 80
- /* 系统参数 */
- #define MOISTURE_THRESHOLD_LOW 30 /* 自动浇水阈值 */
- #define MOISTURE_THRESHOLD_HIGH 60 /* 停止浇水阈值 */
- #define WATERING_DURATION 30000 /* 浇水持续时间(ms) */
- /* 全局变量 */
- volatile uint8_t watering_mode = 0; /* 0:自动 1:定时 2:手动 */
- volatile uint8_t watering_status = 0;
- volatile uint16_t soil_moisture = 0;
- volatile uint8_t water_level = 0;
- volatile uint32_t watering_timer = 0;
- volatile uint32_t next_watering_time = 0;
- /* 硬件初始化 */
- void hardware_init(void) {
- /* 初始化水泵控制 */
- rcu_periph_clock_enable(RCU_GPIOB);
- gpio_mode_set(WATER_PUMP_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, WATER_PUMP_PIN);
- gpio_output_options_set(WATER_PUMP_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, WATER_PUMP_PIN);
- gpio_bit_reset(WATER_PUMP_PORT, WATER_PUMP_PIN);
- /* 初始化水位检测 */
- rcu_periph_clock_enable(RCU_GPIOA);
- gpio_mode_set(WATER_LEVEL_PORT, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, WATER_LEVEL_PIN);
- /* 初始化系统LED */
- gpio_mode_set(SYSTEM_LED_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SYSTEM_LED_PIN);
- gpio_output_options_set(SYSTEM_LED_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, SYSTEM_LED_PIN);
- gpio_bit_reset(SYSTEM_LED_PORT, SYSTEM_LED_PIN);
- /* 初始化ADC用于土壤湿度检测 */
- rcu_periph_clock_enable(RCU_ADC0);
- adc_mode_config(ADC_MODE_FREE);
- adc_special_function_config(ADC_SCAN_MODE, ENABLE);
- adc_special_function_config(ADC_CONTINUOUS_MODE, ENABLE);
- adc_clock_config(ADC_CLK_SYSCLK_DIV6);
- adc_channel_length_config(ADC_REGULAR_CHANNEL, 1);
- adc_regular_channel_config(0, SOIL_MOISTURE_ADC_CHANNEL, ADC_SAMPLETIME_55POINT5);
- adc_enable();
- delay_1ms(1);
- adc_calibration_enable();
- adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL);
- }
- /* 控制函数 */
- void water_pump_on(void) {
- gpio_bit_set(WATER_PUMP_PORT, WATER_PUMP_PIN);
- watering_status = 1;
- printf("水泵开启\n");
- }
- void water_pump_off(void) {
- gpio_bit_reset(WATER_PUMP_PORT, WATER_PUMP_PIN);
- watering_status = 0;
- printf("水泵关闭\n");
- }
- void system_led_toggle(void) {
- gpio_bit_toggle(SYSTEM_LED_PORT, SYSTEM_LED_PIN);
- }
- /* 传感器读取函数 */
- uint16_t read_soil_moisture(void) {
- while(!adc_flag_get(ADC0, ADC_FLAG_EOC));
- uint16_t adc_value = adc_regular_data_read(ADC0);
- /* 转换为百分比 (需要根据实际传感器校准) */
- return (100 - ((adc_value * 100) / 4095));
- }
- uint8_t check_water_level(void) {
- return (gpio_input_bit_get(WATER_LEVEL_PORT, WATER_LEVEL_PIN) == RESET) ? 1 : 0;
- }
- /* 自动浇水逻辑 */
- void auto_watering_task(void) {
- soil_moisture = read_soil_moisture();
- water_level = check_water_level();
- if(watering_mode == 0) { /* 自动模式 */
- if(soil_moisture < MOISTURE_THRESHOLD_LOW && !watering_status && !water_level) {
- water_pump_on();
- watering_timer = WATERING_DURATION;
- }
- else if((soil_moisture > MOISTURE_THRESHOLD_HIGH && watering_status) || water_level) {
- water_pump_off();
- watering_timer = 0;
- }
- }
- /* 处理浇水定时器 */
- if(watering_timer > 0) {
- if(--watering_timer == 0) {
- water_pump_off();
- }
- }
- }
- // 解析 URL 参数
- int get_query_param(const char* request, const char* key, char* value, size_t val_size) {
- const char* query_start = strchr(request, '?');
- if (!query_start) return 0;
- const char* key_pos = strstr(query_start, key);
- if (!key_pos) return 0;
- const char* eq = strchr(key_pos, '=');
- if (!eq) return 0;
- eq++;
- const char* end = eq;
- while (*end && *end != ' ' && *end != '\r' && *end != '&' && *end != '\n') {
- end++;
- }
- size_t len = (end - eq) < (val_size - 1) ? (end - eq) : (val_size - 1);
- memcpy(value, eq, len);
- value[len] = '\0';
- return 1;
- }
- // 发送 HTTP 响应
- void send_response(int fd, const char* content_type, const char* body) {
- char header[256];
- int len = strlen(body);
- snprintf(header, sizeof(header),
- "HTTP/1.1 200 OK\r\n"
- "Content-Type: %s\r\n"
- "Content-Length: %d\r\n"
- "Connection: close\r\n"
- "\r\n", content_type, len);
- write(fd, header, strlen(header));
- write(fd, body, len);
- }
- static void http_server_serve(int conn_fd) {
- char buffer[1024];
- int len = read(conn_fd, buffer, sizeof(buffer) - 1);
- if (len <= 0) {
- close(conn_fd);
- return;
- }
- buffer[len] = '\0';
- printf("请求: %.100s\n", buffer);
- // API 接口处理
- if (strncmp(buffer, "GET /api/", 8) == 0) {
- char action[16] = {0};
- char value[16] = {0};
- if (strncmp(buffer, "GET /api/control", 16) == 0) {
- if (get_query_param(buffer, "action", action, sizeof(action))) {
- if (strcmp(action, "on") == 0) {
- watering_mode = 2; /* 手动模式 */
- water_pump_on();
- watering_timer = WATERING_DURATION;
- } else if (strcmp(action, "off") == 0) {
- water_pump_off();
- } else if (strcmp(action, "auto") == 0) {
- watering_mode = 0; /* 自动模式 */
- } else if (strcmp(action, "timer") == 0) {
- watering_mode = 1; /* 定时模式 */
- }
- }
- }
- else if (strncmp(buffer, "GET /api/timer", 14) == 0) {
- if (get_query_param(buffer, "set", value, sizeof(value))) {
- next_watering_time = atoi(value) * 60 * 1000; /* 转换为毫秒 */
- printf("定时浇水设置: %s分钟后\n", value);
- }
- }
- /* 返回系统状态JSON */
- char json[256];
- const char* mode_str[] = {"自动", "定时", "手动"};
- const char* pump_status = watering_status ? "开启" : "关闭";
- const char* water_level_str = water_level ? "低水位" : "正常";
- snprintf(json, sizeof(json),
- "{"mode":"%s","pump":"%s","moisture":%d,"water_level":"%s","timer":%lu}",
- mode_str[watering_mode], pump_status, soil_moisture, water_level_str,
- watering_timer / 1000);
- send_response(conn_fd, "application/json", json);
- close(conn_fd);
- return;
- }
- // 返回智能浇水系统网页
- const char* html =
- "<!DOCTYPE html>"
- "<html lang="zh-CN">"
- "<head>"
- " <meta charset="UTF-8">"
- " <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">"
- " <title>智能浇水系统 - GD32VW553</title>"
- " <style>"
- " body {"
- " margin: 0; padding: 20px;"
- " font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;"
- " background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);"
- " min-height: 100vh; color: #333;"
- " }"
- " .container { max-width: 500px; margin: 0 auto; background: rgba(255,255,255,0.95); border-radius: 20px; padding: 30px; box-shadow: 0 10px 30px rgba(0,0,0,0.2); }"
- " h1 { text-align: center; color: #2c3e50; margin-bottom: 10px; }"
- " .subtitle { text-align: center; color: #7f8c8d; margin-bottom: 30px; }"
- " .status-card { background: #ecf0f1; border-radius: 15px; padding: 20px; margin: 15px 0; }"
- " .status-item { display: flex; justify-content: space-between; margin: 10px 0; }"
- " .moisture-bar { height: 20px; background: #bdc3c7; border-radius: 10px; overflow: hidden; margin: 10px 0; }"
- " .moisture-fill { height: 100%; background: linear-gradient(90deg, #e74c3c, #f39c12, #27ae60); transition: width 0.5s; }"
- " .btn-group { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin: 15px 0; }"
- " .btn { padding: 12px; border: none; border-radius: 10px; font-size: 16px; font-weight: bold; cursor: pointer; transition: all 0.3s; }"
- " .btn-primary { background: #3498db; color: white; }"
- " .btn-success { background: #27ae60; color: white; }"
- " .btn-warning { background: #f39c12; color: white; }"
- " .btn-danger { background: #e74c3c; color: white; }"
- " .btn:active { transform: scale(0.98); }"
- " .timer-set { display: flex; gap: 10px; margin: 15px 0; }"
- " .timer-input { flex: 1; padding: 12px; border: 2px solid #bdc3c7; border-radius: 10px; font-size: 16px; }"
- " .alert { padding: 10px; border-radius: 5px; margin: 10px 0; text-align: center; }"
- " .alert-warning { background: #fff3cd; color: #856404; border: 1px solid #ffeaa7; }"
- " .footer { text-align: center; margin-top: 30px; color: #7f8c8d; font-size: 14px; }"
- " </style>"
- "</head>"
- "<body>"
- " <div class="container">"
- " <h1>🌱 智能浇水系统</h1>"
- " <div class="subtitle">GD32VW553 · 萤火工场 · 我爱小易</div>"
- " "
- " <div class="status-card">"
- " <h3>📊 系统状态</h3>"
- " <div class="status-item"><span>工作模式:</span><span id="mode">自动</span></div>"
- " <div class="status-item"><span>水泵状态:</span><span id="pump">关闭</span></div>"
- " <div class="status-item"><span>土壤湿度:</span><span id="moisture">0%</span></div>"
- " <div class="moisture-bar"><div id="moistureBar" class="moisture-fill" style="width: 0%"></div></div>"
- " <div class="status-item"><span>水位状态:</span><span id="waterLevel">正常</span></div>"
- " <div class="status-item"><span>剩余时间:</span><span id="timer">0秒</span></div>"
- " </div>"
- " "
- " <div id="waterAlert" class="alert alert-warning" style="display:none;">⚠️ 水位过低,浇水已停止!</div>"
- " "
- " <div class="btn-group">"
- " <button class="btn btn-primary" onclick="setMode('auto')">🤖 自动模式</button>"
- " <button class="btn btn-warning" onclick="setMode('timer')">⏰ 定时模式</button>"
- " </div>"
- " "
- " <div class="btn-group">"
- " <button class="btn btn-success" onclick="controlPump('on')">💧 开始浇水</button>"
- " <button class="btn btn-danger" onclick="controlPump('off')">🛑 停止浇水</button>"
- " </div>"
- " "
- " <div style="margin: 20px 0;">"
- " <h4>定时浇水设置:</h4>"
- " <div class="timer-set">"
- " <input type="number" id="timerInput" class="timer-input" placeholder="分钟后浇水" min="1" max="1440">"
- " <button class="btn btn-warning" onclick="setTimer()">设置定时</button>"
- " </div>"
- " </div>"
- " "
- " <div class="footer">"
- " 连接开发板 Wi-Fi 即可远程控制<br>"
- " 系统将自动监测土壤湿度和水位"
- " </div>"
- " </div>"
- " "
- " <script>"
- " let updateInterval;"
- " "
- " function updateStatus() {"
- " fetch('/api/control?action=status')"
- " .then(res => res.json())"
- " .then(data => {"
- " document.getElementById('mode').textContent = data.mode;"
- " document.getElementById('pump').textContent = data.pump;"
- " document.getElementById('moisture').textContent = data.moisture + '%';"
- " document.getElementById('waterLevel').textContent = data.water_level;"
- " document.getElementById('timer').textContent = data.timer + '秒';"
- " "
- " document.getElementById('moistureBar').style.width = data.moisture + '%';"
- " "
- " const alert = document.getElementById('waterAlert');"
- " alert.style.display = data.water_level === '低水位' ? 'block' : 'none';"
- " "
- " // 根据湿度改变颜色"
- " const moisture = data.moisture;"
- " if(moisture < 30) {"
- " document.getElementById('moistureBar').style.background = '#e74c3c';"
- " } else if(moisture < 60) {"
- " document.getElementById('moistureBar').style.background = '#f39c12';"
- " } else {"
- " document.getElementById('moistureBar').style.background = '#27ae60';"
- " }"
- " })"
- " .catch(err => console.error('更新状态失败:', err));"
- " }"
- " "
- " function setMode(mode) {"
- " fetch('/api/control?action=' + mode)"
- " .then(() => updateStatus())"
- " .catch(err => console.error('设置模式失败:', err));"
- " }"
- " "
- " function controlPump(action) {"
- " fetch('/api/control?action=' + action)"
- " .then(() => updateStatus())"
- " .catch(err => console.error('控制水泵失败:', err));"
- " }"
- " "
- " function setTimer() {"
- " const minutes = document.getElementById('timerInput').value;"
- " if(minutes && minutes > 0) {"
- " fetch('/api/timer?set=' + minutes)"
- " .then(() => {"
- " updateStatus();"
- " document.getElementById('timerInput').value = '';"
- " alert('定时浇水设置成功: ' + minutes + '分钟后');"
- " })"
- " .catch(err => console.error('设置定时失败:', err));"
- " }"
- " }"
- " "
- " // 页面加载时开始定时更新"
- " document.addEventListener('DOMContentLoaded', function() {"
- " updateStatus();"
- " updateInterval = setInterval(updateStatus, 2000); // 每2秒更新一次"
- " });"
- " "
- " // 页面卸载时清除定时器"
- " window.addEventListener('beforeunload', function() {"
- " clearInterval(updateInterval);"
- " });"
- " </script>"
- "</body>"
- "</html>";
- send_response(conn_fd, "text/html; charset=utf-8", html);
- close(conn_fd);
- }
- static void http_server_task(void *arg) {
- int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
- if (listen_fd < 0) {
- printf("创建 Socket 失败!\n");
- return;
- }
- struct sockaddr_in server_addr = {0};
- server_addr.sin_family = AF_INET;
- server_addr.sin_port = htons(HTTP_PORT);
- server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
- if (bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
- printf("绑定端口失败!\n");
- close(listen_fd);
- return;
- }
- if (listen(listen_fd, 5) < 0) {
- printf("监听失败!\n");
- close(listen_fd);
- return;
- }
- printf("智能浇水系统已启动!\n");
- printf("请连接 Wi-Fi: %s, 密码: %s\n", AP_SSID, AP_PASSWORD);
- printf("然后访问: http://192.168.237.1\n");
- while (1) {
- struct sockaddr_in client_addr;
- socklen_t len = sizeof(client_addr);
- int conn_fd = accept(listen_fd, (struct sockaddr *)&client_addr, &len);
- if (conn_fd >= 0) {
- printf("客户端连接: %s\n", inet_ntoa(client_addr.sin_addr));
- http_server_serve(conn_fd);
- }
- /* 在主循环中处理自动浇水任务 */
- auto_watering_task();
- system_led_toggle();
- delay_1ms(100); /* 短暂延时 */
- }
- }
- static void system_monitor_task(void *param) {
- while(1) {
- auto_watering_task();
- system_led_toggle();
- delay_1ms(1000); /* 1秒间隔 */
- }
- }
- static void wifi_ap_task(void *param) {
- printf("正在启动智能浇水系统 AP...\n");
- int ret = wifi_management_ap_start((char *)AP_SSID, (char *)AP_PASSWORD, 1, AUTH_MODE_WPA_WPA2, 0);
- if (ret != 0) {
- printf("AP 启动失败!错误码: %d\n", ret);
- sys_task_delete(NULL);
- return;
- }
- printf("AP 启动成功: %s\n", AP_SSID);
- /* 初始化硬件 */
- hardware_init();
- /* 创建系统监控任务 */
- sys_task_create_dynamic((const uint8_t *)"monitor_task", 2048, OS_TASK_PRIORITY(1), system_monitor_task, NULL);
- /* 启动HTTP服务器 */
- http_server_task(NULL);
- sys_task_delete(NULL);
- }
- int main(void) {
- platform_init();
- if (wifi_init()) {
- printf("Wi-Fi 初始化失败!\n");
- while (1);
- }
- /* 创建AP任务 */
- sys_task_create_dynamic((const uint8_t *)"ap_task", 4096, OS_TASK_PRIORITY(0), wifi_ap_task, NULL);
- sys_os_start();
- while (1);
- }
主要新增功能:土壤湿度检测 - 实时读取并显示湿度值水位检测 - 监测水位状态,低水位时自动停止浇水三种工作模式:🤖 自动模式:根据湿度自动控制⏰ 定时模式:设置定时浇水👆 手动模式:远程手动控制实时状态显示 - 湿度进度条、水位警告、倒计时等响应式界面 - 美观的现代化UI设计使用说明:编译烧录后,设备会创建WiFi热点 SmartWatering_AP手机连接该热点,密码 12345678浏览器访问 http://192.168.237.1实时监控土壤湿度和系统状态远程控制浇水模式和定时设置硬件连接建议:水泵继电器 → PB2土壤湿度传感器 → ADC0通道0 (PA0)水位传感器 → PA1状态LED → PB0这个系统具备了您需要的所有功能,界面美观易用,适合实际部署使用!可惜这不知道哪里有问题,元宝也解决不了。
在画个板子整合的好看点,可惜俺是新人得一点点学,ai给的代码总是有问题,第一次测试的时候是能用的,我后面重新烧录之后就出现通电就掉wifi,继电器持续运行等问题,只能以后有空再解决,简单的功能是勉强实现了
以下是我最后能用的简化版,还有一些调整其他文件,可能这就是造成我第二次无法使用的原因。
- /*!
- \file main.c
- \brief GD32VW553 SoftAP + 中文 Captive Portal + 无刷新 水泵控制
- \author 作者我爱小易
- \company 萤火工场
- */
- #include <stdint.h>
- #include <stdio.h>
- #include <string.h>
- #include "gd32vw55x.h"
- #include "app_cfg.h"
- #include "gd32vw55x_platform.h"
- #include "lwip/sockets.h"
- #include "lwip/priv/sockets_priv.h"
- #include "wifi_management.h"
- #include "wifi_init.h"
- #define PUMP_PORT GPIOB
- #define PUMP_PIN GPIO_PIN_2
- #define AP_SSID "GD32_PUMP_AP"
- #define AP_PASSWORD "12345678"
- #define HTTP_PORT 80
- void pump_init(void) {
- rcu_periph_clock_enable(RCU_GPIOB);
- gpio_mode_set(PUMP_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, PUMP_PIN);
- gpio_output_options_set(PUMP_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, PUMP_PIN);
- gpio_bit_reset(PUMP_PORT, PUMP_PIN); // 初始状态关闭水泵
- }
- void pump_on(void) {
- gpio_bit_set(PUMP_PORT, PUMP_PIN);
- printf("水泵开启\n");
- }
- void pump_off(void) {
- gpio_bit_reset(PUMP_PORT, PUMP_PIN);
- printf("水泵关闭\n");
- }
- // 解析 URL 参数
- int get_query_param(const char* request, const char* key, char* value, size_t val_size) {
- const char* query_start = strchr(request, '?');
- if (!query_start) return 0;
- const char* key_pos = strstr(query_start, key);
- if (!key_pos) return 0;
- const char* eq = strchr(key_pos, '=');
- if (!eq) return 0;
- eq++;
- const char* end = eq;
- while (*end && *end != ' ' && *end != '\r' && *end != '&' && *end != '\n') {
- end++;
- }
- size_t len = (end - eq) < (val_size - 1) ? (end - eq) : (val_size - 1);
- memcpy(value, eq, len);
- value[len] = '\0';
- return 1;
- }
- // 发送 HTTP 响应
- void send_response(int fd, const char* content_type, const char* body) {
- char header[256];
- int len = strlen(body);
- snprintf(header, sizeof(header),
- "HTTP/1.1 200 OK\r\n"
- "Content-Type: %s\r\n"
- "Content-Length: %d\r\n"
- "Connection: close\r\n"
- "\r\n", content_type, len);
- write(fd, header, strlen(header));
- write(fd, body, len);
- }
- static void http_server_serve(int conn_fd) {
- char buffer[1024];
- int len = read(conn_fd, buffer, sizeof(buffer) - 1);
- if (len <= 0) {
- close(conn_fd);
- return;
- }
- buffer[len] = '\0';
- printf("请求: %.100s\n", buffer);
- // 处理 API:/api/control?action=on/off
- if (strncmp(buffer, "GET /api/control", 16) == 0) {
- char action[16] = {0};
- if (get_query_param(buffer, "action", action, sizeof(action))) {
- if (strcmp(action, "on") == 0) {
- pump_on();
- } else if (strcmp(action, "off") == 0) {
- pump_off();
- }
- }
- const char* status = gpio_input_bit_get(PUMP_PORT, PUMP_PIN) ? "on" : "off";
- char json[64];
- snprintf(json, sizeof(json), "{"status":"%s"}", status);
- send_response(conn_fd, "application/json", json);
- close(conn_fd);
- return;
- }
- // 返回中文美化页面(修改后)
- const char* html =
- "<!DOCTYPE html>"
- "<html lang="zh-CN">"
- "<head>"
- " <meta charset="UTF-8">"
- " <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">"
- " <title>GD32VW553 水泵远程控制</title>"
- " <style>"
- " body {"
- " margin: 0; padding: 0;"
- " font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;"
- " background: #ffffff;"
- " height: 100vh; display: flex; flex-direction: column; justify-content: center; align-items: center;"
- " color: #2c3e50; text-align: center;"
- " }"
- " .container { "
- " padding: 40px 30px; "
- " max-width: 480px; "
- " background: #f8f9fa;"
- " border-radius: 20px;"
- " box-shadow: 0 10px 30px rgba(0,0,0,0.08);"
- " }"
- " h1 { font-size: 32px; margin: 10px 0; color: #2c3e50; font-weight: 700; }"
- " .subtitle { font-size: 16px; opacity: 0.7; margin-bottom: 30px; color: #5a6c7d; }"
- " .pump-status { "
- " width: 140px; height: 140px; border-radius: 50%; margin: 30px auto; "
- " transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); "
- " display: flex; align-items: center; justify-content: center; "
- " font-size: 60px; border: 3px solid #e9ecef;"
- " }"
- " .pump-status.on { "
- " background: linear-gradient(135deg, #00b894, #00a085); "
- " box-shadow: 0 10px 25px rgba(0, 184, 148, 0.3); "
- " border-color: #00b894;"
- " }"
- " .pump-status.off { "
- " background: linear-gradient(135deg, #dfe6e9, #b2bec3); "
- " box-shadow: 0 10px 25px rgba(0, 0, 0, 0.05); "
- " border-color: #dfe6e9;"
- " }"
- " .status { font-size: 24px; margin: 20px 0; font-weight: 600; color: #2c3e50; }"
- " .btn {"
- " display: block; width: 100%; padding: 20px;"
- " font-size: 20px; font-weight: 600; border: none; border-radius: 15px;"
- " background: linear-gradient(135deg, #3498db, #2980b9);"
- " color: white; cursor: pointer; margin-top: 25px;"
- " transition: all 0.3s ease;"
- " box-shadow: 0 5px 15px rgba(52, 152, 219, 0.3);"
- " letter-spacing: 1px;"
- " }"
- " .btn.on { "
- " background: linear-gradient(135deg, #00b894, #00a085);"
- " box-shadow: 0 5px 15px rgba(0, 184, 148, 0.3);"
- " }"
- " .btn.off { "
- " background: linear-gradient(135deg, #e74c3c, #c0392b);"
- " box-shadow: 0 5px 15px rgba(231, 76, 60, 0.3);"
- " }"
- " .btn:hover { "
- " transform: translateY(-2px); "
- " box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);"
- " }"
- " .btn:active { transform: translateY(0); }"
- " .footer { margin-top: 25px; font-size: 14px; opacity: 0.6; color: #7f8c8d; }"
- " .warning { "
- " background: #fff3cd; padding: 12px; border-radius: 10px; "
- " margin: 20px 0; font-size: 14px; color: #856404;"
- " border-left: 4px solid #ffc107;"
- " }"
- " [url=/u/media]@media[/url] (max-width: 480px) {"
- " .container { padding: 30px 20px; margin: 20px; }"
- " h1 { font-size: 28px; }"
- " .pump-status { width: 120px; height: 120px; font-size: 50px; }"
- " }"
- " </style>"
- "</head>"
- "<body>"
- " <div class="container">"
- " <h1>GD32VW553 水泵远程控制</h1>"
- " <div class="subtitle">作者:我爱小易|出品:萤火工场</div>"
- " <div id="pumpStatus" class="pump-status off">💧</div>"
- " <div id="status" class="status">水泵状态:关闭</div>"
- " <div class="warning">⚠️ 远程控制水泵,请确保安全操作</div>"
- " <button id="controlBtn" class="btn off">启动水泵</button>"
- " <div class="footer">连接开发板 Wi-Fi 即可远程控制</div>"
- " </div>"
- ""
- " <script>"
- " let isPumpOn = false;"
- ""
- " function updateUI() {"
- " const pumpStatus = document.getElementById('pumpStatus');"
- " const status = document.getElementById('status');"
- " const btn = document.getElementById('controlBtn');"
- " if (isPumpOn) {"
- " pumpStatus.className = 'pump-status on';"
- " pumpStatus.textContent = '💦';"
- " status.textContent = '水泵状态:运行中';"
- " btn.textContent = '停止水泵';"
- " btn.className = 'btn on';"
- " } else {"
- " pumpStatus.className = 'pump-status off';"
- " pumpStatus.textContent = '💧';"
- " status.textContent = '水泵状态:关闭';"
- " btn.textContent = '启动水泵';"
- " btn.className = 'btn off';"
- " }"
- " }"
- ""
- " function sendAction(action) {"
- " fetch('/api/control?action=' + action)"
- " .then(res => res.json())"
- " .then(data => {"
- " isPumpOn = (data.status === 'on');"
- " updateUI();"
- " })"
- " .catch(err => console.error('请求失败:', err));"
- " }"
- ""
- " document.getElementById('controlBtn').addEventListener('click', () => {"
- " sendAction(isPumpOn ? 'off' : 'on');"
- " });"
- ""
- " // 初始化:获取当前状态"
- " fetch('/api/control?action=get')"
- " .then(res => res.json())"
- " .then(data => {"
- " isPumpOn = (data.status === 'on');"
- " updateUI();"
- " });"
- " </script>"
- "</body>"
- "</html>";
- send_response(conn_fd, "text/html; charset=utf-8", html);
- close(conn_fd);
- }
- static void http_server_task(void *arg) {
- int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
- if (listen_fd < 0) {
- printf("创建 Socket 失败!\n");
- return;
- }
- struct sockaddr_in server_addr = {0};
- server_addr.sin_family = AF_INET;
- server_addr.sin_port = htons(HTTP_PORT);
- server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
- if (bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
- printf("绑定端口失败!\n");
- close(listen_fd);
- return;
- }
- if (listen(listen_fd, 5) < 0) {
- printf("监听失败!\n");
- close(listen_fd);
- return;
- }
- printf("HTTP 服务器已启动,请连接 Wi-Fi 后访问 http://192.168.237.1\n");
- while (1) {
- struct sockaddr_in client_addr;
- socklen_t len = sizeof(client_addr);
- int conn_fd = accept(listen_fd, (struct sockaddr *)&client_addr, &len);
- if (conn_fd >= 0) {
- printf("客户端已连接:%s\n", inet_ntoa(client_addr.sin_addr));
- http_server_serve(conn_fd);
- }
- }
- }
- static void wifi_ap_task(void *param) {
- printf("正在启动 SoftAP:%s ...\n", AP_SSID);
- int ret = wifi_management_ap_start((char *)AP_SSID, (char *)AP_PASSWORD, 1, AUTH_MODE_WPA_WPA2, 0);
- if (ret != 0) {
- printf("SoftAP 启动失败!错误码:%d\n", ret);
- sys_task_delete(NULL);
- return;
- }
- printf("SoftAP 已启动,SSID:%s,密码:%s\n", AP_SSID, AP_PASSWORD);
- pump_init();
- http_server_task(NULL);
- sys_task_delete(NULL);
- }
- int main(void) {
- platform_init();
- if (wifi_init()) {
- printf("Wi-Fi 初始化失败!\n");
- while (1);
- }
- sys_task_create_dynamic((const uint8_t *)"ap_task", 4096, OS_TASK_PRIORITY(0), wifi_ap_task, NULL);
- sys_os_start();
- while (1);
- }
总结,这个板子是一款很适合新人尝试的开发板,可惜成熟的项目还是太少,相对主流板子,希望以后优秀的项目能越来越多