/** ****************************************************************************** * @file relay_control.c * @brief 继电器控制模块实现 * @author Application Layer * @version 2.0 ****************************************************************************** * @attention * 本模块实现单路继电器的安全控制 * 关键特性: * 1. 最小切换间隔保护,防止频繁切换损坏继电器 * 2. 状态记录 * 3. 调试日志输出 * * 修订历史: * v2.0 - 精简为单路继电器控制,移除冗余功能 ****************************************************************************** */ #include "relay_control.h" #include "uart2_print.h" #include "main.h" /*============================================================================== * 调试宏定义 *============================================================================*/ /* DEBUG_RELAY: 调试日志开关,置1时启用继电器控制过程日志输出 */ #define DEBUG_RELAY 1 #if DEBUG_RELAY /* 调试日志宏,带模块前缀"[RELAY]"方便过滤日志 */ #define DEBUG_LOG(fmt, ...) UART2_Print_Printf("[RELAY] " fmt "\r\n", ##__VA_ARGS__) #else #define DEBUG_LOG(fmt, ...) #endif /*============================================================================== * 全局变量定义 *============================================================================*/ /** * @brief 继电器当前状态 * @note 记录继电器的开关状态 * * 状态含义: * - false: 继电器处于断开状态(OFF) * - true: 继电器处于闭合状态(ON) * * 初始化说明: * 初始化为false,表示系统上电后继电器默认断开 */ static bool current_state = false; /** * @brief 上一次切换操作的时间戳 * @note 用于实现继电器最小切换间隔保护 * * 设计目的: * 继电器是机械开关,频繁切换会缩短其使用寿命。 * 通过记录上次切换时间,可以强制两次切换之间必须间隔 * 最小时间(RELAY_MIN_INTERVAL),防止频繁操作。 * * 单位说明: * 毫秒(ms),与HAL_GetTick()返回值单位一致 */ static uint32_t last_toggle_tick = 0; /*============================================================================== * 公共函数实现 *============================================================================*/ /** * @brief 继电器模块初始化 * @note 在系统启动时调用,复位继电器到安全初始状态 * * @param 无 * @return 无 * * 功能说明: * 1. 硬件控制引脚设置为低电平,强制确保继电器断开 * 2. 重置状态变量为false * 3. 重置切换时间戳为0 * * 初始化安全: * - 此函数应尽早调用,确保系统启动时继电器处于受控状态 * - 继电器初始状态设为OFF是考虑到故障安全(fail-safe)设计 */ void Relay_Init(void) { /*---------------------------------------------------------- * 硬件层面:将继电器控制引脚设置为低电平 * RL_Control_GPIO_Port和RL_Control_Pin定义在main.h或引脚配置中 *----------------------------------------------------------*/ HAL_GPIO_WritePin(RL_Control_GPIO_Port, RL_Control_Pin, GPIO_PIN_RESET); /*---------------------------------------------------------- * 软件层面:初始化继电器状态为OFF *----------------------------------------------------------*/ current_state = false; /*---------------------------------------------------------- * 重置切换保护相关计时器 *----------------------------------------------------------*/ last_toggle_tick = 0; DEBUG_LOG("Init OK, state=OFF"); } /** * @brief 设置继电器状态 * @note 核心控制函数,实现继电器开关操作及保护逻辑 * * @param state: 目标状态,false=关闭(OFF),true=打开(ON)(输入) * @return 无 * * 功能说明: * 1. 切换间隔保护检查(防频繁操作) * 2. 状态变更判断(避免重复操作) * 3. 硬件GPIO操作 * 4. 状态记录和统计更新 * * 算法说明 - 切换间隔保护: * if (current_tick - last_toggle_tick < RELAY_MIN_INTERVAL) * return; // 切换过于频繁,直接丢弃 * * 这个检查确保两次继电器操作之间至少间隔RELAY_MIN_INTERVAL毫秒, * 防止程序错误或通信干扰导致继电器被频繁开关。 * * 注意/异常: * - 切换间隔太短时静默忽略,防抖处理 * - 状态与当前相同时静默忽略,不重复操作 */ void Relay_SetState(bool state) { /*---------------------------------------------------------- * 获取当前时间,判断与上次操作的时间间隔 *----------------------------------------------------------*/ uint32_t current_tick = HAL_GetTick(); /*---------------------------------------------------------- * 切换间隔保护检查 *----------------------------------------------------------*/ if (current_tick - last_toggle_tick < RELAY_MIN_INTERVAL) { DEBUG_LOG("Toggle too fast, ignored"); return; } /*---------------------------------------------------------- * 状态变更判断:避免重复设置相同状态 *----------------------------------------------------------*/ if (current_state == state) { DEBUG_LOG("State unchanged: %s", state ? "ON" : "OFF"); return; } /*---------------------------------------------------------- * 硬件控制:设置GPIO引脚电平 *----------------------------------------------------------*/ HAL_GPIO_WritePin(RL_Control_GPIO_Port, RL_Control_Pin, state ? GPIO_PIN_SET : GPIO_PIN_RESET); /*---------------------------------------------------------- * 更新软状态和记录切换时间 *----------------------------------------------------------*/ current_state = state; last_toggle_tick = current_tick; DEBUG_LOG("Relay -> %s", state ? "ON" : "OFF"); } /** * @brief 获取继电器当前状态 * @note 返回继电器的开关状态 * * @param 无 * @return bool: 继电器状态,false=关闭(OFF),true=打开(ON) * * 使用示例: * if (Relay_GetState()) { * // 继电器当前处于闭合状态 * } */ bool Relay_GetState(void) { return current_state; }