QP 事件

所谓的事件 可以简单的理解就是消息。

一般写程序的都会用上消息队列,这个就是异步处理,因为MCU实际就一个核心,一般都是循环的程序。

只要主频快,轮询处理的速度快,就可以满足大部分的程序设计要求,目前看了很多的状态机源码,单片机基本都是这么干的。

所以消息队列是很重要的一个功能。

在QPnano中和传统的用法差不多,直接发送消息也就是数据到 缓冲中,比如按下 消息为0x0a,外部触发硬件按下被单片机检查处理后发送消息0x0A到缓冲中。

在QPc中就稍微提升了一点,他其实发送的也是数据,但是这个数据是 消息的地址,仔细想想这样就又很多可能。

这个状态机还有一个特点,是每个状态机都有自己的缓冲区,这个就有点意思了,实际上很多单片机程序都是只有一个环形缓冲。

typedef struct {
    QSignal sig;              /*!< signal of the event instance */
    uint8_t poolId_;          /*!< pool ID (0 for static event) */
    uint8_t volatile refCtr_; /*!< reference counter */
} QEvt;

void QF_poolInit(void * const poolSto, uint_fast32_t const poolSize,
                 uint_fast16_t const evtSize)
{
    /** @pre cannot exceed the number of available memory pools */
    Q_REQUIRE_ID(200, QF_maxPool_ < Q_DIM(QF_pool_));
    /** @pre please initialize event pools in ascending order of evtSize: */
    Q_REQUIRE_ID(201, (QF_maxPool_ == 0U)
        || (QF_EPOOL_EVENT_SIZE_(QF_pool_[QF_maxPool_ - 1U])
            < evtSize));

    /* perform the platform-dependent initialization of the pool */
    QF_EPOOL_INIT_(QF_pool_[QF_maxPool_], poolSto, poolSize, evtSize);
    ++QF_maxPool_; /* one more pool */

#ifdef Q_SPY
    /* generate the object-dictionary entry for the initialized pool */
    {
        char_t obj_name[9] = "EvtPool?";
        obj_name[7] = '0' + (QF_maxPool_ & 0x7FU);
        QS_obj_dict_pre_(&QF_pool_[QF_maxPool_ - 1U], obj_name);
    }
#endif /* Q_SPY*/
}
/*
 事件的内存池
 按照事件的大小设计。
 本人一般不用这些模块,尽量简化简单设计。
*/

创建状态机

void QActive_start_(QActive * const me, uint_fast8_t prio,
                    QEvt const * * const qSto, uint_fast16_t const qLen,
                    void * const stkSto, uint_fast16_t const stkSize,
                    void const * const par)
{
    (void)stkSize; /* unused parameter */

    /** @pre The priority must be in range and the stack storage must not
    * be provided, because the QV kernel does not need per-AO stacks.
    */
    Q_REQUIRE_ID(500, (0U < prio) && (prio <= QF_MAX_ACTIVE)
                      && (stkSto == (void *)0));

    QEQueue_init(&me->eQueue, qSto, qLen); /* initialize the built-in queue */
    me->prio = (uint8_t)prio; /* set the current priority of the AO */
    QF_add_(me); /* make QF aware of this active object */

    QHSM_INIT(&me->super, par, me->prio); /* top-most initial tran. */
    QS_FLUSH(); /* flush the trace buffer to the host */
}
/*
 初始化自己的消息队列
 添加状态机
 初始化状态机入口函数

*/
int_t QF_run(void) {
#ifdef Q_SPY
    uint_fast8_t pprev = 0U; /* previously used priority */
#endif

    QF_onStartup(); /* application-specific startup callback */

    /* the combined event-loop and background-loop of the QV kernel... */
    QF_INT_DISABLE();

    /* produce the QS_QF_RUN trace record */
    QS_BEGIN_NOCRIT_PRE_(QS_QF_RUN, 0U)
    QS_END_NOCRIT_PRE_()

    for (;;) {
        QEvt const *e;
        QActive *a;
        uint_fast8_t p;

        /* find the maximum priority AO ready to run */
        if (QPSet_notEmpty(&QV_readySet_)) {
            QPSet_findMax(&QV_readySet_, p);
            a = QF_active_[p];

#ifdef Q_SPY
            QS_BEGIN_NOCRIT_PRE_(QS_SCHED_NEXT, a->prio)
                QS_TIME_PRE_();     /* timestamp */
                QS_2U8_PRE_(p,      /* priority of the scheduled AO */
                            pprev); /* previous priority */
            QS_END_NOCRIT_PRE_()

            pprev = p; /* update previous priority */
#endif /* Q_SPY */

            QF_INT_ENABLE();

            /* perform the run-to-completion (RTC) step...
            * 1. retrieve the event from the AO's event queue, which by this
            *    time must be non-empty and The "Vanialla" kernel asserts it.
            * 2. dispatch the event to the AO's state machine.
            * 3. determine if event is garbage and collect it if so
            */
            e = QActive_get_(a);
            QHSM_DISPATCH(&a->super, e, a->prio);
            QF_gc(e);

            QF_INT_DISABLE();

            if (a->eQueue.frontEvt == (QEvt *)0) { /* empty queue? */
                QPSet_remove(&QV_readySet_, p);
            }
        }
        else { /* no AO ready to run --> idle */
#ifdef Q_SPY
            if (pprev != 0U) {
                QS_BEGIN_NOCRIT_PRE_(QS_SCHED_IDLE, 0U)
                    QS_TIME_PRE_();    /* timestamp */
                    QS_U8_PRE_(pprev); /* previous priority */
                QS_END_NOCRIT_PRE_()

                pprev = 0U; /* update previous priority */
            }
#endif /* Q_SPY */

            /* QV_onIdle() must be called with interrupts DISABLED because
            * the determination of the idle condition (no events in the
            * queues) can change at any time by an interrupt posting events
            * to a queue. QV_onIdle() MUST enable interrupts internally,
            * perhaps at the same time as putting the CPU into a power-saving
            * mode.
            */
            QV_onIdle();

            QF_INT_DISABLE();
        }
    }
#ifdef __GNUC__  /* GNU compiler? */
    return 0;
#endif
}
/*启动状态机,启动定时器中断,查找优先级最高的状态机,然后处理它的消息*/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值