|
@@ -0,0 +1,373 @@
|
|
|
|
|
+/*
|
|
|
|
|
+ * hw_config.c
|
|
|
|
|
+ *
|
|
|
|
|
+ * 可变化的硬件相关逻辑。
|
|
|
|
|
+ * 换 PCB / 改引脚 / 调启动流程 — 只改这个文件, ukey.c 状态机不动。
|
|
|
|
|
+ *
|
|
|
|
|
+ * 函数清单:
|
|
|
|
|
+ * GPIOA_IRQHandler — 按键 GPIO 中断
|
|
|
|
|
+ * key_handle_short_press — 按键短按次数 → 操作分发
|
|
|
|
|
+ * power_enter_sleep — 进入低功耗睡眠 / 关机
|
|
|
|
|
+ * power_boot — 上电开机硬件初始化
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+#include "hw_config.h"
|
|
|
|
|
+#include "ledx.h"
|
|
|
|
|
+#include "RF_PHY.h"
|
|
|
|
|
+#include "pindef.h"
|
|
|
|
|
+#include "ble/peripheral.h"
|
|
|
|
|
+#include "sir24drv.h"
|
|
|
|
|
+#include "hop_config.h" /* power_boot: HOP_POOL */
|
|
|
|
|
+#include "rx_hop.h" /* power_boot: rx_hop_init */
|
|
|
|
|
+#include "ukey.h" /* power_set_mode, g_power_mode, OPMODE_* */
|
|
|
|
|
+#include "hal_irq.h" /* hal_irq_dispatch_gpio: ISR 统一 dispatch + 清标志 */
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+BOOL g_power_woke_by_irq=FALSE; /* hw_config.c::power_enter_sleep 中置位, 本文件 power_request_reset 清零 */
|
|
|
|
|
+/* g_power_need_reset 定义在 ukey.c,声明见 ukey.h */
|
|
|
|
|
+__HIGH_CODE
|
|
|
|
|
+__attribute__((noinline))
|
|
|
|
|
+ void power_request_reset(){
|
|
|
|
|
+ g_power_woke_by_irq=FALSE;
|
|
|
|
|
+
|
|
|
|
|
+ //不要有延时之类的重操作,这个方法可能会在中断中执行。
|
|
|
|
|
+ /* LED 引脚 */
|
|
|
|
|
+ hal_gpio_mode_cfg(LED_PIN, GPIO_ModeOut_PP_5mA);
|
|
|
|
|
+ hal_gpio_set_low(LED_PIN);
|
|
|
|
|
+
|
|
|
|
|
+ led_pwm_init();
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ /* 声音引脚: 浮空输入 */
|
|
|
|
|
+ hal_gpio_mode_cfg(SOUND_PIN, GPIO_ModeIN_PU);
|
|
|
|
|
+
|
|
|
|
|
+ /* 声音开关: 输出低 */
|
|
|
|
|
+ hal_gpio_mode_cfg(SOUND_SW, GPIO_ModeOut_PP_5mA);
|
|
|
|
|
+ hal_gpio_set_low(SOUND_SW);
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+/* ==================== GPIO 中断 ====================
|
|
|
|
|
+ * ISR 定义仍在 hw_config.c(startup 向量表强符号),但 dispatch/清标志交给
|
|
|
|
|
+ * hal_irq_dispatch_gpio()。原引脚专属逻辑(按键唤醒、sound_hold 装载)保留:
|
|
|
|
|
+ * - dispatch 先读 IF → 入队 → 写 IF 清标志(RW1,整个端口全清)
|
|
|
|
|
+ * - 之后的 hal_gpio_read 读的是引脚实时电平,与 IF 是否已清无关
|
|
|
|
|
+ * - 原 ClearITFlagBit 那行已由 dispatch 内部清覆盖,此处不再重复写 */
|
|
|
|
|
+__INTERRUPT
|
|
|
|
|
+__HIGH_CODE
|
|
|
|
|
+void GPIOA_IRQHandler(void)
|
|
|
|
|
+{
|
|
|
|
|
+ hal_irq_dispatch_gpio(0);
|
|
|
|
|
+ /* SW_KEY 唤醒:标志已由 dispatch 清,唤醒判定走 g_power_woke_by_irq 主循环路径 */
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+#if (SOUND_TRIG_MODE == SOUND_TRIG_IRQ)
|
|
|
|
|
+/* 声控触发(中断方式):SOUND_PIN 下降沿 -> 装载保持计数,倒计时由 sound_poll() 消费 */
|
|
|
|
|
+__INTERRUPT
|
|
|
|
|
+__HIGH_CODE
|
|
|
|
|
+void GPIOB_IRQHandler(void)
|
|
|
|
|
+{
|
|
|
|
|
+ hal_irq_dispatch_gpio(1);
|
|
|
|
|
+ if (hal_gpio_read(SOUND_PIN) == 0) {
|
|
|
|
|
+ sound_hold = SOUND_ACTIVE_DURATION;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+/* ==================== 按键短按处理 ==================== */
|
|
|
|
|
+void key_handle_short_press(uint32_t key_release_tick)
|
|
|
|
|
+{
|
|
|
|
|
+ if (key_short_count > 0) {
|
|
|
|
|
+ if (RTC_GetCycle32k() - key_press_tick > KEY_SEQUENCE_TIMEOUT) {
|
|
|
|
|
+
|
|
|
|
|
+ if (key_short_count == 2) {
|
|
|
|
|
+ /* 双击: 预留(原为配对/BLE) */
|
|
|
|
|
+
|
|
|
|
|
+ } else if (key_short_count == 1 && POWER_CAN_GO_NORMAL()) {
|
|
|
|
|
+ /* 单按: 进入普通模式 */
|
|
|
|
|
+ power_set_mode(OPMODE_NORMAL);
|
|
|
|
|
+
|
|
|
|
|
+ } else if (key_short_count == 1 && g_power_mode == OPMODE_NORMAL) {
|
|
|
|
|
+ /* 普通模式下单按: 切换闪烁模式 */
|
|
|
|
|
+ if (g_rf_is_on) {
|
|
|
|
|
+ key_short_count = 0;
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ eco_reset();
|
|
|
|
|
+ led_set_next_mode();
|
|
|
|
|
+ }
|
|
|
|
|
+ key_short_count = 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+/* ==================== 进入睡眠 / 关机 ==================== */
|
|
|
|
|
+void power_enter_sleep(void)
|
|
|
|
|
+{
|
|
|
|
|
+ RF2401_Shutdown();
|
|
|
|
|
+ g_power_idle_count = 0;
|
|
|
|
|
+ led_set_brightness(0);
|
|
|
|
|
+
|
|
|
|
|
+ /* 按键唤醒: 走订阅层。hal_irq_subscribe 配下降沿 + INT_EN + 使能 GPIO_A NVIC,
|
|
|
|
|
+ * 且把 SW_KEY 记入 _hal_irq_dispatch_mask[0], 不会被其它 PA 引脚的退订误关。 */
|
|
|
|
|
+ hal_gpio_mode_cfg(SW_KEY, GPIO_ModeIN_PU);
|
|
|
|
|
+ hal_irq_subscribe(HAL_IRQ_GPIO, SW_KEY, HAL_IRQ_EDGE_FALL);
|
|
|
|
|
+
|
|
|
|
|
+ hal_gpio_mode_cfg(SOUND_PIN, GPIO_ModeIN_PU);
|
|
|
|
|
+ /* 声音开关: 上拉关断 */
|
|
|
|
|
+ hal_gpio_mode_cfg(SOUND_SW, GPIO_ModeOut_PP_5mA);
|
|
|
|
|
+ hal_gpio_set_high(SOUND_SW);
|
|
|
|
|
+
|
|
|
|
|
+ /* 关掉声音检测引脚的唤醒使能: disarm SOUND 中断 (清 INT_EN 位 + 清残留 IF)。
|
|
|
|
|
+ * SOUND 在 PB, SW_KEY 在 PA, 故 GPIO_B NVIC 可随退订关闭, GPIO_A 仍武装按键唤醒。
|
|
|
|
|
+ * hal_irq_unsubscribe 不清 INT_MODE 位, 但 INT_EN 已清则该 pin 不再触发, 等价。 */
|
|
|
|
|
+ hal_irq_unsubscribe(HAL_IRQ_GPIO, SOUND_PIN);
|
|
|
|
|
+
|
|
|
|
|
+ /* LED 引脚设为输出低 */
|
|
|
|
|
+ hal_gpio_mode_cfg(LED_PIN, GPIO_ModeOut_PP_5mA);
|
|
|
|
|
+ hal_gpio_set_low(LED_PIN);
|
|
|
|
|
+
|
|
|
|
|
+ /* GPIO_A NVIC 已由上面 hal_irq_subscribe(SW_KEY) 使能, 无需再裸调 PFIC_EnableIRQ。 */
|
|
|
|
|
+
|
|
|
|
|
+ PWR_PeriphWakeUpCfg(ENABLE, RB_SLP_GPIO_WAKE, Long_Delay);
|
|
|
|
|
+ DelayMs(50);
|
|
|
|
|
+
|
|
|
|
|
+ /* 标记: 本次由中断唤醒 (若 RTC 唤醒则此标志未被设置, 说明中断失效, 人工唤醒) */
|
|
|
|
|
+ g_power_woke_by_irq = TRUE;
|
|
|
|
|
+ DelayMs(100);
|
|
|
|
|
+
|
|
|
|
|
+ LowPower_Shutdown(0);
|
|
|
|
|
+ HSECFG_Current(HSE_RCur_100);
|
|
|
|
|
+ g_power_need_reset = TRUE;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+/* ==================== 开机初始化 ==================== */
|
|
|
|
|
+void power_boot(void)
|
|
|
|
|
+{
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ /* SI24R1 重映射 + SPI 初始化 */
|
|
|
|
|
+ SI24R1_SPI_REMAP_INIT();
|
|
|
|
|
+ drv_spi_init();
|
|
|
|
|
+ NRF24L01_Gpio_Init();
|
|
|
|
|
+
|
|
|
|
|
+ if (NRF24L01_check() == SUCCESS) {
|
|
|
|
|
+ RF24L01_Init();
|
|
|
|
|
+ NRF24L01_Set_Speed(SPEED_250K);
|
|
|
|
|
+ DelayMs(10);
|
|
|
|
|
+ RF24L01_Set_Mode(MODE_RX);
|
|
|
|
|
+
|
|
|
|
|
+ /* HOP_POOL 首信道开机驻留 */
|
|
|
|
|
+ {
|
|
|
|
|
+ static const uint8_t pool[HOP_POOL_SIZE] = HOP_POOL;
|
|
|
|
|
+ uint8_t boot_freq = pool[0];
|
|
|
|
|
+ RF24LL01_Write_Hopping_Point(boot_freq);
|
|
|
|
|
+ DelayUs(100);
|
|
|
|
|
+ rx_hop_init(boot_freq);
|
|
|
|
|
+ }
|
|
|
|
|
+ IS_RF_INITED = TRUE;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* 按键 / 空闲状态复位 */
|
|
|
|
|
+ key_short_count = 0;
|
|
|
|
|
+ g_power_idle_count = 0;
|
|
|
|
|
+
|
|
|
|
|
+ /* 开机防抖计时:上电后 STRATUP_GUARD_MS 内长按不触发关机 */
|
|
|
|
|
+ g_power_boot_tick = RTC_GetCycle32k();
|
|
|
|
|
+ /* 进入普通模式 */
|
|
|
|
|
+ power_set_mode(OPMODE_NORMAL);
|
|
|
|
|
+
|
|
|
|
|
+ eco_reset();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* ==================== 节能亮度曲线 ==================== */
|
|
|
|
|
+/* 每阶段从 pwm_start 线性过渡到 pwm_end, 持续 sec 秒。
|
|
|
|
|
+ * is_loop=1 的阶段构成循环体; loop_max_sec 限制循环总时长。
|
|
|
|
|
+ * 修改此表即可调整节能策略, 无需改动 ledx.c 逻辑。 */
|
|
|
|
|
+
|
|
|
|
|
+/* 节能曲线数据由 pindef.h::MLED_ECO_PLAN_DATA 提供 (便于按设备/PCB 调整)。
|
|
|
|
|
+ * ECO_PLAN_LEN 用 sizeof 自动计算, 改数据无需手动同步长度。 */
|
|
|
|
|
+struct eco_s eco_plan[] = {
|
|
|
|
|
+ MLED_ECO_PLAN_DATA
|
|
|
|
|
+};
|
|
|
|
|
+#define ECO_PLAN_LEN (sizeof(eco_plan) / sizeof(eco_plan[0]))
|
|
|
|
|
+
|
|
|
|
|
+/* ---- 节能状态机 ---- */
|
|
|
|
|
+volatile uint8_t eco_idx = 0;
|
|
|
|
|
+volatile uint16_t eco_sec = 0;
|
|
|
|
|
+volatile uint16_t eco_loop_sec = 0;
|
|
|
|
|
+
|
|
|
|
|
+void eco_reset(void)
|
|
|
|
|
+{
|
|
|
|
|
+ eco_idx = 0;
|
|
|
|
|
+ eco_sec = 0;
|
|
|
|
|
+ eco_loop_sec = 0;
|
|
|
|
|
+ g_led_pwm_echo = eco_plan[0].pwm_start;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+uint8_t eco_advance(void)
|
|
|
|
|
+{
|
|
|
|
|
+ led_pwm_apply_brightness(g_led_brightness);
|
|
|
|
|
+
|
|
|
|
|
+ struct eco_s *cur = &eco_plan[eco_idx];
|
|
|
|
|
+ eco_sec++;
|
|
|
|
|
+ g_led_pwm_echo = cur->pwm_start
|
|
|
|
|
+ + (int32_t)(cur->pwm_end - cur->pwm_start) * eco_sec / cur->sec;
|
|
|
|
|
+
|
|
|
|
|
+ if (cur->is_loop) {
|
|
|
|
|
+ eco_loop_sec++;
|
|
|
|
|
+ uint8_t ls = eco_idx;
|
|
|
|
|
+ while (ls > 0 && eco_plan[ls - 1].is_loop) ls--;
|
|
|
|
|
+ uint16_t maxs = eco_plan[ls].loop_max_sec;
|
|
|
|
|
+ if (maxs > 0 && eco_loop_sec >= maxs) {
|
|
|
|
|
+ eco_sec = 0;
|
|
|
|
|
+ eco_loop_sec = 0;
|
|
|
|
|
+ uint8_t n = ls;
|
|
|
|
|
+ while (n < ECO_PLAN_LEN && eco_plan[n].is_loop) n++;
|
|
|
|
|
+ if (n < ECO_PLAN_LEN) {
|
|
|
|
|
+ eco_idx = n;
|
|
|
|
|
+ g_led_pwm_echo = eco_plan[eco_idx].pwm_start;
|
|
|
|
|
+ }
|
|
|
|
|
+ return 2;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (eco_sec >= cur->sec) {
|
|
|
|
|
+ eco_sec = 0;
|
|
|
|
|
+ uint8_t is_last_loop = cur->is_loop
|
|
|
|
|
+ && (eco_idx + 1 >= ECO_PLAN_LEN || !eco_plan[eco_idx + 1].is_loop);
|
|
|
|
|
+ if (is_last_loop) {
|
|
|
|
|
+ uint8_t s = eco_idx;
|
|
|
|
|
+ while (s > 0 && eco_plan[s - 1].is_loop) s--;
|
|
|
|
|
+ eco_idx = s;
|
|
|
|
|
+ } else if (eco_idx + 1 < ECO_PLAN_LEN) {
|
|
|
|
|
+ eco_idx++;
|
|
|
|
|
+ }
|
|
|
|
|
+ g_led_pwm_echo = eco_plan[eco_idx].pwm_start;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return 2;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+/* ==================== 声音检测 ==================== */
|
|
|
|
|
+
|
|
|
|
|
+/* 相邻两次采样的最小间隔(RTC tick),小于此值不重复判定。
|
|
|
|
|
+ * 轮询与中断两种方式共用此节拍:轮询用它决定采样节奏,中断用它决定
|
|
|
|
|
+ * sound_hold 倒计时节奏,故两种方式的点灯时长一致。 */
|
|
|
|
|
+#define SOUND_SAMPLE_INTERVAL MS_TO_RTC(SOUND_CHECK_INTERVAL_MS)
|
|
|
|
|
+
|
|
|
|
|
+/* 触发方式由 project_config.h 的 SOUND_TRIG_MODE 二选一(见该文件第 6 节):
|
|
|
|
|
+ * SOUND_TRIG_POLL 轮询采样 GPIO + 去抖,稳定低电平即触发
|
|
|
|
|
+ * SOUND_TRIG_IRQ GPIOB 下降沿中断,ISR 直接装载 sound_hold
|
|
|
|
|
+ * 两种方式共用下面的 sound_hold 倒计时与点灯逻辑。 */
|
|
|
|
|
+
|
|
|
|
|
+#if (SOUND_TRIG_MODE == SOUND_TRIG_POLL)
|
|
|
|
|
+/* 轮询触发(默认):原 sound_poll() 逻辑原样保留 */
|
|
|
|
|
+static uint8_t sound_poll_gpio(void)
|
|
|
|
|
+{
|
|
|
|
|
+ uint32_t current_time = RTC_GetCycle32k();
|
|
|
|
|
+
|
|
|
|
|
+ /* 无符号差值天然处理 32 位回绕(与旧写的显式分支等价) */
|
|
|
|
|
+ uint32_t time_diff = current_time - sound_last_tick;
|
|
|
|
|
+
|
|
|
|
|
+ if (time_diff > SOUND_SAMPLE_INTERVAL) {
|
|
|
|
|
+ sound_last_tick = current_time;
|
|
|
|
|
+
|
|
|
|
|
+ /* 读取 GPIO 并去抖动 */
|
|
|
|
|
+ uint8_t current_gpio_state = (hal_gpio_read(SOUND_PIN) == 0) ? 0 : 1;
|
|
|
|
|
+
|
|
|
|
|
+ if (current_gpio_state != sound_last_level) {
|
|
|
|
|
+ sound_debounce = 0;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ if (sound_debounce < SOUND_DEBOUNCE_COUNT) {
|
|
|
|
|
+ sound_debounce++;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ sound_last_level = current_gpio_state;
|
|
|
|
|
+
|
|
|
|
|
+ /* 去抖动稳定后判定声音 */
|
|
|
|
|
+ if (sound_debounce >= SOUND_DEBOUNCE_COUNT) {
|
|
|
|
|
+ if (current_gpio_state == 0) {
|
|
|
|
|
+ sound_hold = SOUND_ACTIVE_DURATION;
|
|
|
|
|
+ led_set_brightness(255);
|
|
|
|
|
+ return 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* 声音后保持亮度倒计时 */
|
|
|
|
|
+ if (sound_hold > 0) {
|
|
|
|
|
+ sound_hold--;
|
|
|
|
|
+ if (sound_hold > 0) {
|
|
|
|
|
+ led_set_brightness(255);
|
|
|
|
|
+ return 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ led_set_brightness(0);
|
|
|
|
|
+ return 2;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+#else
|
|
|
|
|
+/* 中断触发:sound_hold 由 GPIOB_IRQHandler 在下降沿装载,这里只做固定节拍倒计时 */
|
|
|
|
|
+static uint8_t sound_poll_irq(void)
|
|
|
|
|
+{
|
|
|
|
|
+ uint32_t current_time = RTC_GetCycle32k();
|
|
|
|
|
+ uint32_t time_diff = current_time - sound_last_tick;
|
|
|
|
|
+
|
|
|
|
|
+ if (time_diff > SOUND_SAMPLE_INTERVAL) {
|
|
|
|
|
+ sound_last_tick = current_time;
|
|
|
|
|
+
|
|
|
|
|
+ if (sound_hold > 0) {
|
|
|
|
|
+ sound_hold--;
|
|
|
|
|
+ led_set_brightness(255);
|
|
|
|
|
+ return 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ led_set_brightness(0);
|
|
|
|
|
+ return 2;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
+/* 声控入口:led_glow_tick() 每主循环调用,按 SOUND_TRIG_MODE 派发 */
|
|
|
|
|
+uint8_t sound_poll(void)
|
|
|
|
|
+{
|
|
|
|
|
+#if (SOUND_TRIG_MODE == SOUND_TRIG_IRQ)
|
|
|
|
|
+ return sound_poll_irq();
|
|
|
|
|
+#else
|
|
|
|
|
+ return sound_poll_gpio();
|
|
|
|
|
+#endif
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+/* ---- 进入/退出声控模式(led_set_mode 调用) ----
|
|
|
|
|
+ * 进入:配置 SOUND_PIN 为上拉输入。
|
|
|
|
|
+ * IRQ 方式: hal_irq_subscribe 订阅下降沿 (配 INT_MODE + 使能 INT_EN/NVIC)。
|
|
|
|
|
+ * POLL 方式: 不触碰 NVIC (主循环 sound_poll_gpio 轮询引脚电平)。
|
|
|
|
|
+ * 退出: IRQ 方式 hal_irq_unsubscribe 退订 (disarm + 无其它订阅者时关 NVIC);
|
|
|
|
|
+ * POLL 方式无操作。 */
|
|
|
|
|
+void sound_detect_start(void)
|
|
|
|
|
+{
|
|
|
|
|
+ hal_gpio_mode_cfg(SOUND_PIN, GPIO_ModeIN_PU);
|
|
|
|
|
+#if (SOUND_TRIG_MODE == SOUND_TRIG_IRQ)
|
|
|
|
|
+ /* IRQ 方式: 走统一订阅层。hal_irq_subscribe 配置下降沿 + 使能 GPIO_B NVIC,
|
|
|
|
|
+ * 且把 SOUND_PIN 记入 _hal_irq_dispatch_mask[1], 退订时据其判断是否关 NVIC。 */
|
|
|
|
|
+ hal_irq_subscribe(HAL_IRQ_GPIO, SOUND_PIN, HAL_IRQ_EDGE_FALL);
|
|
|
|
|
+#endif
|
|
|
|
|
+ /* POLL 方式: SOUND 走主循环轮询, 不触碰 GPIO_B NVIC (初始化时已关, 见 RF_main.c) */
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void sound_detect_stop(void)
|
|
|
|
|
+{
|
|
|
|
|
+#if (SOUND_TRIG_MODE == SOUND_TRIG_IRQ)
|
|
|
|
|
+ /* 退订: disarm SOUND 中断 (清 INT_EN + IF); 该端口无其它订阅者时自动关 NVIC */
|
|
|
|
|
+ hal_irq_unsubscribe(HAL_IRQ_GPIO, SOUND_PIN);
|
|
|
|
|
+#endif
|
|
|
|
|
+ /* POLL 方式: 无需操作 (未订阅即无 NVIC/INT_EN 可退) */
|
|
|
|
|
+}
|