嵌入式软件编程思想之事件驱动+表驱动状态机+事件参数+优先级FIFO

在状态机 + 事件驱动的嵌入式架构中,如果所有事件都简单塞进一个 FIFO,高优先级事件可能被低优先级事件阻塞,导致实时性下降。实现事件优先级排序的核心思想是:让高优先级事件先于低优先级事件被处理,同时不破坏状态机的主逻辑。总体设计思想:把系统行为抽象为事件触发状态迁移,用 FIFO 解耦事件生产与消费,用优先级保证关键事件实时响应。

c 复制代码
`#ifndef CORE_EVENT_H
#define CORE_EVENT_H
#include <stdint.h>
#include <stdbool.h>
#define EVT_QUEUE_SIZE 8
typedef uint16_t EvtId;
typedef uint8_t  EvtPrio;
/* 事件参数 */
typedef enum {
    PARAM_NONE = 0,
    PARAM_U8,
    PARAM_U16,
    PARAM_U32,
} ParamType;

typedef union {
    uint8_t  u8;
    uint16_t u16;
    uint32_t u32;
} ParamData;

typedef struct {
    ParamType type;
    ParamData data;
} EventParam;
/* 事件 */
typedef struct {
    EvtId      id;
    EventParam param;
} Event;
/* 优先级 */
typedef enum {
    PRIO_HIGH = 0,
    PRIO_MID,
    PRIO_LOW,
    PRIO_NUM
} EvtPrioEnum;
void  Event_Init(void);
bool  Event_Post(EvtId id, const EventParam *p);
bool  Event_Get(Event *e);
#endif`
c 复制代码
#include "core_event.h"

typedef struct {
    Event buf[EVT_QUEUE_SIZE];
    uint8_t head;
    uint8_t tail;
} EventQueue;

static EventQueue s_queue[PRIO_NUM];

void Event_Init(void)
{
    for (int i = 0; i < PRIO_NUM; i++) {
        s_queue[i].head = 0;
        s_queue[i].tail = 0;
    }
}

static bool Enqueue(EventQueue *q, const Event *e)
{
    uint8_t next = (q->tail + 1) % EVT_QUEUE_SIZE;
    if (next == q->head) return false;
    q->buf[q->tail] = *e;
    q->tail = next;
    return true;
}

static bool Dequeue(EventQueue *q, Event *e)
{
    if (q->head == q->tail) return false;
    *e = q->buf[q->head];
    q->head = (q->head + 1) % EVT_QUEUE_SIZE;
    return true;
}

bool Event_Post(EvtId id, const EventParam *p)
{
    static const EvtPrio prio[] = {
        [1] = PRIO_HIGH,
        [2] = PRIO_HIGH,
        [3] = PRIO_MID,
        [4] = PRIO_LOW,
    };

    Event e = {
        .id = id,
        .param = *p
    };

    EvtPrio p = (id < sizeof(prio)) ? prio[id] : PRIO_LOW;
    return Enqueue(&s_queue[p], &e);
}

bool Event_Get(Event *e)
{
    for (int p = PRIO_HIGH; p < PRIO_NUM; p++) {
        if (Dequeue(&s_queue[p], e))
            return true;
    }
    return false;
}
c 复制代码
#ifndef CORE_FSM_H
#define CORE_FSM_H

#include "core_event.h"

typedef void (*ActionFn)(Event *e);

typedef struct {
    uint8_t   state;
    EvtId     event;
    ActionFn  action;
    uint8_t   nextState;
} FsmTable;

void FSM_Init(const FsmTable *table, uint8_t tableSize, uint8_t initState);
void FSM_Dispatch(Event *e);

#endif
c 复制代码
#include "core_fsm.h"

static const FsmTable *s_table;
static uint8_t s_tableSize;
static uint8_t s_state;

void FSM_Init(const FsmTable *table, uint8_t tableSize, uint8_t initState)
{
    s_table = table;
    s_tableSize = tableSize;
    s_state = initState;
}

