QP-nano在PELICAN人行横道系统中的应用与分析
1. PELICAN人行横道状态机
PELICAN人行横道状态机描述了人行横道信号灯的状态转换逻辑,其完整状态图展示了各个状态之间的转换关系。下面详细介绍其工作流程:
1. 初始状态 :初始转换后,状态机进入“operational”状态,此时显示汽车红灯和行人“禁止通行”信号。
2. 汽车通行状态 :
- “operational”状态有一个嵌套的初始转换,进入“carsEnabled”子状态。
- “carsEnabled”状态又有一个嵌套的初始转换,进入“carsGreen”子状态,此时汽车信号灯变为绿色,并设置一个定时器,在“GREEN_TOUT”时钟周期后超时,该超时时间代表汽车绿灯的最短持续时间。
- “carsGreen”状态还有一个嵌套的初始转换,进入“carsGreenNoPed”子状态,这是一个叶子状态,状态机在此停止并等待。
- 当“carsGreenNoPed”状态接收到“PEDS_WAITING”事件时,状态机转换到“carsGreenPedWait”子状态,此时状态机仍处于“carsGreen”父状态,因为汽车绿灯的最短持续时间尚未结束,但通过转换到该子状态,状态机记住了行人正在等待。
- 当“carsGreenNoPed”状态接收到“Q_TIMEOUT”事件时,状态机转换到“carsGreenInt”(可中断的汽车绿灯)状态。
- “carsGreenInt”状态接收到“PEDS_WAITING”事件时,会立即转换到“carsYellow”状态,因为汽车绿灯的最短持续时间已过。
- “carsGreenPedWait”状态只处理“Q_TIMEOUT”事件,因为行人已经在等待汽车绿灯的最短持续时间结束。
3. 汽车黄灯状态 :“carsYellow”状态显示汽车黄灯,并设置一个定时器,定时器超时后,状态机转换到“pedsEnabled”状态。此转换会导致退出“carsEnabled”父状态,显示汽车红灯。
4. 行人通行状态 :
- “pedsEnabled”状态有一个嵌套的初始转换,进入“pedsWalk”子状态,此时显示行人“通行”信号,并设置一个定时器。
- 定时器超时后,状态机转换到“pedsFlash”状态,此时“禁止通行”信号闪烁。使用内部变量“me->pedFlashCtr”来计算闪烁次数。
- “Q_TIMEOUT”事件触发两个具有互补条件的内部转换。当“me->pedFlashCtr”计数器为偶数时,“禁止通行”信号打开;当计数器为奇数时,“禁止通行”信号关闭。无论哪种情况,计数器都会递减。
- 当“me->pedFlashCtr”计数器达到零时,“Q_TIMEOUT”事件触发状态机转换到“carsEnabled”状态,此转换会执行“pedsEnabled”状态的退出动作,显示行人“禁止通行”信号,PELICAN人行横道的生命周期开始重复。
5. 离线模式 :
- “operational”父状态中的“OFF”事件触发状态机转换到“offline”状态。状态层次结构确保“OFF”转换被“operational”父状态的所有直接或间接子状态继承,因此无论状态机当前处于哪个子状态,“OFF”事件都会触发转换到“offline”状态。
- “offline”状态的子状态中的“Q_TIMEOUT”事件会导致汽车和行人信号灯闪烁。
- “ON”事件可以在任何时候中断“offline”模式,触发状态机转换到“operational”状态。
1.1 状态机流程图
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px
A([初始状态]):::startend --> B(operational):::process
B --> C(carsEnabled):::process
C --> D(carsGreen):::process
D --> E(carsGreenNoPed):::process
E -->|PEDS_WAITING| F(carsGreenPedWait):::process
E -->|Q_TIMEOUT| G(carsGreenInt):::process
G -->|PEDS_WAITING| H(carsYellow):::process
F -->|Q_TIMEOUT| H
H -->|Q_TIMEOUT| I(pedsEnabled):::process
I --> J(pedsWalk):::process
J -->|Q_TIMEOUT| K(pedsFlash):::process
K -->|Q_TIMEOUT<br>me->pedFlashCtr == 0| C
B -->|OFF| L(offline):::process
L -->|ON| B
1.2 状态机主要功能总结
- “carsEnabled”和“pedsEnabled”这两个状态实现了PELICAN人行横道的主要功能,即交替允许汽车和行人通行。
- “carsEnabled”状态的退出动作通过显示汽车红灯来禁止汽车通行,“pedsEnabled”状态的退出动作通过显示行人“禁止通行”信号来禁止行人通行。状态转换的UML语义保证了无论状态以何种方式退出,这些退出动作都会被执行,从而确保行人在“pedsEnabled”状态之外始终看到“禁止通行”信号,汽车在“carsEnabled”状态之外始终看到红灯。
2. 行人活动对象
实际的PELICAN人行横道控制器硬件通常会提供一个按钮来生成“PEDS_WAITING”事件,以及一个开关来生成“ON/OFF”事件。但eZ430 USB棒没有按钮或其他提供外部输入的方式,因此需要在一个单独的状态机中模拟行人/操作员。
行人活动对象非常简单,它会定期向PELICAN活动对象发送“PEDS_WAITING”事件,并时不时地通过发送“OFF”事件和“ON”事件来使人行横道进入离线模式。
3. QP-nano移植到带有QK-nano内核的MSP430
3.1 移植概述
PELICAN和行人活动对象的源代码以及main.c模块对于所有目标CPU实际上是相同的,但每个目标都需要特定的QP-nano移植。这里介绍将QP-nano移植到带有抢占式QK-nano内核的MSP430的方法。
3.2 移植文件
QP-nano移植包括“qpn_port.h”头文件和“bsp.c”源文件中的BSP实现。
3.2.1 qpn_port.h头文件
#ifndef qpn_port_h
#define qpn_port_h
#define Q_NFSM
#define Q_PARAM_SIZE 0
#define QF_TIMEEVT_CTR_SIZE 1
/* maximum # active objects--must match EXACTLY the QF_active[] definition */
#define QF_MAX_ACTIVE 2
/* interrupt locking policy for IAR compiler */
#define QF_INT_LOCK() __disable_interrupt()
#define QF_INT_UNLOCK() __enable_interrupt()
/*#define QF_ISR_NEST*/
/* nesting of ISRs not allowed */
/* interrupt entry and exit for QK */
#define QK_ISR_ENTRY() ((void)0)
#define QK_ISR_EXIT() QK_SCHEDULE_()
#include <intrinsics.h>
/* contains prototypes for the intrinsic functions */
#include <stdint.h>
/* Exact-width integer types. WG14/N843 C99 Standard */
#include "qepn.h"
/* QEP-nano platform-independent public interface */
#include "qfn.h"
/* QF-nano platform-independent public interface */
#include "qkn.h"
/* QK-nano platform-independent public interface */
#endif
/* qpn_port_h */
- 配置说明 :
- PELICAN人行横道应用程序使用两个活动对象(PELICAN和行人)。
- IAR编译器提供了非常高效的用于锁定和解锁中断的内联函数。
- 此QP移植不允许ISR嵌套。
- QK-nano的中断进入和退出宏与中断嵌套策略一致。
- IAR头文件
<intrinsics.h>提供了内联函数的声明,如__disable_interrupt()和__enable_interrupt()。 - IAR编译器符合C99标准,提供了标准头文件
<stdint.h>,用于定义精确宽度的整数类型。 - 通过包含“qkn.h”头文件来配置QK-nano。
3.2.2 bsp.c源文件
#pragma vector = TIMERA0_VECTOR
__interrupt void timerA_ISR(void) {
/* see NOTE01 */
QK_ISR_ENTRY();
/* inform QK-nano about ISR entry */
QF_tick();
QK_ISR_EXIT();
/* inform QK-nano about ISR exit */
}
/*.......................................................................*/
void BSP_init(void) {
WDTCTL = (WDTPW | WDTHOLD);
/* Stop WDT */
P1DIR |= 0x01;
/* P1.0 output */
CCR0 = ((BSP_SMCLK + BSP_TICKS_PER_SEC/2) / BSP_TICKS_PER_SEC);
TACTL = (TASSEL_2 | MC_1);
/* SMCLK, upmode */
}
/*.......................................................................*/
void QF_onStartup(void) {
CCTL0 = CCIE;
/* CCR0 interrupt enabled */
}
/*.......................................................................*/
void QK_onIdle(void) {
/* see NOTE02 */
__low_power_mode_1();
/* adjust the low-power mode to your application */
}
/*.......................................................................*/
void BSP_signalPeds(enum BSP_PedsSignal sig) {
if (sig == PEDS_DONT_WALK) {
LED_on();
}
else {
LED_off();
}
}
/*......................................................................*/
void Q_onAssert(char const Q_ROM * const Q_ROM_VAR file, int line) {
(void)file;
/* avoid compiler warning */
(void)line;
/* avoid compiler warning */
for (;;) {
}
}
- 代码说明 :
- QK-nano可以使用C编译器合成的ISR。在MSP430中,大多数CPU的ISR在进入时会锁定中断。
-
QK_ISR_ENTRY()宏通知QK-nano进入ISR。 - ISR调用为ISR上下文设计的QP-nano服务。
-
QK_ISR_EXIT()宏通知QK-nano退出ISR。 - BSP初始化配置系统时钟滴答定时器,使其以预定义的速率“BSP_TICKS_PER_SEC”(在“bsp.h”中设置为20Hz)滴答。
- 启动回调函数启用系统时钟滴答ISR,这是PELICAN人行横道应用程序中唯一的ISR。
- QK-nano内核的空闲回调函数将进入LPM1模式,这是超低功耗MSP430架构中可用的多种低功耗睡眠模式之一。在实际应用中,应根据具体需求调整电源模式。
3.3 移植总结
使用抢占式内核在PELICAN人行横道示例中并不是很必要,因为该应用程序的定时要求较为宽松。这里介绍抢占式QP-nano配置主要是为了证明QK-nano内核非常轻量级,甚至可以适应内存受限的MCU,如MSP430-F2013。
4. QP-nano内存使用情况
4.1 内存使用表格
为了让你了解QP-nano的内存使用情况,下面的表格展示了不同配置宏设置下QP-nano组件的内存占用情况。数据分别来自IAR编译器针对MSP430 v4.10A(KickStart版本)和ARM Cortex-M3 v5.11(同样是KickStart版本),两种情况都选择了优化级别“High/Size”。
4.1.1 MSP430内存使用情况
| 配置参数 | qepn.c (RAM/ROM) | qfn.c (RAM/ROM) | qkn.c (RAM/ROM) | QP-nano 总计 (RAM/ROM) | 配置编号 |
|---|---|---|---|---|---|
| Q_NFSM | Q_NHSM | Q_PARAM_SIZE | QF_TIMEEVT_CTR_SIZE | QF_MAX_ACTIVE | QK_PREEMPTIVE |
| √ | 0 | 0 | 4 | 0/110 | 6/420 |
| √ | 2 | 0 | 4 | 0/110 | 6/474 |
| √ | 0 | 0 | 8 | 0/110 | 6/504 |
| √ | 2 | 2 | 8 | 0/110 | 9/578 |
| √ | 2 | 2 | 8 | 0/634 | 9/578 |
| 2 | 2 | 8 | 0/722 | 9/578 | N/A |
| √ | 0 | 0 | 4 | √ | 0/110 |
| √ | 2 | 0 | 4 | √ | 0/110 |
| √ | 0 | 0 | 8 | √ | 0/110 |
| √ | 2 | 2 | 8 | √ | 0/110 |
| √ | 2 | 2 | 8 | √ | 0/634 |
| 2 | 2 | 8 | √ | 0/722 | 6/313 |
4.1.2 ARM Cortex-M3内存使用情况
| 配置参数 | qepn.c (RAM/ROM) | qfn.c (RAM/ROM) | qkn.c + qkn.s (RAM/ROM) | QP-nano 总计 (RAM/ROM) | 配置编号 |
|---|---|---|---|---|---|
| Q_NFSM | Q_NHSM | Q_PARAM_SIZE | QF_TIMEEVT_CTR_SIZE | QF_MAX_ACTIVE | QK_PREEMPTIVE |
| √ | 0 | 0 | 4 | 0/110 | 12/406 |
| √ | 2 | 0 | 4 | 0/110 | 12/456 |
| √ | 0 | 0 | 8 | 0/110 | 12/426 |
| √ | 2 | 2 | 8 | 0/110 | 13/550 |
| √ | 2 | 2 | 8 | 0/620 | 13/550 |
| 2 | 2 | 8 | 0/702 | 13/550 | N/A |
| √ | 0 | 0 | 4 | √ | 0/110 |
| √ | 2 | 0 | 4 | √ | 0/110 |
| √ | 0 | 0 | 8 | √ | 0/110 |
| √ | 2 | 2 | 8 | √ | 0/110 |
| √ | 2 | 2 | 8 | √ | 0/620 |
| 2 | 2 | 8 | √ | 0/702 | 9/334 |
4.2 内存使用分析
- 配置说明 :表格中列出了不同的配置参数设置,包括是否使用非分层有限状态机(Q_NFSM)、分层状态机(Q_NHSM)、事件参数大小(Q_PARAM_SIZE)、时间事件计数器大小(QF_TIMEEVT_CTR_SIZE)、最大活动对象数量(QF_MAX_ACTIVE)以及是否使用抢占式内核(QK_PREEMPTIVE)。
- 内存占用分析 :
- 不同的QP-nano配置分为非抢占式“普通”内核(配置1 - 6)和抢占式QK-nano内核(配置7 - 12)。在每个组中,较简单的配置排在前面,较复杂的配置排在后面。
- 配置1是绝对最小配置,它消除了HSM代码(仅提供基本的FSM支持),不使用事件参数和时间事件,最多支持四个活动对象。这种最小配置的功能非常有限。
- 配置4已经相对合理,它仍然只提供非分层FSM,但包括事件参数、时间事件和最多八个活动对象,代码空间成本不到700字节。
- 到目前为止,最昂贵的功能(就ROM而言)是HSM支持,大约需要650字节(例如,比较配置4和5或10和11)。
- 相比之下,QK-nano抢占式内核与“普通”内核相比,ROM占用仅增加50 - 100字节。显然,QK-nano的真正成本在于增加的堆栈需求,而表格中并未显示这一点。
- 与使用IAR编译器为Cortex-M3编译的完整版QP4相比,配置八个活动对象时,完整版QP4需要2,718字节的ROM(QEP组件616字节,QF组件2,102字节)和121字节的RAM,这大致相当于表2中QP-nano的配置6。
4.3 内存使用总结
MSP430和Cortex-M3都具有良好的代码密度,IAR编译器为这些CPU架构生成了出色的机器代码。因此,表格中的数据应被视为QP-nano的最小内存占用,而不是平均结果。表格的主要目的是让你大致了解各种选项的相对成本,而不是提供绝对准确的测量值。需要注意的是,表格仅显示了QP-nano组件直接使用的内存,不包括应用程序所需的内存,特别是堆栈使用情况或活动对象及其事件队列所需的RAM。
5. 总结与展望
5.1 QP - nano的优势总结
- 轻量级与可扩展性 :QP - nano是一个轻量级的事件驱动框架,能够扩展到非常小的系统,从大约2KB的ROM和100字节左右的RAM开始就能运行。这使得它非常适合低功耗、内存受限的MCU,如MSP430 - F2013等。
- UML风格支持 :支持UML风格的分层状态机和活动对象,这种设计方式使得系统的状态转换逻辑更加清晰,易于理解和维护。例如在PELICAN人行横道状态机中,通过分层状态机可以清晰地描述信号灯的各种状态转换。
- 配置灵活性 :通过不同的配置宏设置,可以根据具体应用需求灵活调整QP - nano的功能和内存使用情况。可以选择是否使用分层状态机、事件参数、时间事件等,还能决定是否采用抢占式内核。
5.2 不同配置的选择建议
- 简单应用场景 :如果应用场景对功能要求较低,如只需要基本的有限状态机支持,且对内存使用非常敏感,可以选择类似配置1的最小配置。这种配置不使用分层状态机、事件参数和时间事件,最多支持四个活动对象,内存占用最小。
- 中等复杂度应用 :对于中等复杂度的应用,配置4是一个不错的选择。它提供了事件参数、时间事件和最多八个活动对象的支持,代码空间成本不到700字节,能满足大多数中等规模应用的需求。
- 需要分层状态机的应用 :如果应用需要处理复杂的状态转换逻辑,分层状态机(HSM)是必不可少的。但需要注意的是,HSM支持会显著增加ROM的占用,大约需要650字节。在选择时需要权衡功能需求和内存成本。
- 对实时性要求较高的应用 :如果应用对实时性要求较高,需要使用抢占式内核。虽然QK - nano抢占式内核与“普通”内核相比,ROM占用仅增加50 - 100字节,但会增加堆栈需求。在实际应用中,需要根据系统的内存情况和实时性要求来决定是否使用。
5.3 未来发展方向
- 进一步优化内存使用 :随着MCU的不断发展,对内存使用的要求也越来越高。未来可以进一步研究如何优化QP - nano的内存使用,减少不必要的内存开销,使其能够适应更小的系统。
- 支持更多的硬件平台 :目前QP - nano已经支持MSP430和ARM Cortex - M3等平台,但随着硬件技术的不断发展,可能会有更多新型的MCU出现。未来可以考虑将QP - nano移植到更多的硬件平台上,扩大其应用范围。
- 与其他技术的融合 :可以探索将QP - nano与其他技术,如物联网、人工智能等进行融合,开发出更具创新性的应用。例如,在智能交通系统中,结合QP - nano的状态机控制和物联网技术,可以实现更加智能的人行横道控制。
5.4 总结流程图
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
A([QP - nano优势]):::startend --> B(轻量级与可扩展性):::process
A --> C(UML风格支持):::process
A --> D(配置灵活性):::process
E([配置选择建议]):::startend --> F(简单应用选最小配置):::process
E --> G(中等应用选配置4):::process
E --> H(需HSM权衡内存):::process
E --> I(实时性高选抢占内核):::process
J([未来发展方向]):::startend --> K(优化内存使用):::process
J --> L(支持更多平台):::process
J --> M(与其他技术融合):::process
5.5 总结表格
| 方面 | 详情 |
|---|---|
| QP - nano优势 | 轻量级、可扩展性强,支持UML风格,配置灵活 |
| 配置选择建议 | 简单应用选最小配置;中等应用选配置4;需HSM权衡内存;实时性高选抢占内核 |
| 未来发展方向 | 优化内存使用,支持更多平台,与其他技术融合 |
通过对QP - nano在PELICAN人行横道系统中的应用分析,我们可以看到QP - nano在嵌入式系统开发中具有很大的优势和潜力。在未来的嵌入式系统开发中,QP - nano有望在更多的领域得到应用,为开发者提供更加高效、灵活的解决方案。
超级会员免费看

949

被折叠的 条评论
为什么被折叠?



