主循环SYS_TICK无阻塞延迟

#include "stm32f4xx_hal.h"
#include <stdint.h>

typedef enum {
    EVT_RELAY_ON = 0,
    EVT_RELAY_OFF
} evt_type_t;

typedef struct {
    uint8_t  active;
    uint8_t  relay_id;
    uint8_t  type;
    uint8_t  token;        // 防止旧事件误执行(可选但强烈推荐)
    uint32_t deadline_ms;
} event_t;

#define MAX_EVENTS 32
#define RELAY_NUM  8

static event_t g_events[MAX_EVENTS];
static uint8_t g_relay_token[RELAY_NUM];  // 每路继电器的版本号

// 你自己实现:根据 relay_id 控制对应 GPIO
void Relay_On(uint8_t id);
void Relay_Off(uint8_t id);

// 添加事件:在 delay_ms 后执行 ON/OFF
static int Scheduler_Add(uint8_t relay_id, evt_type_t type, uint32_t delay_ms, uint8_t token)
{
    uint32_t now = HAL_GetTick();
    uint32_t deadline = now + delay_ms;

    for (int i = 0; i < MAX_EVENTS; i++) {
        if (!g_events[i].active) {
            g_events[i].active = 1;
            g_events[i].relay_id = relay_id;
            g_events[i].type = (uint8_t)type;
            g_events[i].deadline_ms = deadline;
            g_events[i].token = token;
            return 0; // ok
        }
    }
    return -1; // 队列满了
}

// 主循环里一直调用
void Scheduler_Poll(void)
{
    uint32_t now = HAL_GetTick();

    for (int i = 0; i < MAX_EVENTS; i++) {
        if (!g_events[i].active) continue;

        // 到期判断(防溢出)
        if ((int32_t)(now - g_events[i].deadline_ms) >= 0) {

            uint8_t id = g_events[i].relay_id;

            // token 检查:不一致说明被更新过,丢弃旧事件
            if (g_events[i].token == g_relay_token[id]) {
                if (g_events[i].type == EVT_RELAY_ON)  Relay_On(id);
                else                                   Relay_Off(id);
            }

            g_events[i].active = 0; // 释放槽位
        }
    }
}

// 继电器“脉冲”:立即开,ms 后关
int Relay_Pulse(uint8_t id, uint32_t ms)
{
    if (id >= RELAY_NUM) return -2;

    g_relay_token[id]++;       // 更新版本号
    Relay_On(id);              // 立即执行

    // 安排 ms 后关
    return Scheduler_Add(id, EVT_RELAY_OFF, ms, g_relay_token[id]);
}

主循环内运行

int main(void)
{
    HAL_Init();
    // ... GPIO/时钟初始化

    while (1) {
        Scheduler_Poll();

        // 比如某条件触发
        // Relay_Pulse(3, 80);
    }
}

posted @ 2026-01-27 23:18  xs314  阅读(15)  评论(0)    收藏  举报