void FSM_Dispatch(Event *e)
{
    for (uint8_t i = 0; i < s_tableSize; i++) {
        const FsmTable *t = &s_table[i];
        if (t->state == s_state && t->event == e->id) {
            if (t->action) t->action(e);
            s_state = t->nextState;
            return;
        }
    }
}

应用层:

c 复制代码
typedef enum {
    EVT_KEY = 1,
    EVT_TEMP,
    EVT_FAULT,
    EVT_MAX
} AppEvent;

typedef enum {
    ST_IDLE = 0,
    ST_RUN,
    ST_ERR,
    ST_MAX
} AppState;
c 复制代码
#include "core_fsm.h"
#include "app_event.h"
#include <stdio.h>

static void Act_Start(Event *e);
static void Act_Temp(Event *e);
static void Act_Fault(Event *e);
static void Act_Null(Event *e) { (void)e; }

static const FsmTable s_appFsm[] = {
    {ST_IDLE, EVT_KEY,   Act_Start, ST_RUN},
    {ST_RUN,  EVT_TEMP,  Act_Temp,  ST_RUN},
    {ST_RUN,  EVT_FAULT, Act_Fault, ST_ERR},
    {ST_ERR,  EVT_KEY,   Act_Start, ST_IDLE},
};

void App_FsmInit(void)
{
    FSM_Init(s_appFsm, sizeof(s_appFsm)/sizeof(s_appFsm[0]), ST_IDLE);
}

static void Act_Start(Event *e)
{
    printf("Start, key=%d\r\n", e->param.data.u8);
}

static void Act_Temp(Event *e)
{
    printf("Temp=%d\r\n", e->param.data.u16);
}

static void Act_Fault(Event *e)
{
    printf("Fault=%lu\r\n", e->param.data.u32);
}

主程序

c 复制代码
#include "core_event.h"
#include "core_fsm.h"
#include "app_event.h"

int main(void)
{
    EventParam p;

    Event_Init();
    App_FsmInit();

    /* 模拟事件 */
    p.type = PARAM_U8; p.data.u8 = 1;
    Event_Post(EVT_KEY, &p);

    p.type = PARAM_U16; p.data.u16 = 25;
    Event_Post(EVT_TEMP, &p);

    while (1) {
        Event e;
        if (Event_Get(&e)) {
            FSM_Dispatch(&e);
        } else {
            /* 低功耗 / 睡眠 */
        }
    }
}
相关推荐
hsjiasb34 分钟前
FreeRTOS学习(二十六)——动态内存管理heap_1到heap_5
stm32·单片机·学习·学习笔记·freertos
周洲08305 小时前
STM32 GPIO 外部中断深度解析:边沿触发 / 电平触发、NVIC 优先级配置、中断嵌套实战
stm32·单片机·嵌入式硬件
LCG元5 小时前
STM32F103 CAN 总线通信实战:标准库双机通信与过滤器配置精讲
stm32·单片机·嵌入式硬件
z20348315207 小时前
STM32单片机控制无源蜂鸣器播放《晴天》
stm32·单片机·嵌入式硬件
国科安芯9 小时前
详解ADC 规则组外部触发:CH2、CH3 与 TRGO2
运维·网络·单片机·嵌入式硬件·mcu·系统架构
ACP广源盛139246256739 小时前
WAIC2026 国产算力浪潮@ACP#YLB3118 在算力矩阵中的存储定位与落地场景
大数据·人工智能·分布式·单片机·嵌入式硬件
Dr.kangder9 小时前
嵌入式面试总结(十四)——中断处理
单片机·面试·职场和发展·架构·硬件架构·嵌入式
振南的单片机世界10 小时前
硬核菊花链:3个GPIO+无限74HC595=端口扩展“无限套娃”
arm开发·stm32·单片机·嵌入式硬件
Dr.kangder10 小时前
嵌入式面试总结(十)——流水线
单片机·嵌入式硬件·面试·职场和发展·系统架构·嵌入式
LCG元13 小时前
STM32软件模拟I2C驱动多从机实战:AHT20温湿度 + BH1750光照 + 0.96寸OLED实时显示
stm32·单片机·嵌入式硬件