57、QP-nano:实现轻量级嵌入式系统开发

QP-nano实现轻量级嵌入式系统开发

QP-nano:实现轻量级嵌入式系统开发

1. 主动对象结构声明原则

在开发中,不建议全局声明主动对象结构,而是在特定主动对象模块的文件作用域内声明。例如, struct TunnelTag tunnel.c 文件作用域内声明,这样能确保每个主动对象完全封装。

2. 主动对象构造函数

系统中的每个主动对象都必须提供一个“构造函数”,用于初始化主动对象实例。这些构造函数不接受“me”指针,因为它们可以访问全局主动对象实例,但可以接受其他初始化参数。例如, Missile_ctor() 接受导弹速度参数,构造函数在 main() 开始时被调用。

3. 在 QP-nano 中实现 Ship 主动对象

3.1 实现概述

在 QP-nano 中实现主动对象与完整版 QP 非常相似,需要从 QP-nano 提供的 QActive 基础结构派生具体的主动对象结构,主要工作是详细设计主动对象的状态机。与完整版 QP 的重要区别在于,QP-nano 中的状态处理函数只接受一个“me”指针作为参数,当前事件嵌入在状态机内部,可通过“me”指针访问。QP-nano 提供了 Q_SIG() Q_PAR() 宏,分别用于方便地访问当前事件的信号和标量参数。

3.2 Ship 主动对象代码实现

#include "qpn_port.h"
#include "bsp.h"
#include "game.h"

/* local objects ----------------------------------------------------------*/
typedef struct ShipTag {
    QActive super;
    /* extend the QActive class */
    uint8_t x;
    uint8_t y;
    uint8_t exp_ctr;
    uint16_t score;
} Ship;
/* the Ship active object */

static QState Ship_initial(Ship *me);
static QState Ship_active(Ship *me);
static QState Ship_parked(Ship *me);
static QState Ship_flying(Ship *me);
static QState Ship_exploding(Ship *me);

/* global objects -------------------------------------------------------*/
Ship AO_Ship;

void Ship_ctor(void) {
    Ship *me = &AO_Ship;
    QActive_ctor(&me->super, (QStateHandler)&Ship_initial);
    me->x = GAME_SHIP_X;
    me->y = GAME_SHIP_Y;
}

/* HSM definition -------------------------------------------------------*/
QState Ship_initial(Ship *me) {
    return Q_TRAN(&Ship_active);
    /* top-most initial transition */
}

QState Ship_active(Ship *me) {
    switch (Q_SIG(me)) {
    case Q_INIT_SIG: {
        /* nested initial transition */
        return Q_TRAN(&Ship_parked);
    }
    case PLAYER_SHIP_MOVE_SIG: {
        me->x = (uint8_t)Q_PAR(me);
        me->y = (uint8_t)(Q_PAR(me) >> 8);
        return Q_HANDLED();
    }
    }
    return Q_SUPER(&QHsm_top);
}

QState Ship_flying(Ship *me) {
    switch (Q_SIG(me)) {
    case Q_ENTRY_SIG: {
        me->score = 0;
        /* reset the score */
        QActive_post((QActive *)&AO_Tunnel, SCORE_SIG, me->score);
        return Q_HANDLED();
    }
    case TIME_TICK_SIG: {
        /* tell the Tunnel to draw the Ship and test for hits */
        QActive_post((QActive *)&AO_Tunnel, SHIP_IMG_SIG,
                     ((QParam)SHIP_BMP << 16)
                     | (QParam)me->x
                     | ((QParam)me->y << 8));
        ++me->score;
        /* increment the score for surviving another tick */
        if ((me->score % 10) == 0) {
            /* is the score "round"? */
            QActive_post((QActive *)&AO_Tunnel, SCORE_SIG, me->score);
        }
        return Q_HANDLED();
    }
    case PLAYER_TRIGGER_SIG: {
        /* trigger the Missile */
        QActive_post((QActive *)&AO_Missile, MISSILE_FIRE_SIG,
                     (QParam)me->x
                     | (((QParam)me->y + SHIP_HEIGHT - 1) << 8));
        return Q_HANDLED();
    }
    case DESTROYED_MINE_SIG: {
        me->score += Q_PAR(me);
        /* the score will be sent to the Tunnel by the next TIME_TICK */
        return Q_HANDLED();
    }
    case HIT_WALL_SIG:
    case HIT_MINE_SIG: {
        return Q_TRAN(&Ship_exploding);
    }
    }
    return Q_SUPER(&Ship_active);
}

