嵌入式框架Zorb Framework搭建一:嵌入式环境搭建、调试输出和建立时间系统

我是卓波,我是一名嵌入式工程师,我万万没想到我会在这里跟大家吹牛皮。

我是卓波,我是一名嵌入式工程师,我万万没想到我会在这里跟大家吹牛皮。

嵌入式框架Zorb Framework搭建过程

嵌入式框架Zorb
Framework搭建一:嵌入式环境搭建、调试输出和建立时间系统

嵌入式框架Zorb
Framework搭建二:环形缓冲区的实现

嵌入式框架Zorb
Framework搭建三:列表的实现

嵌入式框架Zorb
Framework搭建四:状态机的实现

嵌入式框架Zorb
Framework搭建五:事件的实现

嵌入式框架Zorb
Framework搭建六:定时器的实现

嵌入式框架Zorb
Framework搭建七:任务的实现

 

嵌入式框架Zorb Framework搭建过程

嵌入式框架Zorb Framework搭建一:嵌入式环境搭建、调试输出和建立时间系统

嵌入式框架Zorb Framework搭建二:环形缓冲区的实现

嵌入式框架Zorb Framework搭建三:列表的实现

嵌入式框架Zorb Framework搭建四:状态机的实现

嵌入式框架Zorb Framework搭建五:事件的实现

嵌入式框架Zorb Framework搭建六:定时器的实现

嵌入式框架Zorb Framework搭建七:任务的实现

一、前言

  在嵌入式开发中,我们常常会用到定时器,我们可以用芯片的定时器外设,可以用内核的systick,也可以使用操作系统的定时器。本篇要设计的定时器类似与操作系统的定时器,是软件定时器。如果Zorb
Framework运行在操作系统上面,大可以不使用本篇的功能,直接使用操作系统自带的定时器。

 

一、前言

  之前,我一直以为C语言只是面向过程的语言,直到我发现它也可以用来创造对象。现在,我就要用面向对象的思想来搭建一个轻量级的嵌入式框架Zorb
Framework。搭建Zorb
Framework的目的是为在不能运行Linux的芯片上快速开发应用,不用反复造轮子。

  Zorb Framework的初步设计功能有

  1、时间系统功能zf_time

  2、环形缓冲区功能zf_buffer

  3、列表功能zf_list

  4、状态机功能zf_fsm

  5、事件功能zf_event

  6、定时器功能zf_timer

  7、任务功能zf_task

  前6个功能,就可以实现纯事件驱动的程序,基本可以满足中小型嵌入式应用程序开发的需求。加上任务功能,是为了满足部分程序对实时性要求较高的需求。当然,也可以将前6个功能裁剪出来,然后运行在现有的嵌入式系统上面,这样子也可以满足实时性的需求。

二、定时器设计

  我们先来看看要实现的定时器提供什么功能:

  初步要提供的功能如下:

  1、可以设置定时时间

  2、可以设置定时器是单次还是重复运行

  3、可以设置定时器处理函数

  4、定时器函数可以直接运行或者推送异步事件

  5、可以打开和关闭定时器

  因此,初步设计的数据结构如下: 

 1 /* 定时器处理程序 */
 2 typedef void (*ITimerProcess)(void);
 3 
 4 /* 定时器结构 */
 5 typedef struct _Timer
 6 {
 7     uint8_t Priority;               /* 事件优先级 */
 8     uint32_t Interval;              /* 时间间隔(ms) */
 9     uint32_t AlarmTime;             /* 定时到达时间 */
10     bool IsAutoReset;               /* 重复运行(默认开) */
11     bool IsRunning;                 /* 是否正在运行(默认关) */
12     /* 事件的处理者,事件将推送到处理者的队列 */
13     /* 不设置处理者则本地执行(挂载Timer_process的地方) */
14     EventHandler *pEventHandler;
15     /* 处理事件 */
16     ITimerProcess TimerProcess;
17     
18     /* 开始定时器 */
19     void (*Start)(struct _Timer * const pTimer);
20     
21     /* 关闭定时器 */
22     void (*Stop)(struct _Timer * const pTimer);
23     
24     /* 重新运行定时器 */
25     void (*Restart)(struct _Timer * const pTimer);
26     
27     /* 销毁定时器(释放空间) */
28     bool (*Dispose)(struct _Timer * const pTimer);
29 } Timer;

  事件和事件处理器已经设计好了,再把定时器的处理程序添加到系统滴答程序中即可:

 1 /******************************************************************************
 2  * 描述  :系统滴答程序(需挂在硬件的时间中断里边)
 3  * 参数  :无
 4  * 返回  :无
 5 ******************************************************************************/
 6 void ZF_timeTick (void)
 7 {
 8     /* 系统滴答计数 */
 9     ZF_tick++;
10     
11     /* 软件定时器程序 */
12     Timer_process();
13 }

  具体实现请看附件代码或在文末的github地址拉框架源码。

 

