STM32从零到量产开发:四路继电器工业控制模块开发— 继电器模块bsp_led.h与 bsp_led.c文件
📅 2026/7/29 3:06:59
👁️ 阅读次数
📝 编程学习
STM32从零到量产开发:四路继电器工业控制模块开发— 继电器模块bsp_led.h与 bsp_led.c文件
bsp_led.h实现
/** ****************************************************************************** * @file bsp_led.h * @brief 四路LED指示灯底层驱动对外接口 * @note RUN/COMM/FAULT/RS232四路独立指示灯,非阻塞毫秒时基状态机 ****************************************************************************** */#ifndef__BSP_LED_H#define__BSP_LED_H#ifdef__cplusplusextern"C"{#endif#include"main.h"/** * @brief LED模块初始化 * @note 初始化全部计时静态变量,上电熄灭所有LED */voidBSP_LED_Init(void);/** * @brief LED状态机刷新函数,主循环周期调用(5~10ms) * @note 处理RUN慢闪、FAULT快闪、COMM/RS232脉冲超时熄灭、自检计时 */voidBSP_LED_Refresh(void);/** * @brief Modbus RS485总线通信脉冲触发,收发数据点亮50ms */voidBSP_CommPulse(void);/** * @brief RS232上位机交互脉冲触发,收到串口指令点亮50ms */voidBSP_RS232Pulse(void);/** * @brief 设置故障告警灯开关 * @param active 1=开启FAULT快闪 0=关闭故障灯 */voidBSP_LED_SetFault(uint8_tactive);/** * @brief 四路LED整机自检,全部点亮1.5s后自动恢复正常灯效 */voidBSP_LED_SelfTest(void);#ifdef__cplusplus}#endif#endifbsp_led.c实现
/** ****************************************************************************** * @file bsp_led.c * @brief 4路独立LED指示灯驱动实现(非阻塞状态机 + 通信瞬时脉冲)(#LED redesign) * @details 依托HAL_GetTick毫秒时基实现无阻塞计时,区分常驻闪烁、瞬时脉冲、全局自检三类灯效逻辑 * 硬件统一低电平有效:GPIO_PIN_RESET=点亮,GPIO_PIN_SET=熄灭 ****************************************************************************** */#include"bsp_led.h"#include"main.h"/* ===================== 1. 顶层时序配置宏(统一管理灯效时长参数) ===================== *//* 闪烁周期单位ms,匹配产品规格书时序要求 * RUN运行灯 1Hz 慢闪;FAULT故障灯 10Hz 快闪 */#defineLED_SLOW_PERIOD1000u/* RUN完整闪烁周期 1000ms */#defineLED_SLOW_ON_TIME500u/* RUN单次点亮持续时长 */#defineLED_FAST_PERIOD100u/* FAULT完整闪烁周期 100ms */#defineLED_FAST_ON_TIME50u/* FAULT单次点亮持续时长 */#defineLED_PULSE_MS50u/* RS485/RS232通信脉冲点亮宽度 */#defineLED_TEST_MS1500u/* 四路LED硬件自检总持续时长 *//* ===================== 2. 模块静态私有状态变量(仅本文件内部读写) ===================== */staticuint32_ts_run_last=0u;/* RUN运行灯慢闪计时基准时间戳 * 读写位置:仅BSP_LED_Refresh内部读写 */staticuint8_ts_fault_active=0u;/* 故障告警总开关 1=开启FAULT快闪,0=关闭告警 * 赋值入口:BSP_LED_SetFault();读取判断:BSP_LED_Refresh故障分支 */staticuint32_ts_fault_last=0u;/* FAULT故障灯快闪计时基准时间戳 * 赋值入口:BSP_LED_SetFault();读取判断:BSP_LED_Refresh故障分支 */staticuint32_ts_comm_off_at=0u;/* RS485通信脉冲熄灭截止时间戳,0代表无有效脉冲 * 赋值入口:BSP_LED_CommPulse(),赋值为当前滴答+LED_PULSE_MS;读取清零:BSP_LED_Refresh脉冲分支 */staticuint32_ts_rs232_off_at=0u;/* RS232串口脉冲熄灭截止时间戳,0代表无有效脉冲 * 赋值入口:BSP_RS232Pulse(),赋值为当前滴答+LED_PULSE_MS;读取清零:BSP_LED_Refresh脉冲分支 */staticuint32_ts_test_off_at=0u;/* LED全局自检模式截止时间戳,0代表无自检任务 * 赋值入口:BSP_LED_SelfTest(),赋值为当前滴答+LED_TEST_MS;读取清零:BSP_LED_Refresh自检分支 *//* ===================== 3. 底层私有硬件IO适配函数(全文件统一调用,硬件逻辑单点维护) ===================== *//** * @brief LED底层引脚输出统一适配接口 * @param port: LED对应GPIO端口 * @param pin: LED对应引脚编号 * @param on: 逻辑状态 1=点亮,0=熄灭 * @note 硬件低电平有效,on=1输出GPIO_PIN_RESET,on=0输出GPIO_PIN_SET */staticvoidLED_Write(GPIO_TypeDef*port,uint16_tpin,uint8_ton){HAL_GPIO_WritePin(port,pin,on?GPIO_PIN_RESET:GPIO_PIN_SET);}/* ===================== 4. 对外公共业务接口(按程序运行时序:初始化→核心刷新→状态控制→自检) ===================== *//** * @brief LED模块初始化,复位全部计时、状态缓存,四路LED上电统一熄灭 */voidBSP_LED_Init(void){s_run_last=HAL_GetTick();s_fault_last=HAL_GetTick();s_fault_active=0u;s_comm_off_at=0u;s_rs232_off_at=0u;s_test_off_at=0u;/* 四路LED初始全部熄灭 */LED_Write(STATUS_LED_GPIO_Port,STATUS_LED_Pin,0u);LED_Write(COMM_LED_GPIO_Port,COMM_LED_Pin,0u);LED_Write(FAULT_LED_GPIO_Port,FAULT_LED_Pin,0u);LED_Write(RS232_LED_GPIO_Port,RS232_LED_Pin,0u);}/** * @brief LED全局状态机定时刷新主函数,主循环轮询调用 * @note 推荐调用周期 5~10ms;依赖HAL_GetTick()系统毫秒时基 * 执行优先级:自检逻辑 > RUN常驻闪烁 > FAULT故障闪烁 > 通信脉冲超时熄灭 */voidBSP_LED_Refresh(void){uint32_tnow=HAL_GetTick();uint32_telapsed;/* 【双向关联指引】 * 变量 s_test_off_at:定义在文件顶部【模块静态私有状态变量】区块 * 变量赋值位置:文件末尾函数 BSP_LED_SelfTest(),调用时赋值为 HAL_GetTick() + LED_TEST_MS(1500ms) * 变量非0代表自检任务正在执行;自检优先级最高,直接跳过所有常规灯效逻辑 */if(s_test_off_at!=0u){/* 有符号差值判断,兼容uwTick 49.7天溢出归零场景 */if(((int32_t)(now-s_test_off_at))>=0){s_test_off_at=0u;s_run_last=now;/* 复位RUN计时基准,避免自检结束闪烁相位偏移 *//* 自检到期熄灭全部通信、故障灯 */LED_Write(COMM_LED_GPIO_Port,COMM_LED_Pin,0u);LED_Write(FAULT_LED_GPIO_Port,FAULT_LED_Pin,0u);LED_Write(RS232_LED_GPIO_Port,RS232_LED_Pin,0u);}else{return;}}/* RUN运行灯1Hz常驻慢闪逻辑,不受故障、通信状态干扰 * 计时变量 s_run_last:定义在顶部静态变量区,仅本分支读写 */elapsed=now-s_run_last;if(elapsed>=LED_SLOW_ON_TIME&&elapsed<LED_SLOW_PERIOD){LED_Write(STATUS_LED_GPIO_Port,STATUS_LED_Pin,0u);}elseif(elapsed>=LED_SLOW_PERIOD){LED_Write(STATUS_LED_GPIO_Port,STATUS_LED_Pin,1u);s_run_last=now;}else{LED_Write(STATUS_LED_GPIO_Port,STATUS_LED_Pin,1u);}/* FAULT故障灯10Hz快闪逻辑,仅故障激活时执行 * 关联变量:s_fault_active(总开关)、s_fault_last(计时戳) * 变量定义:文件顶部静态变量;赋值入口:BSP_LED_SetFault() */if(s_fault_active){elapsed=now-s_fault_last;if(elapsed>=LED_FAST_ON_TIME&&elapsed<LED_FAST_PERIOD){LED_Write(FAULT_LED_GPIO_Port,FAULT_LED_Pin,0u);}elseif(elapsed>=LED_FAST_PERIOD){LED_Write(FAULT_LED_GPIO_Port,FAULT_LED_Pin,1u);s_fault_last=now;}else{LED_Write(FAULT_LED_GPIO_Port,FAULT_LED_Pin,1u);}}/* RS485通信脉冲计时标志 s_comm_off_at:定义在文件顶部【模块静态私有状态变量】区块 * 赋值入口:BSP_LED_CommPulse(),赋值为 HAL_GetTick() + LED_PULSE_MS(50ms) * 变量非0代表存在未结束通信脉冲,时间戳超时后熄灭LED并清零标记 */if(s_comm_off_at!=0u&&((int32_t)(now-s_comm_off_at))>=0){LED_Write(COMM_LED_GPIO_Port,COMM_LED_Pin,0u);s_comm_off_at=0u;}/* RS232串口通信脉冲计时标志 s_rs232_off_at:定义在文件顶部【模块静态私有状态变量】区块 * 赋值入口:BSP_RS232Pulse(),赋值为 HAL_GetTick() + LED_PULSE_MS(50ms) * 变量非0代表存在未结束串口脉冲,时间戳超时后熄灭LED并清零标记 */if(s_rs232_off_at!=0u&&((int32_t)(now-s_rs232_off_at))>=0){LED_Write(RS232_LED_GPIO_Port,RS232_LED_Pin,0u);s_rs232_off_at=0u;}}/** * @brief 故障告警状态开关控制 * @param active: 1=触发故障,FAULT灯10Hz快闪;0=清除故障,FAULT灯直接熄灭 * @note 【关联指引】本函数为 s_fault_active / s_fault_last 唯一赋值入口 * 两个变量在BSP_LED_Refresh()故障闪烁分支做读取判断,控制FAULT灯周期翻转 */voidBSP_LED_SetFault(uint8_tactive){//上层要开启故障,且当前原本无故障if(active&&!s_fault_active){s_fault_active=1u;// 打开故障总开关s_fault_last=HAL_GetTick();// 记录故障触发时刻,作为闪烁计时起点LED_Write(FAULT_LED_GPIO_Port,FAULT_LED_Pin,1u);}//上层要清除故障,且当前正处于故障状态elseif(!active&&s_fault_active){s_fault_active=0u;// 关闭故障总开关LED_Write(FAULT_LED_GPIO_Port,FAULT_LED_Pin,0u);}}/** * @brief Modbus RS485总线通信脉冲触发 * @note 【关联指引】本函数为 s_comm_off_at 唯一赋值入口 * s_comm_off_at = HAL_GetTick() + LED_PULSE_MS,赋值后在BSP_LED_Refresh()脉冲分支做超时判断熄灭 * 在Modbus有效帧收发位置调用,单次触发50ms点亮脉冲;频繁收发会持续刷新超时,保持常亮 */voidBSP_CommPulse(void){s_comm_off_at=HAL_GetTick()+LED_PULSE_MS;//记录LED_PULSE_MS后要熄灭的截止时间戳LED_Write(COMM_LED_GPIO_Port,COMM_LED_Pin,1u);//立刻点亮通信指示灯,BSP_LED_Refresh()没有亮灯的动作,要在这里亮灯}/** * @brief RS232串口通信活动脉冲触发 * @note 【关联指引】本函数为 s_rs232_off_at 唯一赋值入口 * s_rs232_off_at = HAL_GetTick() + LED_PULSE_MS,赋值后在BSP_LED_Refresh()脉冲分支做超时判断熄灭 * 在RS232命令解析、数据收发位置调用,单次触发50ms点亮脉冲 */voidBSP_RS232Pulse(void){s_rs232_off_at=HAL_GetTick()+LED_PULSE_MS;LED_Write(RS232_LED_GPIO_Port,RS232_LED_Pin,1u);}/** * @brief 启动四路LED硬件自检,全部同步点亮1.5s * @note 【关联指引】本函数为 s_test_off_at 唯一赋值入口 * s_test_off_at = HAL_GetTick() + LED_TEST_MS,赋值后在BSP_LED_Refresh()头部做自检优先级判断 * 自检优先级最高,运行期间屏蔽所有闪烁、脉冲逻辑;非阻塞,1.5s后自动恢复常规灯效,用于产线硬件接线校验 */voidBSP_LED_SelfTest(void){s_test_off_at=HAL_GetTick()+LED_TEST_MS;LED_Write(STATUS_LED_GPIO_Port,STATUS_LED_Pin,1u);LED_Write(COMM_LED_GPIO_Port,COMM_LED_Pin,1u);LED_Write(FAULT_LED_GPIO_Port,FAULT_LED_Pin,1u);LED_Write(RS232_LED_GPIO_Port,RS232_LED_Pin,1u);}
编程学习
技术分享
实战经验