3.3 代码解释

  • Ship 结构体定义了 Ship 主动对象,派生自 QActive 结构。
  • Ship_initial() 函数定义了 Ship 状态机的最顶层初始转换。
  • 状态处理函数通过 Q_SIG() 宏根据事件信号进行 switch 语句判断,使用 Q_TRAN() 宏指定转换目标,使用 Q_PAR() 宏访问事件参数。
  • QActive_post() 函数用于直接将指定的事件信号和参数发送到接收方主动对象。

3.4 状态机操作步骤

操作步骤 描述
1 定义 Ship 结构体,继承 QActive 结构。
2 实现 Ship 状态机的初始转换函数 Ship_initial()
3 实现状态处理函数,根据事件信号进行不同处理。
4 使用 Q_TRAN() 宏指定转换目标, Q_PAR() 宏访问事件参数。
5 使用 QActive_post() 函数发送事件。

3.5 状态机流程图

graph TD;
    A[Ship_initial] --> B[Ship_active];
    B --> C[Ship_parked];
    B --> D[Ship_flying];
    D --> E[Ship_exploding];
    D -->|TIME_TICK_SIG| D;
    D -->|PLAYER_TRIGGER_SIG| D;
    D -->|DESTROYED_MINE_SIG| D;
    D -->|HIT_WALL_SIG/HIT_MINE_SIG| E;

4. QP-nano 中的时间事件

4.1 时间事件概述

QP-nano 为系统中的每个主动对象维护一个私有时间事件(定时器),这些定时器可以被编程(激活),在指定的时钟滴答数后生成保留的 Q_TIMEOUT 事件。内部,QP-nano 仅将时间事件表示为一个递减计数器(通常为 2 字节的 RAM),只支持单次时间事件,因为周期性时间事件需要两倍的 RAM 来存储周期。 Q_TIMEOUT 信号在 QP-nano 中是预定义的保留信号之一。

4.2 时间事件代码示例

QState Tunnel_game_over(Tunnel *me) {
    switch (Q_SIG(me)) {
    case Q_ENTRY_SIG: {
        QActive_arm((QActive *)me, BSP_TICKS_PER_SEC/2);
        /* 1/2 sec */
        me->blink_ctr = 5*2;
        /* 5s timeout */
        BSP_drawNString((GAME_SCREEN_WIDTH - 6*9)/2, 0, "Game Over");
        return (QState)0;
    }
    case Q_EXIT_SIG: {
        QActive_disarm((QActive *)me);
        BSP_updateScore(0);
        /* clear the score on the display */
        return (QState)0;
    }
    case Q_TIMEOUT_SIG: {
        QActive_arm((QActive *)me, BSP_TICKS_PER_SEC/2);
        /* 1/2 sec */
        BSP_drawNString((GAME_SCREEN_WIDTH - 6*9)/2, 0,
                        (((me->blink_ctr & 1) != 0)
                         ? "Game Over"
                         : " "));
        if ((--me->blink_ctr) == 0) {
            /* blinked enough times? */
            Q_TRAN(&Tunnel_demo);
        }
        return (QState)0;
    }
    }
    return (QState)&Tunnel_active;
}

4.3 代码解释

  • Q_ENTRY_SIG 中激活时间事件,设置超时时间和闪烁计数器,并显示“Game Over”文本。
  • Q_EXIT_SIG 中停用时间事件,清除显示上的分数。
  • Q_TIMEOUT_SIG 中再次激活时间事件,根据闪烁计数器的值显示或隐藏“Game Over”文本,当闪烁次数达到上限时,进行状态转换。

4.4 时间事件操作步骤

操作步骤 描述
1 在状态进入时,使用 QActive_arm() 函数激活时间事件。
2 在状态退出时,使用 QActive_disarm() 函数停用时间事件。
3 处理 Q_TIMEOUT_SIG 事件,根据需要重新激活时间事件或进行状态转换。

4.5 时间事件流程图

