STM32 继电器驱动——双触发模式的通用控制接口
问题背景继电器模块的触发方式有两种高电平触发常见于低电平驱动型继电器模组和低电平触发常见于光耦隔离型模组。如果业务代码直接操作 GPIO 而不区分触发模式换一个模块就要改代码。本文给出一个简洁的继电器驱动通过active_mode字段封装两种触发模式的差异提供初始化、开关、翻转等标准接口。驱动设计核心思路驱动使用relay_active_t枚举区分触发模式typedef enum { RELAY_ACTIVE_HIGH 0, // 高电平触发输出 SET 吸合 RELAY_ACTIVE_LOW // 低电平触发输出 RESET 吸合 } relay_active_t;所有操作函数relay_on、relay_off都根据active_mode计算实际物理电平调用方只需关心开/关逻辑。toggle 实现relay_toggle通过HAL_GPIO_ReadPin读取当前引脚电平结合active_mode判断继电器是否已吸合然后翻转。这种读-判断-写的方式比维护内部状态变量更可靠状态始终与硬件一致。API 参考函数说明relay_init(cb, gpio_x, gpio_pin, active_mode, set_pin)初始化并关闭继电器relay_on(cb)吸合继电器relay_off(cb)释放继电器relay_set(cb, val)设置状态0关, 非0开relay_toggle(cb)翻转状态使用示例#include driver_relay.h ​ relay_control_t relay1; ​ int main(void) { // 初始化高电平触发GPIOB_PIN_12 relay_init(relay1, (uint32_t)GPIOB, GPIO_PIN_12, RELAY_ACTIVE_HIGH, (relay_gpio_set_func_t)HAL_GPIO_WritePin); ​ relay_on(relay1); // 吸合 HAL_Delay(1000); relay_off(relay1); // 释放 HAL_Delay(1000); relay_toggle(relay1); // 再次吸合 HAL_Delay(1000); relay_set(relay1, 0); // 通过变量控制释放 ​ while (1); }注意事项gpio_x参数为uint32_t类型传入 GPIO 端口时需要强转set_pin函数指针不能为 NULL否则relay_init返回RELAY_ERRORrelay_toggle内部调用HAL_GPIO_ReadPin需要该引脚已在 CubeMX 中正确配置初始化后继电器默认处于关闭释放状态总结本驱动仅 ~150 行代码核心价值在于用active_mode字段消除了不同继电器模块在触发方式上的差异让上层代码完全透明。完整源码driver_relay.h/** * file driver_relay.h * author Jiang Ying * brief 继电器驱动头文件 * version V1.0.0 * date 2026.03.28 * note 该文件包含继电器驱动函数声明提供初始化、开启、关闭、 * 设置和切换功能。用户可以通过调用这些函数来控制继电器的状态。 */ ​ #ifndef _DRIVER_RELAY_H #define _DRIVER_RELAY_H ​ /* Includes ------------------------------------------------------------------*/ #include stm32f1xx_hal.h ​ #include stdint.h ​ /** * brief 继电器状态枚举 * note 定义继电器的两种状态关闭和开启 */ typedef enum { RELAY_ERROR 0, RELAY_OK !RELAY_ERROR }relay_state_t; ​ /** * brief 继电器状态枚举 * note 定义继电器的两种状态关闭和开启 */ typedef enum { RELAY_RESET 0, RELAY_SET }relay_set_t; ​ /** * brief 继电器触发模式枚举 * note 定义继电器的不同触发模式 */ typedef enum { RELAY_ACTIVE_HIGH 0, /* 高电平触发模式GPIO输出高电平时继电器吸合 */ RELAY_ACTIVE_LOW /* 低电平触发模式GPIO输出低电平时继电器吸合 */ }relay_active_t; ​ /** * brief GPIO设置函数指针类型 * note 用于设置GPIO引脚状态的函数指针类型 */ typedef relay_state_t (*relay_gpio_set_func_t)(uint32_t, uint32_t, uint32_t); ​ /** * brief 继电器控制结构体 * note 包含继电器的GPIO配置、触发模式和控制函数 */ typedef struct { uint32_t gpio_x; /* GPIO端口 */ uint32_t gpio_pin; /* GPIO引脚 */ relay_active_t active_mode; /* 继电器触发模式 */ relay_gpio_set_func_t set_pin; /* GPIO设置函数指针 */ }relay_control_t; ​ ​ relay_state_t relay_init(relay_control_t *cb, uint32_t gpio_x, uint32_t gpio_pin, relay_active_t active_mode, relay_gpio_set_func_t set_pin); relay_state_t relay_on(relay_control_t *cb); relay_state_t relay_off(relay_control_t *cb); relay_state_t relay_set(relay_control_t *cb, uint32_t val); relay_state_t relay_toggle(relay_control_t *cb); ​ ​ #endif /* _DRIVER_RELAY_H */ ​driver_relay.c/** * file driver_relay.c * author Jiang Ying * brief 继电器驱动源文件 * version V1.0.0 * date 2026.03.28 */ /* Includes ------------------------------------------------------------------*/ #include driver_relay.h ​ /** * brief 打开继电器 * param cb 继电器控制结构体指针 * return 继电器操作状态 * note 根据继电器的触发模式决定输出高电平还是低电平 */ relay_state_t relay_on(relay_control_t *cb) { relay_state_t state RELAY_ERROR; uint32_t pin_state; ​ /* 根据触发模式决定实际输出的电平 */ if (cb-active_mode RELAY_ACTIVE_HIGH) { pin_state RELAY_SET; /* 高电平触发模式输出高电平吸合继电器 */ } else { pin_state RELAY_RESET; /* 低电平触发模式输出低电平吸合继电器 */ } ​ state cb-set_pin(cb-gpio_x, cb-gpio_pin, pin_state); ​ return state; } ​ /** * brief 关闭继电器 * param cb 继电器控制结构体指针 * return 继电器操作状态 * note 根据继电器的触发模式决定输出高电平还是低电平 */ relay_state_t relay_off(relay_control_t *cb) { relay_state_t state RELAY_ERROR; uint32_t pin_state; ​ /* 根据触发模式决定实际输出的电平 */ if (cb-active_mode RELAY_ACTIVE_HIGH) { pin_state RELAY_RESET; /* 高电平触发模式输出低电平释放继电器 */ } else { pin_state RELAY_SET; /* 低电平触发模式输出高电平释放继电器 */ } ​ state cb-set_pin(cb-gpio_x, cb-gpio_pin, pin_state); ​ return state; } ​ /** * brief 设置继电器状态 * param cb 继电器控制结构体指针 * param val 继电器状态值0表示关闭非0表示打开 * return 继电器操作状态 * note 根据继电器的触发模式和状态值决定输出高电平还是低电平 */ relay_state_t relay_set(relay_control_t *cb, uint32_t val) { if (val) { return relay_on(cb); /* 打开继电器 */ } else { return relay_off(cb); /* 关闭继电器 */ } } ​ /** * brief 初始化继电器控制结构体 * param cb 继电器控制结构体指针 * param gpio_x GPIO端口 * param gpio_pin GPIO引脚 * param active_mode 继电器触发模式 * param set_pin GPIO设置函数指针 * return 继电器操作状态 * note 配置继电器控制结构体并初始化继电器为关闭状态 */ relay_state_t relay_init(relay_control_t *cb, uint32_t gpio_x, uint32_t gpio_pin, relay_active_t active_mode, relay_gpio_set_func_t set_pin) { relay_state_t state RELAY_ERROR; ​ if (cb NULL || set_pin NULL) { return RELAY_ERROR; } ​ /* 配置继电器控制结构体 */ cb-gpio_x gpio_x; cb-gpio_pin gpio_pin; cb-active_mode active_mode; cb-set_pin set_pin; ​ /* 初始化继电器为关闭状态 */ state relay_off(cb); ​ return state; } ​ /** * brief 切换继电器状态 * param cb 继电器控制结构体指针 * return 继电器操作状态 * note 如果继电器当前是打开状态则关闭如果是关闭状态则打开 */ relay_state_t relay_toggle(relay_control_t *cb) { relay_state_t state RELAY_ERROR; uint32_t current_state; uint32_t new_state; ​ /* 获取当前引脚状态 */ if (cb-active_mode RELAY_ACTIVE_HIGH) { /* 高电平触发模式下引脚为高表示继电器打开 */ current_state (HAL_GPIO_ReadPin((GPIO_TypeDef*)cb-gpio_x, cb-gpio_pin) GPIO_PIN_SET) ? 1 : 0; } else { /* 低电平触发模式下引脚为低表示继电器打开 */ current_state (HAL_GPIO_ReadPin((GPIO_TypeDef*)cb-gpio_x, cb-gpio_pin) GPIO_PIN_RESET) ? 1 : 0; } ​ /* 切换状态 */ new_state current_state ? 0 : 1; ​ /* 设置新状态 */ state relay_set(cb, new_state); ​ return state; } ​

相关新闻

连山区口腔机构排名,专业的竟然是这些!

连山区口腔机构排名,专业的竟然是这些!

引言在连山区,口腔健康备受关注,众多口腔机构林立。究竟哪些机构专业度较高呢?让我们一同探寻。专业口腔机构剖析连山区兴工路周雷口腔诊所:这是一家备受赞誉的口腔机构。诊所环境整洁舒适,诊疗设备定期消毒&#xff0…

2026/8/2 7:39:22 阅读更多 →
BRSS 大版本更新:网易云也能当播客,部署更简单,Bug 全修

BRSS 大版本更新:网易云也能当播客,部署更简单,Bug 全修

上次文章 项目地址:Github、Gitee 🔗 新版本仓库:Master分支 📦 老版本归档: Old-version 分支 一、这次都更新了什么(新功能) 🎵 1. 网易云音乐电台 → 播客 这是呼声最高的功…

2026/8/2 7:39:22 阅读更多 →
搭建同城外卖系统:商家端商品管理、多规格SKU与库存同步解决方案

搭建同城外卖系统:商家端商品管理、多规格SKU与库存同步解决方案

在搭建同城外卖系统时,很多开发工作会围绕用户下单、骑手配送展开,而真正决定商家运营效率的,往往是商家端的商品管理能力。尤其是商品规格越来越丰富后,如何设计SKU模型、保证库存准确、降低维护成本,是开发同城外卖A…

2026/8/2 7:39:22 阅读更多 →

最新新闻

Unity UGUI聊天框自适应布局:告别强制刷新,实现高性能UI

Unity UGUI聊天框自适应布局:告别强制刷新,实现高性能UI

1. 项目概述:为什么聊天框自适应是个“老大难”? 做Unity UI开发,尤其是社交、MMO这类带聊天系统的项目,最让人头疼的UI组件之一,恐怕就是聊天框了。你肯定遇到过这种情况:精心设计好的气泡背景图&#xff…

2026/8/2 8:16:40 阅读更多 →
Meta SAM模型实战:零样本分割如何赋能数字衣橱应用落地

Meta SAM模型实战:零样本分割如何赋能数字衣橱应用落地

1. 从“衣橱整理”到“数字衣橱”:一个被低估的AI应用场景 如果你和我一样,曾经对着满柜子的衣服却感觉“没衣服穿”,或者为了找一件特定款式的衬衫翻箱倒柜,那你一定能理解“数字衣橱”这个概念背后的朴素需求。传统的做法是手动…

2026/8/2 8:16:40 阅读更多 →
AI驱动的用户转化漏斗评估体系(2024最新版A/B测试+因果推断双引擎)

AI驱动的用户转化漏斗评估体系(2024最新版A/B测试+因果推断双引擎)

更多请点击: https://intelliparadigm.com 第一章:AI 活动效果评估 AI 活动效果评估是衡量模型在真实业务场景中价值落地的关键环节,它超越传统离线指标(如准确率、F1 值),聚焦于用户行为变化、商业目标达…

2026/8/2 8:16:39 阅读更多 →
图神经网络在海洋预报中的应用:SeaCast模型原理与工程实践

图神经网络在海洋预报中的应用:SeaCast模型原理与工程实践

1. 项目概述:当海洋预报遇上图神经网络 最近在关注海洋科技和AI交叉领域的朋友,可能都注意到了“SeaCast”这个名字。一个欧洲的科研团队,搞出了一个能在20秒内完成未来15天高分辨率海洋预报的模型。这个标题本身就充满了冲击力:2…

2026/8/2 8:16:39 阅读更多 →
蝰蛇战术-XM7长款氧化版深度解析:2.0ATM波箱与全金属配置实战指南

蝰蛇战术-XM7长款氧化版深度解析:2.0ATM波箱与全金属配置实战指南

最近在战术装备圈和下场玩家中,一个名字被频繁提及: 蝰蛇战术-XM7 。如果你正在寻找一款性能、外观、质感都足够“顶”的发射器,并且对传统的“塑料玩具”感已经厌倦,那么这款产品很可能就是你的下一个目标。 但问题来了&#…

2026/8/2 8:16:39 阅读更多 →
工业通信核心:RS232转RS485/422转换器原理、设计与实战避坑指南

工业通信核心:RS232转RS485/422转换器原理、设计与实战避坑指南

1. 从RS232到RS485/422:为什么工业现场离不开串口转换? 如果你在工业自动化、楼宇自控或者安防监控领域待过,那么对RS232、RS485、RS422这几个名词一定不会陌生。它们就像工业通信领域的“普通话”和“方言”,各自有擅长的场景。很…

2026/8/2 8:15:39 阅读更多 →

日新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/2 0:00:38 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/2 0:00:38 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/2 0:00:38 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/2 0:00:38 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/2 0:00:38 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/2 0:00:38 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/2 6:34:16 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/2 2:47:48 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/2 0:23:22 阅读更多 →