• 【LPC54100】在M0上跑事件驱动构架(一)


    @20150216

    初次接触非对称双核MCU,由于之前好多知识不熟悉,这三天遇到不少问题。现在终于把事件驱动在M0核上跑起来了,就发一贴简单介绍下这个事件驱动构架和这几天的5410x芯片学习所得。
    关于事件驱动架构,其主要用于低功耗设计,可以很方便的进入休眠模式。一般单片机裸奔都是轮询,如:

    1. void main()
    2. {
    3.     while(1)
    4.     {
    5.         tesk1();
    6.         tesk2();
    7.         tesk3();
    8.     }
    9. }

    复制代码

    在这种轮询处理中,很难判断在何时休眠,该休眠多长时间,又该使用什么等级的休眠。

    而事件驱动的main函数如下(以VSF为例):

    1. while (1)
    2.         {
    3.                 vsfsm_poll();
    4.                 vsf_enter_critical();
    5.                 if (!vsfsm_get_event_pending())
    6.                 {
    7.                         vsf_leave_critical();
    8.                         __WFI();
    9.                 }
    10.                 else
    11.                 {
    12.                         vsf_leave_critical();
    13.                 }
    14.         }

    复制代码

    VSF在程序中增加了一个事件队列,当这个事件队列为空时,即进行休眠。休眠时间由程序所配置的唤醒定时器决定,当然一些外部硬件中断也可以唤醒。如果需要使用不同的休眠等级,那也需要做一个休眠等级管理器,不同线程要求不同的休眠等级,然后由管理器决定休眠等级。当然这些细化配置会比较麻烦…

    其实,事件驱动能干的,在RTOS中都能干,很多事情RTOS可以干的更好,更舒服。但是,事件驱动有一个最大的优点:省RAM,在很多低功耗MCU中,RAM一般比较小,RTOS虽然都能裁剪,但是每个任务所分配的堆栈不能裁剪,当任务一多,ram分配也挺烦心。而事件驱动归根到底还是裸奔,只是将线程(一个函数指针加一个事件状态)放在队列中进行管理,逐个调用而已。每个线程只花费十几个字节RAM。

    这次所用的是Simon的事件驱动VSF平台,代码是放在github上的,github.com/versaloon/vsf,21ic也有一些介绍帖,有兴趣自己去看。
    下面把示例代码献丑一下,非常非常粗糙的,帖子里的代码额外增加了中文说明

    1. // 线程1
    2. // 定义一个事件状态
    3. #define EVENT_1_USER_LOCAL_SCANF                (VSFSM_EVT_USER_LOCAL + 1)
    4. static struct vsfsm_state_t *
    5. event_1_handler(struct vsfsm_t *sm, vsfsm_evt_t evt);
    6. struct vsfsm_t event_1_sm =
    7. {
    8.         {event_1_handler}, // 初始化handler
    9. };
    10. // 用于产生间隔为5秒的周期事件定时器
    11. static struct vsftimer_timer_t event_1_timer =
    12. {
    13.         5000,        // 间隔为5秒
    14.         &event_1_sm,        // 对应状态机
    15.         EVENT_1_USER_LOCAL_SCANF, // 周期事件
    16. };
    17. struct vsfsm_state_t *
    18. event_1_handler(struct vsfsm_t *sm, vsfsm_evt_t evt)
    19. {
    20.         switch (evt)
    21.         {
    22.         case VSFSM_EVT_INIT: // 初始化事件时,被默认执行
    23.                 vsftimer_register(&event_1_timer);
    24.                 break;
    25.         case EVENT_1_USER_LOCAL_SCANF: // 周期事件处理
    26.                 Board_UARTPutSTR(“event 1rn”); // 打印出“event 1”
    27.                 print_tick();                                        // 打印出当前系统tick
    28.                 break;
    29.         default:
    30.                 break;
    31.         }
    32.         return NULL;
    33. }
    34. // 线程2,将线程间隔改为3秒
    35. #define EVENT_2_USER_LOCAL_SCANF                (VSFSM_EVT_USER_LOCAL + 1)
    36. static struct vsfsm_state_t *
    37. event_2_handler(struct vsfsm_t *sm, vsfsm_evt_t evt);
    38. struct vsfsm_t event_2_sm =
    39. {
    40.         {event_2_handler},
    41. };
    42. static struct vsftimer_timer_t event_2_timer =
    43. {
    44.         3000,
    45.         &event_2_sm,
    46.         EVENT_2_USER_LOCAL_SCANF,
    47. };
    48. struct vsfsm_state_t *
    49. event_2_handler(struct vsfsm_t *sm, vsfsm_evt_t evt)
    50. {
    51.         switch (evt)
    52.         {
    53.         case VSFSM_EVT_INIT:
    54.                 vsftimer_register(&event_2_timer);
    55.                 break;
    56.         case EVENT_2_USER_LOCAL_SCANF:
    57.                 Board_UARTPutSTR(“event 2rn”);
    58.                 print_tick();
    59.                 break;
    60.         default:
    61.                 break;
    62.         }
    63.         return NULL;
    64. }
    65. int main(void)
    66. {
    67.         // 串口初始化
    68.         board_uart_init();
    69.         // 使用utick中断唤醒
    70.         board_utick_init();
    71.         vsftimer_init();
    72.         Board_UARTPutSTR(“START!rn”);
    73.         vsfsm_init(&event_1_sm);
    74.         vsfsm_init(&event_2_sm);
    75.         vsf_leave_critical();
    76.         while (1)
    77.         {
    78.                 vsfsm_poll(); // 轮询状态机
    79.                 vsf_enter_critical();
    80.                 if (!vsfsm_get_event_pending()) // 判断是否有未处理事件
    81.                 {
    82.                         vsf_leave_critical();
    83.                         __WFI();
    84.                 }
    85.                 else
    86.                 {
    87.                         vsf_leave_critical();
    88.                 }
    89.         }
    90. }

    复制代码

    串口输出: 

    1

    PS: 现在的vsftimer并没有做休眠时间的动态管理,而是简单粗暴的定时唤醒一次,看看有没有事件需要处理。这个功能我会在后面完善。
    Simon的架构中还有很多好玩的东西,有兴趣可以去研究下。

  • 相关阅读:
    深入解析ATL 笔记1 添加一个simple object时做了什么
    分析MFC中CDialog的子类对象如何知道自己是model还是modeless的
    分析boost::signal之识别是否Trackable的派生类对象
    《转》汇编标志位
    <转> strcpy当初没有考虑到的地方
    <转>OD常用断点列表
    依赖倒转原则
    <转> xor eax, ebp” being used
    <转>NEG+SBB指令组合的用处
    函数Int3断点检测
  • 原文地址:https://www.cnblogs.com/leop/p/5015339.html
Copyright © 2020-2023  润新知