graph TD;
    A[Q_ENTRY_SIG] --> B[QActive_arm];
    B --> C[设置 blink_ctr];
    C --> D[显示 Game Over];
    E[Q_EXIT_SIG] --> F[QActive_disarm];
    F --> G[清除分数];
    H[Q_TIMEOUT_SIG] --> I[QActive_arm];
    I --> J[判断 blink_ctr];
    J -->|!=0| K[显示或隐藏 Game Over];
    J -->|==0| L[Q_TRAN 到 Tunnel_demo];

5. “Fly ‘n’ Shoot” 应用的板级支持包(BSP)

5.1 BSP 概述

QP-nano 会调用几个特定于平台的回调函数,这些函数通常需要在板级支持包(BSP)中定义。除了回调函数,还必须定义所有的中断服务例程(ISR)。

5.2 BSP 代码示例

#include "qpn_port.h"
#include "game.h"
#include "bsp.h"

/* Local-scope objects ---------------------------------------------------*/
static void interrupt (*l_dosTmrISR)(void);
static void interrupt (*l_dosKbdISR)(void);
#define TMR_VECTOR 0x08
#define KBD_VECTOR 0x09

/*.......................................................................*/
static void interrupt tmrISR(void) {
    /* 80x86 enters ISRs with int. locked */
    QF_tick();
    /* process all armed time events */
    QActive_postISR((QActive *)&AO_Tunnel, TIME_TICK_SIG, 0);
    QActive_postISR((QActive *)&AO_Ship, TIME_TICK_SIG, 0);
    QActive_postISR((QActive *)&AO_Missile, TIME_TICK_SIG, 0);
    outportb(0x20, 0x20);
    /* write EOI to the master PIC */
}

/*.......................................................................*/
void BSP_init(void) {
    ...
}

/*.......................................................................*/
void BSP_drawBitmap(uint8_t const *bitmap, uint8_t width, uint8_t height) {
    Video_drawBitmapAt(0, 8, bitmap, width, height);
}

/*.......................................................................*/
void BSP_drawNString(uint8_t x, uint8_t y, char const *str) {
    Video_drawStringAt(x, 8 + y*8, str);
}

/*.......................................................................*/
void BSP_updateScore(uint16_t score) {
    if (score == 0) {
        Video_clearRect(68, 24, 72, 25, VIDEO_BGND_RED);
    }
    Video_printNumAt(68, 24, VIDEO_FGND_YELLOW, score);
}

/*.......................................................................*/
void QF_onStartup(void) {
    /* save the original DOS vectors ... */
    l_dosTmrISR = getvect(TMR_VECTOR);
    l_dosKbdISR = getvect(KBD_VECTOR);
    QF_INT_LOCK();
    setvect(TMR_VECTOR, &tmrISR);
    setvect(KBD_VECTOR, &kbdISR);
    QF_INT_UNLOCK();
}

/*.......................................................................*/
void QF_stop(void) {
    /* restore the original DOS vectors ... */
    if (l_dosTmrISR != (void interrupt (*)(void))0) { /* DOS vectors saved? */
        QF_INT_LOCK();
        setvect(TMR_VECTOR, l_dosTmrISR);
        setvect(KBD_VECTOR, l_dosKbdISR);
        QF_INT_UNLOCK();
    }
    _exit(0);
    /* exit to DOS */
}

/*.......................................................................*/
void QF_onIdle(void) {
    /* see NOTE01 */
    QF_INT_UNLOCK();
}

/*-----------------------------------------------------------------------*/
void Q_onAssert(char const Q_ROM * const Q_ROM_VAR file, int line) {
    ...
    QF_stop();
    /* stop QF and cleanup */
}

5.3 代码解释

  • tmrISR() 是定时器中断服务例程,调用 QF_tick() 处理所有激活的时间事件,并将 TIME_TICK 事件直接发送给需要接收的主动对象。
  • QF_onStartup() 回调函数在所有主动对象状态机启动后但事件循环开始执行前被调用,用于配置和启动中断。
  • QF_stop() 函数停止 QP-nano 并将控制权返回给操作系统,在 DOS 版本中,该函数会恢复原始中断并退出到 DOS。
  • QF_onIdle() 回调函数在中断锁定的情况下被调用,需要解锁中断。
  • Q_onAssert() 是断言失败回调函数,用于处理断言失败的情况。