二、嵌入式环境搭建

  采用STM32F429开发板作为硬件运行环境,硬件资源用到串口1和systick,其中串口1提供调试打印功能,systick提供系统时间计数功能。

  图片 1

  关于硬件环境的搭建不多说,可以参照开发板提供的例程来搭建,板级初始化完成了调试串口和systick的初始化。

 1 /****************************************************************************** 2  * 描述  :硬件环境初始化 3  * 参数  :无 4  * 返回  :无 5 ******************************************************************************/ 6 void BSP_init(void) 7 { 8     /* 嵌套向量中断控制器组选择 */ 9     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);10     11     /* 初始化调试串口 */12     Debug_USART_init();13     14     /* Systick初始化 */15     SystemTick_init();16 }17 18 /******************************************************************************19  * 描述  :硬件底层程序20  * 参数  :无21  * 返回  :无22 ******************************************************************************/23 void BSP_process(void)24 {25 26 }

三、定时器结果测试

  简单的测试代码如下:

 1 /**
 2   *****************************************************************************
 3   * @file    app_timer.c
 4   * @author  Zorb
 5   * @version V1.0.0
 6   * @date    2018-06-28
 7   * @brief   定时器测试的实现
 8   *****************************************************************************
 9   * @history
10   *
11   * 1. Date:2018-06-28
12   *    Author:Zorb
13   *    Modification:建立文件
14   *
15   *****************************************************************************
16   */
17 
18 #include "app_timer.h"
19 #include "zf_includes.h"
20 
21 /* 事件处理器 */
22 static EventHandler *pEventHandler;
23 /* 定时器1 */
24 static Timer *pTimer1;
25 /* 定时器2 */
26 static Timer *pTimer2;
27 
28 /******************************************************************************
29  * 描述  :定时器程序1
30  * 参数  :void
31  * 返回  :无
32 ******************************************************************************/
33 void TimerProcess1(void)
34 {
35     ZF_DEBUG(LOG_D, "%dms:timer process 1 run\r\n", ZF_SYSTIME_MS());
36 }
37 
38 /******************************************************************************
39  * 描述  :定时器程序2
40  * 参数  :void
41  * 返回  :无
42 ******************************************************************************/
43 void TimerProcess2(void)
44 {
45     ZF_DEBUG(LOG_D, "%dms:timer process 2 run\r\n", ZF_SYSTIME_MS());
46 }
47 
48 /******************************************************************************
49  * 描述  :任务初始化
50  * 参数  :无
51  * 返回  :无
52 ******************************************************************************/
53 void App_Timer_init(void)
54 {
55     /* 初始化事件处理器 */
56     EventHandler_create(&pEventHandler);
57     
58     /* 创建定时器1 */
59     Timer_create(&pTimer1);
60     pTimer1->Priority = 1;
61     pTimer1->Interval = 500;
62     pTimer1->TimerProcess = TimerProcess1;
63     pTimer1->IsAutoReset = true;
64     pTimer1->pEventHandler = pEventHandler;
65     pTimer1->Start(pTimer1);
66     
67     /* 创建定时器2 */
68     Timer_create(&pTimer2);
69     pTimer2->Priority = 2;
70     pTimer2->Interval = 1000;
71     pTimer2->TimerProcess = TimerProcess2;
72     pTimer2->IsAutoReset = true;
73     pTimer2->pEventHandler = pEventHandler;
74     pTimer2->Start(pTimer2);
75 }
76 
77 /******************************************************************************
78  * 描述  :任务程序
79  * 参数  :无
80  * 返回  :无
81 ******************************************************************************/
82 void App_Timer_process(void)
83 {
84     while(1)
85     {
86         /* 执行事件 */
87         if (pEventHandler->GetEventCount(pEventHandler) > 0)
88         {
89             pEventHandler->Execute(pEventHandler);
90         }
91         else
92         {
93             /* 可在此实现低功耗 */
94         }
95     }
96 }
97 /******************************** END OF FILE ********************************/

  结果:

