/** * @file main.c * @brief EDC 步进电机网页控制 (ESP-IDF) * * 硬件接线: * ESP32 TX (GPIO6) -> 电机 RX * ESP32 RX (GPIO7) -> 电机 TX * ESP32 GPIO5 -> 电磁铁 * ESP32 GPIO4 -> 舵机 * ESP32 GPIO11 -> 协议 UART TX (→ MPU) (UART0) * ESP32 GPIO12 -> 协议 UART RX (← MPU) (UART0) * ESP32 GPIO2 -> I2C SDA (← MPU) * ESP32 GPIO3 -> I2C SCL * ESP32 GPIO27 -> RGB LED (WS2812) * ESP32 GPIO8 -> 按钮 (低电平有效, 触发识别) * ESP32 GPIO9 -> 无源蜂鸣器 (经三极管驱动) * ESP32 GND -> 电机 GND / MPU GND * * 注: 日志控制台已切换到 USB Serial/JTAG (COM 口监视), * UART0 (GPIO11/12) 专用于 MPU 协议通讯。 * * WiFi: 连接 ICE (密码 12345678), 获取 IP 后用浏览器打开控制页面 */ #include "magnet.h" #include "servo.h" #include "web_ctrl.h" #include "protocol.h" #include "rgb.h" #include "actuator.h" #include "key.h" #include "buzzer.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_log.h" static const char *TAG = "MAIN"; /* ---- 按钮识别任务 ---- */ #define RECOGNIZE_TIMEOUT_MS 20000 #define RECOGNIZE_POLL_MS 100 /* 归零速度: XY 用 ACTUATOR_EXEC_VEL/ACC (3000/250), Z 用 ACTUATOR_EXEC_Z_VEL/Z_ACC (低速); 到位等待: 轮询闭环到位标志, 超时按最大行程 + 裕量兜底 */ static void button_recognize_task(void *pvParam) { while (1) { if (key_is_pressed()) { ESP_LOGI(TAG, "按钮按下, 先发 TASK_START (MPU 开始计时) ..."); buzzer_beep(2000, 100); /* 短音: 识别开始 */ /* 按下按钮即通知 MPU 任务开始计时 (与 RECOGNIZE 区分, 不触发识别) */ edc_proto_send_task_start(); /* ---- 归零: 舵机抬起 + Z/X/Y 三轴并行回零 ---- Cycle 执行完成后也会调用 actuator_home_all() 置零 */ actuator_home_all(); ESP_LOGI(TAG, "归零完成, 发送 RECOGNIZE ..."); /* 清除旧 Cycle 记录 */ actuator_clear_last_cycle(); /* 发送识别指令 */ edc_proto_send_recognize(); /* 等待 MPU 回传 Cycle, 超时则发送 REQUEST */ bool got_cycle = false; int loops = RECOGNIZE_TIMEOUT_MS / RECOGNIZE_POLL_MS; for (int i = 0; i < loops; i++) { vTaskDelay(pdMS_TO_TICKS(RECOGNIZE_POLL_MS)); if (actuator_is_last_cycle_valid()) { got_cycle = true; ESP_LOGI(TAG, "RECOGNIZE 成功, 已收到 Cycle"); buzzer_beep_twice(2000, 150); /* 双短音: 识别成功 */ break; } } if (!got_cycle) { ESP_LOGW(TAG, "RECOGNIZE 超时 (%d ms), 发送 CYCLE_REQUEST", RECOGNIZE_TIMEOUT_MS); buzzer_beep(880, 500); /* 长低音: 识别失败/超时 */ edc_proto_send_request(); } } vTaskDelay(pdMS_TO_TICKS(50)); } } void app_main(void) { /* 初始化 RGB LED (GPIO27, 最先启动, 指示系统状态) */ rgb_init(GPIO_NUM_27); rgb_set(32, 32, 0); /* 黄色 (低亮), 表示启动中 */ /* 初始化执行器 (步进电机 + 舵机) */ actuator_init(); /* 初始化电磁铁 (GPIO5) */ magnet_init(GPIO_NUM_5); /* 初始化按钮 (GPIO8, 低电平有效, 触发识别) */ key_init(GPIO_NUM_8); /* 初始化无源蜂鸣器 (GPIO9, 提示音) */ buzzer_init(GPIO_NUM_9); /* 初始化通讯协议 (I2C 从机 GPIO2/3 + UART0 GPIO11/12) */ edc_proto_init(NULL); /* 启动协议接收任务 */ xTaskCreate(edc_proto_task, "proto", 4096, NULL, 2, NULL); /* 启动按钮识别任务 */ xTaskCreate(button_recognize_task, "btn", 2048, NULL, 1, NULL); /* 上电延时 2 秒, 等待电机闭环初始化完毕 */ ESP_LOGI(TAG, "等待电机初始化..."); vTaskDelay(pdMS_TO_TICKS(2000)); /* 启动 WiFi + HTTP 网页控制服务器 */ web_ctrl_init(); /* 系统就绪: 黄灯 (低亮) */ rgb_set(32, 32, 0); rgb_set_state(RGB_STATE_IDLE); buzzer_beep(2000, 120); /* 启动/就绪: 短促一声 */ ESP_LOGI(TAG, "系统就绪, 等待网页指令..."); /* 结束提示: 每轮只响一次, 防止慢闪循环重复响 */ bool done_beeped = false; while (1) { /* 根据系统状态选择闪烁颜色 */ rgb_state_t st = rgb_get_state(); if (st == RGB_STATE_DONE) { /* 绿灯慢闪: Cycle 执行完毕 */ if (!done_beeped) { buzzer_beep_triple(2000, 100); /* 执行结束: 急促三响 */ done_beeped = true; } rgb_set(0, 32, 0); } else { /* 黄灯慢闪: 待机 */ done_beeped = false; rgb_set(32, 32, 0); } vTaskDelay(pdMS_TO_TICKS(500)); rgb_off(); vTaskDelay(pdMS_TO_TICKS(500)); } }