QP 事件

    科技2022-08-08  120

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

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

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

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

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

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

    实际上,你如果吧QPn的 改一下也能实现,但是我个人认为为了保证代码 大家都能在共有的理解基础上都能看懂。

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

    也可以理解其实他就是一个状态机而已。

     

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

     

    Processed: 0.010, SQL: 8