500ms:timer process 1 run
1000ms:timer process 1 run
1002ms:timer process 2 run
1500ms:timer process 1 run
2000ms:timer process 1 run
2002ms:timer process 2 run
2500ms:timer process 1 run
3000ms:timer process 1 run
3002ms:timer process 2 run
3500ms:timer process 1 run
4000ms:timer process 1 run
4002ms:timer process 2 run
4500ms:timer process 1 run
5000ms:timer process 1 run
5002ms:timer process 2 run

省略...

  在测试程序中,定时器1周期为500ms,定时器2周期为1000ms。至于定时器2程序第一次执行的时间为1002ms的原因:定时器1和定时器2同时在1000ms处响应,但定时器1 的优先级比定时器2的优先级高,因此事件处理器先处理完定时器1的事件再处理定时器2的事件,而调试串口波特率115200,定时器1程序把调试数据发送完的时间大约2ms,因此定时器2的第一次执行时间为1002ms。

 

三、调试输出

  开发一个程序,最开始也最重要的是搭建调试的环境,我们采用串口1作为调试输出,然后调试信息分为三个等级,后续上位机可以根据不同等级进行高亮提示:

 1 /** 2   ***************************************************************************** 3   * @file    zf_debug.h 4   * @author  Zorb 5   * @version V1.0.0 6   * @date    2018-06-28 7   * @brief   调试输出的头文件 8   ***************************************************************************** 9   * @history10   *11   * 1. Date:2018-06-2812   *    Author:Zorb13   *    Modification:建立文件14   *15   *****************************************************************************16   */17 18 #ifndef __ZF_DEBUG_H__19 #define __ZF_DEBUG_H__20 21 #ifdef __cplusplus22 extern "C" {23 #endif24 25 #include "stdio.h"26 #include "stdbool.h"27 28 #define LOG_D 0; /* 信息等级:正常 */29 #define LOG_W 1; /* 信息等级:告警 */30 #define LOG_E 2; /* 信息等级:错误 */31 32 #define _ZF_DEBUG             /* 定义调试功能 */33 #define ZF_DEBUG_ON true      /* 启用调试功能 */34 35 #ifdef _ZF_DEBUG36     #if ZF_DEBUG_ON37         #define ZF_DEBUG(rank, x...) do     \38         {                                   \39             char code[10] = "[rank=0]";     \40             code[6] = '0' + (char)rank;     \41             if (code[6] != '0')             \42             {                               \43                 printf("%s", code);         \44             }                               \45             printf;                      \46         } while(0)47     #else48         #define ZF_DEBUG(rank, x...)49     #endif /* ZF_DEBUG_ON */50 #endif /* _ZF_DEBUG */51 52 #ifdef __cplusplus53 }54 #endif55 56 #endif /* __ZF_DEBUG_H__ */57 58 /******************************** END OF FILE ********************************/

四、最后

  本篇为Zorb
