STM32从零到量产开发:四路继电器工业控制模块开发— 继电器模块bsp_di.h与 bsp_di.c文件

STM32从零到量产开发:四路继电器工业控制模块开发--- 继电器模块bsp_di.h与 bsp_di.c文件

bsp_di.h代码实现

c 复制代码
/**
  ******************************************************************************
  * @file    bsp_di.h
  * @brief   4通道光耦隔离数字输入驱动 - 对应产品规格书 3.3 数字输入端子
  *
  * 硬件映射 (来自 CubeMX main.h):
  *   DI1 -> PB0, DI2 -> PB1, DI3 -> PB10, DI4 -> PB11
  *
  * 极性说明:
  *   GPIO 配置为上拉输入, 光耦导通时引脚被拉低
  *   规格书 3.3: "输入为低有效" -> 读到低电平 = 外部有输入信号
  *   本驱动对上层统一暴露逻辑值: 1=有输入, 0=无输入
  *
  * 消抖机制说明:
  *   软件定时消抖,多次采样电平保持 DEBOUNCE_CONFIRM_MS 毫秒一致,才更新稳定状态
  *   扫描依赖系统毫秒时基 HAL_GetTick()
  ******************************************************************************
  */
#ifndef __BSP_DI_H
#define __BSP_DI_H

#ifdef __cplusplus
extern "C" {
#endif

#include "main.h"

/* 数字输入总通道数量 */
#define DI_CH_NUM            4u

/* 软件消抖确认时长配置说明 */
/* 如果按键输入硬件已经有消抖电容,工业场景软件消抖取5~10ms */
/* 如果是无光耦隔离/外部干接点/传感器输入,软件消抖不能省,建议设 3~5ms */
#define DI_DEBOUNCE_MS       10u

/**
  * @brief  初始化4路数字输入GPIO,初始化消抖缓存状态
  * @note   GPIO硬件模式由MX_GPIO_Init完成配置,本函数仅初始化内部消抖变量
  */
void BSP_DI_Init(void);

/**
  * @brief  DI通道消抖定时扫描函数
  * @note   必须在主循环固定周期调用,推荐扫描周期 1~5ms;依赖 HAL_GetTick() 获取系统毫秒时基
  */
void BSP_DI_Scan(void);

/**
  * @brief  获取单路DI经过软件消抖后的稳定逻辑状态(业务正常读取接口)
  * @param  ch: 通道编号 1~4
  * @retval 1=外部有输入信号,0=无输入信号
  */
uint8_t BSP_DI_Get(uint8_t ch);

/**
  * @brief  批量获取全部4路DI消抖后稳定状态,返回位图掩码
  * @retval 4位有效掩码
  *         bit0对应DI1、bit1对应DI2、bit2对应DI3、bit3对应DI4;bit=1代表该通道有输入
  */
uint8_t BSP_DI_GetAll(void);

/**
  * @brief  获取单路DI当前实时原始电平(未经过软件消抖,仅调试排查硬件时使用)
  * @param  ch: 通道编号 1~4
  * @retval 1=硬件检测到输入,0=无输入
  */
uint8_t BSP_DI_GetRaw(uint8_t ch);

#ifdef __cplusplus
}
#endif
#endif /* __BSP_DI_H */

bsp_di.c代码实现

c 复制代码
/**
  ******************************************************************************
  * @file    bsp_di.c
  * @brief   4通道数字输入驱动实现 (含软件消抖)
  ******************************************************************************
  */
#include "bsp_di.h"
#include "main.h"

/* ===================== 硬件引脚定义 ===================== */
/* DI 引脚映射结构体 (通道号 1~4 对应数组索引 0~3) */
typedef struct
{
    GPIO_TypeDef *port;
    uint16_t      pin;
} di_pin_t;

/* 硬件引脚映射表 */
static const di_pin_t s_di_tbl[DI_CH_NUM] =
{
    { DI1_GPIO_Port, DI1_Pin },
    { DI2_GPIO_Port, DI2_Pin },
    { DI3_GPIO_Port, DI3_Pin },
    { DI4_GPIO_Port, DI4_Pin },
};

/* ===================== 消抖状态结构定义 ===================== */
/* 单通道消抖状态结构体 */
typedef struct
{
    uint8_t  raw;           /* 实时原始引脚电平,仅底层扫描使用,上层禁止读取 */
    uint8_t  stable;        /* 消抖完成稳定状态,业务/Modbus读取 */
    uint32_t last_change;   /* 电平跳变时间戳(ms),消抖计时基准 */
} di_debounce_t;

