QPイベント

いわゆるイベントは、単にメッセージとして理解することができます。

通常、プログラムを作成する人はメッセージキューを使用しますが、MCUは実際にはコアであり、通常は循環プログラムであるため、これは非同期処理です。

主周波数は高速で、ポーリング処理速度は高速であり、プログラム設計要件のほとんどを満たすことができます。現在、多くのステートマシンまたはシングルチップマイクロコンピュータがこれを行っています。

したがって、メッセージキューは非常に重要な機能です。

QPnでは、従来の使用法と同様です。メッセージを直接送信するのはバッファへのデータです。たとえば、プレスメッセージは0x0aであり、外部トリガーハードウェアプレスはマイクロコントローラーによってチェックおよび処理されて、メッセージ0x0Aをに送信します。バッファ。

QPcでは少し改善されています。実際、彼が送信するのはデータですが、このデータはメッセージのアドレスです。考えてみれば、多くの可能性があります。

実際、QPnを変更すれば達成することもできますが、個人的には、共通の理解に基づいてコードを誰もが理解できるようにするためだと思います。

このステートマシンのもう1つの特徴は、各ステートマシンに独自のバッファがあることです。これは少し興味深いです。実際、多くのシングルチップマイクロコンピュータプログラムには、リングバッファが1つしかありません。

彼が実際には単なるステートマシンであることも理解できます。

 

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
}
/*启动状态机,启动定时器中断,查找优先级最高的状态机,然后处理它的消息*/

 

おすすめ

転載: blog.csdn.net/C_ROOKIES/article/details/108926873