Framework提供了定时器功能。在对定时精度要求不高(毫秒级),完全可以使用软件定时器。软件定时器是在硬件定时器的基础上开发的,好处在于可以挂载多个定时器,不用再为芯片的定时器资源不够而烦恼。

 

  Zorb Framework
github:https://github.com/54zorb/Zorb-Framework

  版权所有,转载请打赏哟

 

如果你喜欢我的文章,可以通过微信扫一扫给我打赏哟

图片 2

四、实现断言

  在开发过程中,在关键地方进行一些断言,可以方便定位bug。

 1 /** 2   ***************************************************************************** 3   * @file    zf_assert.h 4   * @author  Zorb 5   * @version V1.0.0 6   * @date    2018-06-28 7   * @brief   断言的头文件 8   ***************************************************************************** 9   * @history10   *11   * 1. Date:2018-06-2812   *    Author:Zorb13   *    Modification:建立文件14   *15   *****************************************************************************16   */17 18 #ifndef __ZF_ASSERT_H__19 #define __ZF_ASSERT_H__20 21 #ifdef __cplusplus22 extern "C" {23 #endif24 25 #include "stdint.h"26 27 #define _ZF_ASSERT              /* 定义断言功能 */28 #define ZF_ASSERT_ON true       /* 启用断言功能 */29 30 #ifdef _ZF_ASSERT31     #if ZF_ASSERT_ON32          #define ZF_ASSERT(expression_) ((expression_) ?\33             (void)0 : ZF_assertHandle((uint8_t *)__FILE__, (int)__LINE__));34     #else35          #define ZF_ASSERT(expression_)36     #endif /* ZF_ASSERT_ON */37 #endif /* _ZF_ASSERT */38 39 /* 断言产生时的处理 */40 void ZF_assertHandle(uint8_t *pFileName, int line);41 42 #ifdef __cplusplus43 }44 #endif45 46 #endif /* __ZF_ASSERT_H__ */47 48 /******************************** END OF FILE ********************************/

  断言的处理很简单,就是告诉我们在哪个文件哪一行出错就可以,实现如下

 1 /** 2   ***************************************************************************** 3   * @file    zf_assert.c 4   * @author  Zorb 5   * @version V1.0.0 6   * @date    2018-06-28 7   * @brief   断言的实现 8   ***************************************************************************** 9   * @history10   *11   * 1. Date:2018-06-2812   *    Author:Zorb13   *    Modification:建立文件14   *15   *****************************************************************************16   */17 18 #include "zf_assert.h"19 #include "zf_debug.h"20 21 /******************************************************************************22  * 描述  :断言产生时的处理23  * 参数  :-pFileName 文件名24  *         -line 行数25  * 返回  :无26 ******************************************************************************/27 void ZF_assertHandle(uint8_t *pFileName, int line)28 {29     ZF_DEBUG(LOG_E, "file:%s line:%d:asserted\r\n", pFileName, line);30     31     while (1);32 }33 34 /******************************** END OF FILE ********************************/

