/* * hw_config.c * * 可变化的硬件相关逻辑。 * 换 PCB / 改引脚 / 调启动流程 — 只改这个文件, ukey.c 状态机不动。 * * 函数清单: * GPIOA_IRQHandler — 按键 GPIO 中断 * checkbleOnOrOff — 按键短按次数 → 操作分发 * sw_hal_sleep — 进入低功耗睡眠 / 关机 * sys_startup — 上电开机硬件初始化 */ #include "hw_config.h" #include "ledx.h" #include "RF_PHY.h" #include "pindef.h" #include "peripheral.h" #include "sir24drv.h" #include "hop_config.h" /* sys_startup: HOP_POOL */ #include "rx_hop.h" /* sys_startup: rx_hop_init */ #include "ukey.h" /* setOPMode, __OP_MODE__, OPMODE_* */ /* ==================== GPIO 中断 ==================== */ __INTERRUPT __HIGH_CODE void GPIOA_IRQHandler(void) { GPIO_PIN_ClearITFlagBit(SW_KEY_PORT, SW_KEY); } /* ==================== 按键短按处理 ==================== */ void checkbleOnOrOff(uint32_t key_up_time) { if (key_down_counter > 0) { if (RTC_GetCycle32k() - key_down_time > KEY_SEQUENCE_TIMEOUT) { if (key_down_counter == 2) { /* 双击: 预留(原为配对/BLE) */ } else if (key_down_counter == 1 && CAN_ENTERN_NORMAL_OPMODE()) { /* 单按: 进入普通模式 */ setOPMode(OPMODE_NORMAL); } else if (key_down_counter == 1 && __OP_MODE__ == OPMODE_NORMAL) { /* 普通模式下单按: 切换闪烁模式 */ if (isRFOn) { key_down_counter = 0; return; } resetEco(); setColorModeNext(); } key_down_counter = 0; } } } /* ==================== 进入睡眠 / 关机 ==================== */ void sw_hal_sleep(void) { RF2401_Shutdown(); sys_idle_count = 0; setBrightness(0); /* 按键唤醒配置 */ GPIO_PIN_ModeCfg(SW_KEY_PORT, SW_KEY, GPIO_ModeIN_PU); GPIO_PIN_ITModeCfg(SW_KEY_PORT, SW_KEY, GPIO_ITMode_FallEdge); /* 声音开关: 上拉关断 */ GPIO_PIN_ModeCfg(SOUND_SW_PORT, SOUND_SW, GPIO_ModeOut_PP_5mA); GPIO_PIN_SetBits(SOUND_SW_PORT, SOUND_SW); /* 关掉声音检测引脚的唤醒使能 */ R16_PB_INT_EN &= ~SOUND_PIN; R16_PB_INT_MODE &= ~SOUND_PIN; R16_PB_INT_IF = SOUND_PIN; /* LED 引脚设为输出低 */ GPIO_PIN_ModeCfg(LED_PORT, LED_PIN, GPIO_ModeOut_PP_5mA); GPIO_PIN_ResetBits(LED_PORT, LED_PIN); /* 使能 GPIO 中断唤醒 */ PFIC_EnableIRQ(GPIO_A_IRQn); PWR_PeriphWakeUpCfg(ENABLE, RB_SLP_GPIO_WAKE, Long_Delay); DelayMs(50); /* 标记: 本次由中断唤醒 (若 RTC 唤醒则此标志未被设置, 说明中断失效, 人工唤醒) */ is_iqr_weekup = TRUE; DelayMs(100); LowPower_Shutdown(0); HSECFG_Current(HSE_RCur_100); need_pwup = TRUE; } /* ==================== 开机初始化 ==================== */ void sys_startup(void) { /* LED 引脚 */ GPIO_PIN_ModeCfg(LED_PORT, LED_PIN, GPIO_ModeOut_PP_5mA); GPIO_PIN_ResetBits(LED_PORT, LED_PIN); ledPwmInit(); /* 进入普通模式 */ setOPMode(OPMODE_NORMAL); /* 声音引脚: 浮空输入 */ GPIO_PIN_ModeCfg(SOUND_PORT, SOUND_PIN, GPIO_ModeIN_Floating); /* 声音开关: 输出低 */ GPIO_PIN_ModeCfg(SOUND_SW_PORT, SOUND_SW, GPIO_ModeOut_PP_5mA); GPIO_PIN_ResetBits(SOUND_SW_PORT, SOUND_SW); /* 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_down_counter = 0; is_key_down = FALSE; skip_this_btn_down = TRUE; sys_idle_count = 0; count_5 = 0; /* 开机防抖计时 */ is_powup_first = TRUE; sys_open_time = RTC_GetCycle32k(); resetEco(); } /* ==================== 节能亮度曲线 ==================== */ /* 每阶段从 pwm_start 线性过渡到 pwm_end, 持续 sec 秒。 * is_loop=1 的阶段构成循环体; loop_max_sec 限制循环总时长。 * 修改此表即可调整节能策略, 无需改动 ledx.c 逻辑。 */ /* 修改此表后需同步更新 hw_config.h 中的 ECO_PLAN_LEN */ struct eco_s eco_plan[] = { { 9500, 60, 9500, 0, 0 }, /* 95% 保持 60 秒 */ }; /* ---- 节能状态机 ---- */ volatile uint8_t eco_idx = 0; volatile uint16_t eco_sec = 0; volatile uint16_t eco_loop_sec = 0; uint8_t resetEco(void) { eco_idx = 0; eco_sec = 0; eco_loop_sec = 0; _led_pwm_echo = eco_plan[0].pwm_start; } uint8_t changeEco(void) { ledPwmApplyBrightness(_led_brightness); struct eco_s *cur = &eco_plan[eco_idx]; eco_sec++; _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; _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++; } _led_pwm_echo = eco_plan[eco_idx].pwm_start; } return 2; } /* ==================== 声音检测 ==================== */ static uint32_t ms10sys32tick = MS_TO_RTC(2); /* 2ms 检测间隔 */ uint8_t catchSound(void) { uint32_t current_time = RTC_GetCycle32k(); uint32_t time_diff; /* 安全时间差 (处理 32-bit 溢出) */ if (current_time >= _led_current_sound_systick) { time_diff = current_time - _led_current_sound_systick; } else { time_diff = 0xFFFFFFFF - _led_current_sound_systick + current_time + 1; } if (time_diff > ms10sys32tick) { _led_current_sound_systick = current_time; /* 读取 GPIO 并去抖动 */ uint8_t current_gpio_state = (GPIO_PIN_ReadPortPin(SOUND_PORT, SOUND_PIN) == 0) ? 0 : 1; if (current_gpio_state != last_gpio_state) { sound_debounce_count = 0; } else { if (sound_debounce_count < SOUND_DEBOUNCE_COUNT) { sound_debounce_count++; } } last_gpio_state = current_gpio_state; /* 去抖动稳定后判定声音 */ if (sound_debounce_count >= SOUND_DEBOUNCE_COUNT) { if (current_gpio_state == 0) { inSound = SOUND_ACTIVE_DURATION; setBrightness(255); return 1; } } /* 声音后保持亮度倒计时 */ if (inSound > 0) { inSound--; if (inSound > 0) { setBrightness(255); return 1; } } setBrightness(0); return 2; } return 0; }