5.4 BSP 操作步骤

操作步骤 描述
1 实现定时器中断服务例程 tmrISR() ,调用 QF_tick() 并发送 TIME_TICK 事件。
2 实现 QF_onStartup() 函数,配置和启动中断。
3 实现 QF_stop() 函数,停止 QP-nano 并恢复中断。
4 实现 QF_onIdle() 函数,解锁中断。
5 实现 Q_onAssert() 函数,处理断言失败。

5.5 BSP 流程图

graph TD;
    A[系统启动] --> B[QF_onStartup];
    B --> C[设置中断向量];
    D[定时器中断] --> E[tmrISR];
    E --> F[QF_tick];
    F --> G[发送 TIME_TICK 事件];
    H[系统停止] --> I[QF_stop];
    I --> J[恢复中断向量];
    K[空闲状态] --> L[QF_onIdle];
    L --> M[解锁中断];
    N[断言失败] --> O[Q_onAssert];
    O --> P[停止 QF 并清理];

6. 构建 “Fly ‘n’ Shoot” QP-nano 应用

6.1 构建概述

构建 QP-nano 应用比完整版 QP 更简单,只需要将两个 QP-nano 源文件 qepn.c qfn.c 添加到项目中,并指示编译器在 <qp>\qpn\include\ 目录中搜索头文件。如果使用 QK-nano,还需要添加 qkn.c 源文件。

6.2 构建操作步骤

操作步骤 描述
1 qepn.c qfn.c 源文件添加到项目中。
2 指示编译器在 <qp>\qpn\include\ 目录中搜索头文件。
3 如果使用 QK-nano,添加 qkn.c 源文件。
4 根据不同的编译器和平台,使用相应的项目文件进行构建。

6.3 构建流程图

graph TD;
    A[创建项目] --> B[添加源文件];
    B --> C[设置头文件搜索路径];
    C --> D[选择编译器和平台];
    D --> E[使用项目文件构建];

7. QP-nano 结构

7.1 QP-nano 结构概述

QP-nano 提供了中央基类 QActive 用于派生具体的主动对象。 QActive 类是抽象的,默认从 QHsm 层次状态机类派生,这意味着主动对象是 HSMs,并继承了 init() dispatch() 状态机接口。 QActive 还包含主动对象优先级、事件队列和时间事件计数器。

7.2 QP-nano 类结构

类名 描述
QEvent 表示 QP-nano 中的事件,事件信号 QSignal 被 typedef 为字节( uint8_t ),还包含一个标量事件参数。
QHsm 层次状态机类,包含当前事件。
QActive 抽象基类,用于派生具体的主动对象,包含优先级、事件队列和时间事件计数器。
QActiveCB 主动对象控制块结构,包含在编译时已知的只读数据元素。

7.3 QP-nano 结构流程图

graph TD;
    A[QEvent] --> B[sig: QSignal];
    A --> C[par: QParam];
    D[QHsm] --> E[init()];
    D --> F[dispatch()];
    D --> G[state: QState Handler];
    D --> H[evt: QEvent];
    I[QActive] --> J[start()];
    I --> K[post()];
    I --> L[postISR()];
    I --> M[arm()];
    I --> N[disarm()];
    I --> O[prio: uint8_t];
    I --> P[head: uint8_t];
    I --> Q[tail: uint8_t];
    I --> R[nUsed: uint8_t];
    I --> S[tickCtr: QTimeEvtCtr];
    T[QActiveCB] --> U[act: * QActive];
    T --> V[queue: * QEvent];
    T --> W[end: uint8_t];
    X[QF_active[]] --> Y[QActiveCB];
    Z[应用程序] --> I[QActive];
    Z --> A[QEvent];
    Z --> D[QHsm];
    Z --> T[QActiveCB];

通过以上内容,我们详细介绍了 QP-nano 在嵌入式系统开发中的应用,包括主动对象的实现、时间事件的处理、板级支持包的编写、应用的构建以及 QP-nano 的结构。这些知识可以帮助开发者更好地利用 QP-nano 进行轻量级嵌入式系统的开发。