五、建立时间系统

  为了减少框架对资源的消耗,所以初步设定框架的最小时间周期为1ms,因此我们需要设置systick的定时周期为1ms,然后每次进入中断为我们的框架计数即可。

 1 /****************************************************************************** 2  * 描述  :SysTick中断服务程序 3  * 参数  :无 4  * 返回  :无 5 ******************************************************************************/ 6 void SysTick_Handler(void) 7 { 8     /* 为zorb framework提供计时 */ 9     ZF_timeTick();10 }

  现在时间系统提供的功能比较基础,只有系统滴答计数和系统死等待延时,后面我们开发定时器功能和任务功能的时候会重新扩展时间系统。

 1 /** 2   ***************************************************************************** 3   * @file    zf_time.h 4   * @author  Zorb 5   * @version V1.0.0 6   * @date    2018-06-28 7   * @brief   系统时间的头文件 8   ***************************************************************************** 9   * @history10   *11   * 1. Date:2018-06-2812   *    Author:Zorb13   *    Modification:建立文件14   *15   *****************************************************************************16   */17 18 #ifndef __ZF_TIME_H__19 #define __ZF_TIME_H__20 21 #ifdef __cplusplus22 extern "C" {23 #endif24 25 #include "stdbool.h"26 #include "stdint.h"27 28 /* 系统滴答周期 */29 #define ZF_TICK_PERIOD 130 31 /* 获取系统滴答数 */32 #define ZF_SYSTICK() ZF_getSystemTick()33 34 /* 获取系统时间 */35 #define ZF_SYSTIME_MS() ZF_getSystemTimeMS()36 37 /* 系统延时 */38 #define ZF_DELAY_MS do                            \39 {                                                      \40     if (ms_ % ZF_TICK_PERIOD)                          \41     {                                                  \42         ZF_delayTick((ms_ / ZF_TICK_PERIOD) + 1);      \43     }                                                  \44     else                                               \45     {                                                  \46         ZF_delayTick(ms_ / ZF_TICK_PERIOD);            \47     }                                                  \48 } while(0)49 50 /* 获取系统滴答数 */51 uint32_t ZF_getSystemTick(void);52 53 /* 获取系统时间 */54 uint32_t ZF_getSystemTimeMS(void);55 56 /* 系统延时 */57 void ZF_delayTick(uint32_t tick);58 59 /* 系统滴答程序(需挂在硬件的时间中断里边) */60 void ZF_timeTick (void);61 62 #ifdef __cplusplus63 }64 #endif65 66 #endif /* __ZF_TIME_H__ */67 68 /******************************** END OF FILE ********************************/

 1 /** 2   ***************************************************************************** 3   * @file    zf_time.c 4   * @author  Zorb 5   * @version V1.0.0 6   * @date    2018-06-28 7   * @brief   系统时间的实现 8   ***************************************************************************** 9   * @history10   *11   * 1. Date:2018-06-2812   *    Author:Zorb13   *    Modification:建立文件14   *15   *****************************************************************************16   */17 18 #include "zf_time.h"19 20 /* 系统滴答数 */21 uint32_t ZF_tick = 0;22 23 /******************************************************************************24  * 描述  :获取系统滴答数25  * 参数  :无26  * 返回  :系统滴答数27 ******************************************************************************/28 uint32_t ZF_getSystemTick(void)29 {30     return ZF_tick;31 }32 33 /******************************************************************************34  * 描述  :获取系统时间35  * 参数  :无36  * 返回  :系统时间37 ******************************************************************************/38 uint32_t ZF_getSystemTimeMS(void)39 {40     return ZF_tick * ZF_TICK_PERIOD;41 }42 43 /******************************************************************************44  * 描述  :系统延时45  * 参数  :-tick   需要延时的系统周期数46  * 返回  :无47 ******************************************************************************/48 void ZF_delayTick(uint32_t tick)49 {50     uint32_t startTick = ZF_getSystemTick();51     while((ZF_getSystemTick() - startTick) < tick);52 }53 54 /******************************************************************************55  * 描述  :系统滴答程序(需挂在硬件的时间中断里边)56  * 参数  :无57  * 返回  :无58 ******************************************************************************/59 void ZF_timeTick (void)60 {61     /* 系统滴答计数 */62     ZF_tick++;63 }64 65 /******************************** END OF FILE ********************************/

六、最后

  本篇实现的功能比较基础,但是整个框架开发的根基,后面所有扩展的功能都需要在此环境下进行开发。搭建良好的调试输出环境,可以帮我们快速定位bug的所在,从而提高开发效率。

  本文工程代码:1-Zorb_Framework嵌入式环境搭建.rar

  Zorb Framework github:https://github.com/54zorb/Zorb-Framework

  版权所有,转载请打赏哟

如果你喜欢我的文章,可以通过微信扫一扫给我打赏哟

图片 2