蜂鸣器+RGB修复
This commit is contained in:
1 parent
fef37b36e9
commit
351e22e123
7 files changed
+205
-1
No files matched your search
@@ -506,6 +506,9 @@ void edc_proto_on_cycle(const edc_cycle_t *cycle, edc_channel_t ch)
|
|||||||
}
|
}
|
||||||
s_last_exec_id = cycle->cycle_id;
|
s_last_exec_id = cycle->cycle_id;
|
||||||
|
|
||||||
|
/* 新一轮执行开始: 复位 RGB 状态 (执行期间 _wait_flash 显示红灯) */
|
||||||
|
rgb_set_state(RGB_STATE_IDLE);
|
||||||
|
|
||||||
/* 执行电机运动 (阻塞, 含拾放全流程) */
|
/* 执行电机运动 (阻塞, 含拾放全流程) */
|
||||||
ESP_LOGI(TAG, "开始执行 Cycle #%u ...", cycle->cycle_id);
|
ESP_LOGI(TAG, "开始执行 Cycle #%u ...", cycle->cycle_id);
|
||||||
actuator_execute_cycle(cycle);
|
actuator_execute_cycle(cycle);
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
idf_component_register(SRCS "buzzer.c"
|
||||||
|
INCLUDE_DIRS "."
|
||||||
|
REQUIRES esp_driver_ledc esp_driver_gpio driver)
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
/**
|
||||||
|
* @file buzzer.c
|
||||||
|
* @brief 无源蜂鸣器控制实现 (LEDC PWM)
|
||||||
|
*
|
||||||
|
* 无源蜂鸣器需要外部提供音频频率的方波才能发声, 不能像有源蜂鸣器那样
|
||||||
|
* 直接给高电平。这里用 LEDC 在独立定时器上产生可变频率的 50% 占空比方波。
|
||||||
|
*
|
||||||
|
* 资源分配 (与 servo 错开):
|
||||||
|
* servo : LEDC_TIMER_0 / LEDC_CHANNEL_0 (50Hz 固定)
|
||||||
|
* buzzer : LEDC_TIMER_1 / LEDC_CHANNEL_2 (音频频率, 可动态改频)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "buzzer.h"
|
||||||
|
#include "driver/ledc.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
|
||||||
|
#define BUZZER_TIMER LEDC_TIMER_1
|
||||||
|
#define BUZZER_MODE LEDC_LOW_SPEED_MODE
|
||||||
|
#define BUZZER_CHANNEL LEDC_CHANNEL_2
|
||||||
|
#define BUZZER_DUTY_RES LEDC_TIMER_10_BIT /* 0~1023, 允许更高频率 */
|
||||||
|
#define BUZZER_MAX_DUTY 1023
|
||||||
|
#define BUZZER_DEFAULT_FREQ_HZ 4000
|
||||||
|
|
||||||
|
static const char *TAG = "BUZZER";
|
||||||
|
static bool s_initialized = false;
|
||||||
|
static uint32_t s_freq_hz = 0;
|
||||||
|
|
||||||
|
void buzzer_init(int gpio)
|
||||||
|
{
|
||||||
|
ledc_timer_config_t timer_cfg = {
|
||||||
|
.speed_mode = BUZZER_MODE,
|
||||||
|
.duty_resolution = BUZZER_DUTY_RES,
|
||||||
|
.timer_num = BUZZER_TIMER,
|
||||||
|
.freq_hz = BUZZER_DEFAULT_FREQ_HZ,
|
||||||
|
.clk_cfg = LEDC_AUTO_CLK,
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK(ledc_timer_config(&timer_cfg));
|
||||||
|
|
||||||
|
ledc_channel_config_t chan_cfg = {
|
||||||
|
.gpio_num = gpio,
|
||||||
|
.speed_mode = BUZZER_MODE,
|
||||||
|
.channel = BUZZER_CHANNEL,
|
||||||
|
.intr_type = LEDC_INTR_DISABLE,
|
||||||
|
.timer_sel = BUZZER_TIMER,
|
||||||
|
.duty = 0, /* 默认静音 */
|
||||||
|
.hpoint = 0,
|
||||||
|
.flags.output_invert = 0,
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK(ledc_channel_config(&chan_cfg));
|
||||||
|
|
||||||
|
s_initialized = true;
|
||||||
|
s_freq_hz = BUZZER_DEFAULT_FREQ_HZ;
|
||||||
|
ESP_LOGI(TAG, "初始化完成 (GPIO%d, 通道%d)", gpio, BUZZER_CHANNEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void buzzer_set_freq(uint32_t freq_hz)
|
||||||
|
{
|
||||||
|
if (!s_initialized || freq_hz == 0) return;
|
||||||
|
if (freq_hz == s_freq_hz) return;
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(ledc_set_freq(BUZZER_MODE, BUZZER_TIMER, freq_hz));
|
||||||
|
s_freq_hz = freq_hz;
|
||||||
|
ESP_LOGD(TAG, "频率: %lu Hz", (unsigned long)freq_hz);
|
||||||
|
}
|
||||||
|
|
||||||
|
void buzzer_on(uint32_t freq_hz)
|
||||||
|
{
|
||||||
|
if (!s_initialized) return;
|
||||||
|
|
||||||
|
buzzer_set_freq(freq_hz);
|
||||||
|
ESP_ERROR_CHECK(ledc_set_duty(BUZZER_MODE, BUZZER_CHANNEL, BUZZER_MAX_DUTY / 2));
|
||||||
|
ESP_ERROR_CHECK(ledc_update_duty(BUZZER_MODE, BUZZER_CHANNEL));
|
||||||
|
}
|
||||||
|
|
||||||
|
void buzzer_off(void)
|
||||||
|
{
|
||||||
|
if (!s_initialized) return;
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(ledc_set_duty(BUZZER_MODE, BUZZER_CHANNEL, 0));
|
||||||
|
ESP_ERROR_CHECK(ledc_update_duty(BUZZER_MODE, BUZZER_CHANNEL));
|
||||||
|
}
|
||||||
|
|
||||||
|
void buzzer_beep(uint32_t freq_hz, uint32_t duration_ms)
|
||||||
|
{
|
||||||
|
buzzer_on(freq_hz);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(duration_ms));
|
||||||
|
buzzer_off();
|
||||||
|
}
|
||||||
|
|
||||||
|
void buzzer_beep_twice(uint32_t freq_hz, uint32_t duration_ms)
|
||||||
|
{
|
||||||
|
buzzer_beep(freq_hz, duration_ms);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(120));
|
||||||
|
buzzer_beep(freq_hz, duration_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
void buzzer_beep_triple(uint32_t freq_hz, uint32_t duration_ms)
|
||||||
|
{
|
||||||
|
buzzer_beep(freq_hz, duration_ms);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(120));
|
||||||
|
buzzer_beep(freq_hz, duration_ms);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(120));
|
||||||
|
buzzer_beep(freq_hz, duration_ms);
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* @file buzzer.h
|
||||||
|
* @brief 无源蜂鸣器控制 (LEDC PWM 音调)
|
||||||
|
*
|
||||||
|
* 硬件建议 (无源蜂鸣器电流较大, 建议用 NPN 三极管驱动):
|
||||||
|
* ESP32 GPIO ──[1kΩ]── S8050 基极
|
||||||
|
* 蜂鸣器 + → 5V (或 3.3V)
|
||||||
|
* 蜂鸣器 − → 三极管集电极
|
||||||
|
* 三极管发射极 → GND
|
||||||
|
* (磁式蜂鸣器可在两端并联 1N4148 续流二极管)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BUZZER_H
|
||||||
|
#define BUZZER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化无源蜂鸣器 (LEDC 独立定时器/通道)
|
||||||
|
* @param gpio GPIO 引脚号, 如 GPIO_NUM_13
|
||||||
|
*/
|
||||||
|
void buzzer_init(int gpio);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 开始发声
|
||||||
|
* @param freq_hz 频率 (Hz), 常用 2000~4000
|
||||||
|
*/
|
||||||
|
void buzzer_on(uint32_t freq_hz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 停止发声 (静音)
|
||||||
|
*/
|
||||||
|
void buzzer_off(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置音调频率 (不改变发声状态)
|
||||||
|
*/
|
||||||
|
void buzzer_set_freq(uint32_t freq_hz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 阻塞式响一声 (需在任务中调用)
|
||||||
|
* @param freq_hz 频率 (Hz)
|
||||||
|
* @param duration_ms 时长 (ms)
|
||||||
|
*/
|
||||||
|
void buzzer_beep(uint32_t freq_hz, uint32_t duration_ms);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 阻塞式响两声 (确认提示音)
|
||||||
|
*/
|
||||||
|
void buzzer_beep_twice(uint32_t freq_hz, uint32_t duration_ms);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 阻塞式急促响三声 (执行完成提示音)
|
||||||
|
*/
|
||||||
|
void buzzer_beep_triple(uint32_t freq_hz, uint32_t duration_ms);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* BUZZER_H */
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "driver/rmt_tx.h"
|
#include "driver/rmt_tx.h"
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/semphr.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
static const char *TAG = "RGB";
|
static const char *TAG = "RGB";
|
||||||
@@ -145,17 +146,24 @@ static esp_err_t rmt_new_led_strip_encoder(rmt_encoder_handle_t *ret_encoder)
|
|||||||
|
|
||||||
static rmt_channel_handle_t s_led_chan = NULL;
|
static rmt_channel_handle_t s_led_chan = NULL;
|
||||||
static rmt_encoder_handle_t s_led_encoder = NULL;
|
static rmt_encoder_handle_t s_led_encoder = NULL;
|
||||||
|
static SemaphoreHandle_t s_lock = NULL; /* 串行化 RMT 访问 */
|
||||||
|
|
||||||
/* ── 内部: 发送 GRB 数据 ── */
|
/* ── 内部: 发送 GRB 数据 ── */
|
||||||
|
|
||||||
static void rgb_transmit(uint8_t g, uint8_t r, uint8_t b)
|
static void rgb_transmit(uint8_t g, uint8_t r, uint8_t b)
|
||||||
{
|
{
|
||||||
|
if (!s_led_chan || !s_lock) return;
|
||||||
|
|
||||||
uint8_t grb[3] = { g, r, b };
|
uint8_t grb[3] = { g, r, b };
|
||||||
|
|
||||||
|
/* main 循环与 Cycle 执行 (_wait_flash) 会从不同任务调用本函数,
|
||||||
|
必须互斥, 否则并发操作同一 RMT 通道会导致绿灯丢失甚至复位 */
|
||||||
|
xSemaphoreTake(s_lock, portMAX_DELAY);
|
||||||
rmt_transmit_config_t tx_config = { .loop_count = 0 };
|
rmt_transmit_config_t tx_config = { .loop_count = 0 };
|
||||||
ESP_ERROR_CHECK(rmt_transmit(s_led_chan, s_led_encoder,
|
ESP_ERROR_CHECK(rmt_transmit(s_led_chan, s_led_encoder,
|
||||||
grb, sizeof(grb), &tx_config));
|
grb, sizeof(grb), &tx_config));
|
||||||
ESP_ERROR_CHECK(rmt_tx_wait_all_done(s_led_chan, portMAX_DELAY));
|
ESP_ERROR_CHECK(rmt_tx_wait_all_done(s_led_chan, portMAX_DELAY));
|
||||||
|
xSemaphoreGive(s_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── 公开接口 ── */
|
/* ── 公开接口 ── */
|
||||||
@@ -167,6 +175,8 @@ void rgb_init(int gpio)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s_lock = xSemaphoreCreateMutex();
|
||||||
|
|
||||||
rmt_tx_channel_config_t tx_chan_config = {
|
rmt_tx_channel_config_t tx_chan_config = {
|
||||||
.clk_src = RMT_CLK_SRC_DEFAULT,
|
.clk_src = RMT_CLK_SRC_DEFAULT,
|
||||||
.gpio_num = gpio,
|
.gpio_num = gpio,
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
idf_component_register(SRCS "main.c"
|
idf_component_register(SRCS "main.c"
|
||||||
INCLUDE_DIRS "."
|
INCLUDE_DIRS "."
|
||||||
PRIV_REQUIRES emm_v5 magnet servo key web_ctrl protocol rgb actuator)
|
PRIV_REQUIRES emm_v5 magnet servo key web_ctrl protocol rgb actuator buzzer)
|
||||||
|
|
||||||
# 调试开关: 启用 WiFi + Web 服务器 (消除 IDE 未定义警告)
|
# 调试开关: 启用 WiFi + Web 服务器 (消除 IDE 未定义警告)
|
||||||
target_compile_definitions(${COMPONENT_LIB} PRIVATE EDC_DEBUG_WEB)
|
target_compile_definitions(${COMPONENT_LIB} PRIVATE EDC_DEBUG_WEB)
|
||||||
+17
@@ -13,6 +13,7 @@
|
|||||||
* ESP32 GPIO3 -> I2C SCL
|
* ESP32 GPIO3 -> I2C SCL
|
||||||
* ESP32 GPIO27 -> RGB LED (WS2812)
|
* ESP32 GPIO27 -> RGB LED (WS2812)
|
||||||
* ESP32 GPIO8 -> 按钮 (低电平有效, 触发识别)
|
* ESP32 GPIO8 -> 按钮 (低电平有效, 触发识别)
|
||||||
|
* ESP32 GPIO9 -> 无源蜂鸣器 (经三极管驱动)
|
||||||
* ESP32 GND -> 电机 GND / MPU GND
|
* ESP32 GND -> 电机 GND / MPU GND
|
||||||
*
|
*
|
||||||
* 注: 日志控制台已切换到 USB Serial/JTAG (COM 口监视),
|
* 注: 日志控制台已切换到 USB Serial/JTAG (COM 口监视),
|
||||||
@@ -29,6 +30,7 @@
|
|||||||
#include "rgb.h"
|
#include "rgb.h"
|
||||||
#include "actuator.h"
|
#include "actuator.h"
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
|
#include "buzzer.h"
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
@@ -46,6 +48,7 @@ static void button_recognize_task(void *pvParam)
|
|||||||
while (1) {
|
while (1) {
|
||||||
if (key_is_pressed()) {
|
if (key_is_pressed()) {
|
||||||
ESP_LOGI(TAG, "按钮按下, 归零后再发送 RECOGNIZE ...");
|
ESP_LOGI(TAG, "按钮按下, 归零后再发送 RECOGNIZE ...");
|
||||||
|
buzzer_beep(2000, 100); /* 短音: 识别开始 */
|
||||||
|
|
||||||
/* ---- 归零: 舵机抬起 + Z 回 0° (低速, 最坏行程 270°) ---- */
|
/* ---- 归零: 舵机抬起 + Z 回 0° (低速, 最坏行程 270°) ---- */
|
||||||
actuator_servo_up();
|
actuator_servo_up();
|
||||||
@@ -86,6 +89,7 @@ static void button_recognize_task(void *pvParam)
|
|||||||
if (actuator_is_last_cycle_valid()) {
|
if (actuator_is_last_cycle_valid()) {
|
||||||
got_cycle = true;
|
got_cycle = true;
|
||||||
ESP_LOGI(TAG, "RECOGNIZE 成功, 已收到 Cycle");
|
ESP_LOGI(TAG, "RECOGNIZE 成功, 已收到 Cycle");
|
||||||
|
buzzer_beep_twice(2000, 150); /* 双短音: 识别成功 */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,6 +97,7 @@ static void button_recognize_task(void *pvParam)
|
|||||||
if (!got_cycle) {
|
if (!got_cycle) {
|
||||||
ESP_LOGW(TAG, "RECOGNIZE 超时 (%d ms), 发送 CYCLE_REQUEST",
|
ESP_LOGW(TAG, "RECOGNIZE 超时 (%d ms), 发送 CYCLE_REQUEST",
|
||||||
RECOGNIZE_TIMEOUT_MS);
|
RECOGNIZE_TIMEOUT_MS);
|
||||||
|
buzzer_beep(880, 500); /* 长低音: 识别失败/超时 */
|
||||||
edc_proto_send_request();
|
edc_proto_send_request();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,6 +120,9 @@ void app_main(void)
|
|||||||
/* 初始化按钮 (GPIO8, 低电平有效, 触发识别) */
|
/* 初始化按钮 (GPIO8, 低电平有效, 触发识别) */
|
||||||
key_init(GPIO_NUM_8);
|
key_init(GPIO_NUM_8);
|
||||||
|
|
||||||
|
/* 初始化无源蜂鸣器 (GPIO9, 提示音) */
|
||||||
|
buzzer_init(GPIO_NUM_9);
|
||||||
|
|
||||||
/* 初始化通讯协议 (I2C 从机 GPIO2/3 + UART0 GPIO11/12) */
|
/* 初始化通讯协议 (I2C 从机 GPIO2/3 + UART0 GPIO11/12) */
|
||||||
edc_proto_init(NULL);
|
edc_proto_init(NULL);
|
||||||
|
|
||||||
@@ -134,16 +142,25 @@ void app_main(void)
|
|||||||
/* 系统就绪: 黄灯 (低亮) */
|
/* 系统就绪: 黄灯 (低亮) */
|
||||||
rgb_set(32, 32, 0);
|
rgb_set(32, 32, 0);
|
||||||
rgb_set_state(RGB_STATE_IDLE);
|
rgb_set_state(RGB_STATE_IDLE);
|
||||||
|
buzzer_beep(2000, 120); /* 启动/就绪: 短促一声 */
|
||||||
ESP_LOGI(TAG, "系统就绪, 等待网页指令...");
|
ESP_LOGI(TAG, "系统就绪, 等待网页指令...");
|
||||||
|
|
||||||
|
/* 结束提示: 每轮只响一次, 防止慢闪循环重复响 */
|
||||||
|
bool done_beeped = false;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
/* 根据系统状态选择闪烁颜色 */
|
/* 根据系统状态选择闪烁颜色 */
|
||||||
rgb_state_t st = rgb_get_state();
|
rgb_state_t st = rgb_get_state();
|
||||||
if (st == RGB_STATE_DONE) {
|
if (st == RGB_STATE_DONE) {
|
||||||
/* 绿灯慢闪: Cycle 执行完毕 */
|
/* 绿灯慢闪: Cycle 执行完毕 */
|
||||||
|
if (!done_beeped) {
|
||||||
|
buzzer_beep_triple(2000, 100); /* 执行结束: 急促三响 */
|
||||||
|
done_beeped = true;
|
||||||
|
}
|
||||||
rgb_set(0, 32, 0);
|
rgb_set(0, 32, 0);
|
||||||
} else {
|
} else {
|
||||||
/* 黄灯慢闪: 待机 */
|
/* 黄灯慢闪: 待机 */
|
||||||
|
done_beeped = false;
|
||||||
rgb_set(32, 32, 0);
|
rgb_set(32, 32, 0);
|
||||||
}
|
}
|
||||||
vTaskDelay(pdMS_TO_TICKS(500));
|
vTaskDelay(pdMS_TO_TICKS(500));
|
||||||
|
|||||||
Reference in new issue
Block a user