/* 四路独立消抖状态缓存 */
static di_debounce_t s_di[DI_CH_NUM];

/* ===================== 内部底层私有函数 ===================== */
/**
  * @brief  底层读取单通道原始引脚电平
  * @param  idx 内部数组下标 0~3
  * @retval 1 = 低电平有输入,0 = 无输入
  * @note  硬件电平适配层,仅此处修改高低有效逻辑,上层全部无感
  */
static uint8_t DI_ReadRawLevel(uint8_t idx)
{
    return (HAL_GPIO_ReadPin(s_di_tbl[idx].port, s_di_tbl[idx].pin) == GPIO_PIN_RESET) ? 1u : 0u;
}

/* ===================== 对外公共接口 ===================== */
/**
  * @brief  DI模块初始化,初始化所有通道消抖状态
  */
void BSP_DI_Init(void)
{
    uint8_t i;
    uint32_t now = HAL_GetTick();
    for (i = 0u; i < DI_CH_NUM; i++)
    {
        s_di[i].raw         = DI_ReadRawLevel(i);
        s_di[i].stable      = s_di[i].raw;
        s_di[i].last_change = now;
    }
}

/**
  * @brief  周期消抖扫描函数,主循环定时调用
  * @note  检测电平跳变重置计时,稳定达到消抖时长后更新可靠状态
  */
void BSP_DI_Scan(void)
{
    uint8_t  i;
    uint8_t  cur;
    uint32_t now = HAL_GetTick();

    for (i = 0u; i < DI_CH_NUM; i++)
    {
        cur = DI_ReadRawLevel(i);
        if (cur != s_di[i].raw)
        {
            s_di[i].raw         = cur;
            s_di[i].last_change = now;
        }
        else
        {
            if ((cur != s_di[i].stable) && ((now - s_di[i].last_change) >= DI_DEBOUNCE_MS))
            {
                s_di[i].stable = cur;
            }
        }
    }
}

/**
  * @brief  获取单路消抖完成后的DI状态
  * @param  ch 通道号 1~4
  * @retval 0无输入 / 1有输入,非法通道返回0
  */
uint8_t BSP_DI_Get(uint8_t ch)
{
    if (ch < 1u || ch > DI_CH_NUM)
    {
        return 0u;
    }
    return s_di[ch - 1u].stable;
}

/**
  * @brief  获取四路DI整体状态掩码
  * @retval bit0~bit3 对应 DI1~DI4,bit置1代表有输入
  */
uint8_t BSP_DI_GetAll(void)
{
    uint8_t i;
    uint8_t mask = 0u;
    for (i = 0u; i < DI_CH_NUM; i++)
    {
        if (s_di[i].stable)
        {
            mask |= (uint8_t)(1u << i);
        }
    }
    return mask;
}

/**
  * @brief  获取单路未消抖原始电平,仅调试诊断使用
  * @param  ch 通道号 1~4
  * @retval 1低电平有输入 / 0无输入,非法通道返回0
  */
uint8_t BSP_DI_GetRaw(uint8_t ch)
{
    if (ch < 1u || ch > DI_CH_NUM)
    {
        return 0u;
    }
    return DI_ReadRawLevel(ch - 1u);
}
相关推荐
笔夏4 小时前
【移芯平台CAT1模组】烧写固件
stm32·单片机·学习
躺柒4 小时前
读半导体简史08大型机
linux·服务器·c语言·数据库·unix·ibm
wuyk5556 小时前
67.嵌入式C语言进阶:结构体指针实战指南——STM32外设、传感器数据访问的高效技巧
c语言·开发语言·stm32·单片机
我不管我就要叫小猪6 小时前
C/C++----命名空间
c语言·开发语言·c++
白白白小纯7 小时前
算法篇—返回倒数第k个节点
c语言·数据结构·算法·leetcode
无忧.芙桃7 小时前
数据结构之堆
c语言·数据结构·c++·算法·
2301_777998347 小时前
Linux线程控制——从线程创建到线程分离(第三部分:线程等待 pthread_join)
linux·运维·服务器·c语言·c++
LONGZETECH7 小时前
新能源汽车动力系统仿真硬核拆解:五系统分层架构的设计逻辑与技术权衡
c语言·开发语言·架构·汽车·汽车仿真教学软件·汽车教学软件
白白白小纯9 小时前
算法篇—链表的中间节点
c语言·数据结构·算法·leetcode