基于遗传算法的新的异构分布式系统任务调度算法研究(Matlab代码实现)内容概要:本文档围绕基于遗传算法的异构分布式系统任务调度算法展开研究,重点介绍了一种结合遗传算法的新颖优化方法,并通过Matlab代码实现验证其在复杂调度问题中的有效性。文中还涵盖了多种智能优化算法在生产调度、经济调度、车间调度、无人机路径规划、微电网优化等领域的应用案例,展示了从理论建模到仿真实现的完整流程。此外,文档系统梳理了智能优化、机器学习、路径规划、电力系统管理等多个科研方向的技术体系与实际应用场景,强调“借力”工具与创新思维在科研中的重要性。; 适合人群:具备一定Matlab编程基础,从事智能优化、自动化、电力系统、控制工程等相关领域研究的研究生及科研人员,尤其适合正在开展调度优化、路径规划或算法改进类课题的研究者; 使用场景及目标:①学习遗传算法及其他智能优化算法(如粒子群、蜣螂优化、NSGA等)在任务调度中的设计与实现;②掌握Matlab/Simulink在科研仿真中的综合应用;③获取多领域(如微电网、无人机、车间调度)的算法复现与创新思路; 阅读建议:建议按目录顺序系统浏览,重点关注算法原理与代码实现的对应关系,结合提供的网盘资源下载完整代码进行调试与复现,同时注重从已有案例中提炼可迁移的科研方法与创新路径。
【微电网】【创新点】基于非支配排序的蜣螂优化算法NSDBO求解微电网多目标优化调度研究(Matlab代码实现)内容概要:本文提出了一种基于非支配排序的蜣螂优化算法(NSDBO),用于求解微电网多目标优化调度问题。该方法结合非支配排序机制,提升了传统蜣螂优化算法在处理多目标问题时的收敛性和分布性,有效解决了微电网调度中经济成本、碳排放、能源利用率等多个相互冲突目标的优化难题。研究构建了包含风、光、储能等多种分布式能源的微电网模型,并通过Matlab代码实现算法仿真,验证了NSDBO在寻找帕累托最优解集方面的优越性能,相较于其他多目标优化算法表现出更强的搜索能力和稳定性。; 适合人群:具备一定电力系统或优化算法基础,从事新能源、微电网、智能优化等相关领域研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①应用于微电网能量管理系统的多目标优化调度设计;②作为新型智能优化算法的研究与改进基础,用于解决复杂的多目标工程优化问题;③帮助理解非支配排序机制在进化算法中的集成方法及其在实际系统中的仿真实现。; 阅读建议:建议读者结合Matlab代码深入理解算法实现细节,重点关注非支配排序、拥挤度计算和蜣螂行为模拟的结合方式,并可通过替换目标函数或系统参数进行扩展实验,以掌握算法的适应性与调参技巧。
本项目是一个以经典51系列单片机——STC89C52为核心,设计实现的一款高性价比数字频率计。它集成了信号输入处理、频率测量及直观显示的功能,专为电子爱好者、学生及工程师设计,旨在提供一种简单高效的频率测量解决方案。 系统组成 核心控制器:STC89C52单片机,负责整体的运算和控制。 信号输入:兼容多种波形(如正弦波、三角波、方波)的输入接口。 整形电路:采用74HC14施密特触发器,确保输入信号的稳定性和精确性。 分频电路:利用74HC390双十进制计数器/分频器,帮助进行频率的准确测量。 显示模块:LCD1602液晶显示屏,清晰展示当前测量的频率值(单位:Hz)。 电源:支持标准电源输入,保证系统的稳定运行。 功能特点 宽频率测量范围:1Hz至12MHz,覆盖了从低频到高频的广泛需求。 高灵敏度:能够识别并测量幅度小至1Vpp的信号,适合各类微弱信号的频率测试。 直观显示:通过LCD1602液晶屏实时显示频率值,最多显示8位数字,便于读取。 扩展性设计:基础版本提供了丰富的可能性,用户可根据需要添加更多功能,如数据记录、报警提示等。 资源包含 原理图:详细的电路连接示意图,帮助快速理解系统架构。 PCB设计文件:用于制作电路板。 单片机程序源码:用C语言编写,适用于Keil等开发环境。 使用说明:指导如何搭建系统,以及基本的操作方法。 设计报告:分析设计思路,性能评估和技术细节。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值