嵌入式软件通用框架

前言

一个好的软件架构,能让代码逻辑更好的理解是如何运行的。在最开始写代码的时候,我总是一股脑的从头写道尾,想到什么功能就写上去。如今工作这么久了,重新审视一下自己的以前的代码和现在的在公司里写的代码,既可以发现:以前的代码很多功能上会出现相关干扰的风险。

常用三种架构

应用程序的架构大致有三种:

1、简单的前后台顺序执行程序,这类写法是大多数人使用的方法,不需用思考程序的具体架构,直接通过执行顺序编写应用程序即可。

2、时间片轮询法,此方法是介于顺序执行与操作系统之间的一种方法。

3、操作系统,此法应该是应用程序编写的最高境界。

本篇主要介绍时间片轮询法,适用于大多低端设备,在个人的一些DIY产品上使用也是刚好可以的。

时间片轮询法

介于前后台顺序执行法操作系统之间的一种程序架构设计方案。该设计方案需能帮助嵌入式软件开发者更上一层楼,在嵌入式软件开发过程中,若遇到以下几点,那么该设计方案可以说是最优选择,适用于程序较复杂的嵌入式系统;

  • 目前的需求设计需要完全没有必要上操作系统。
  • 任务函数无需时刻执行,存在间隔时间(比如按键,一般情况下,都需要软件防抖,初学者的做法通常是延时10ms左右再去判断,但10ms极大浪费了CPU的资源,在这段时间内CPU完全可以处理很多其他事情)
  • 实时性有一定的要求。

该设计方案需要使用一个定时器,一般情况下定时1ms即可(定时时间可随意定,但中断过于频繁效率就低,中断太长,实时性差),因此需要考虑到每个任务函数的执行时间,建议不能超过1ms(能通过程序优化缩短执行时间则最好优化,如果不能优化的,则必须保证该任务的执行周期必须远大于任务所执行的耗时时间),同时要求主循环或任务函数中不能存在毫秒级别的延时。

钩子函数实现方式

#include "app_task.h"
#include "bsp_mpu6050.h"  
#include "elog.h"
#define TAG "app_task"

static void app_task_test(void);

/**
 * @brief 任务函数相关信息结构体定义.
 */
typedef struct
{
    uint8_t m_runFlag;         /*!< 程序运行标记:0-不运行,1运行 */
    uint16_t m_timer;          /*!< 计时器 */
    uint16_t m_itvTime;        /*!< 任务运行间隔时间 */
    void (*m_pTaskHook)(void); /*!< 要运行的任务函数 */
} app_task_type_t;

#define APP_TASKS_MAX 2 // 定义任务数目

/** 任务函数相关信息 */
static app_task_type_t gs_tTaskInfo[APP_TASKS_MAX] = {
    // {0, 1, 1, NULL},       // 任务     1ms
    // {0, 10, 10, NULL},     // 任务     10ms
    // {0, 20, 20, NULL},     // 任务     20ms
    {0, 500, 500, app_task_test},       // 任务     500ms
    {0, 1000, 1000, MPU6050_test_demo}, // 任务     1000ms
};

static void app_task_test(void)
{
    elog_i(TAG,"app_task_test");
}

/**
  * @brief      任务函数运行标志处理.
  * @note       该函数由1ms定时器中断调用
  * @param      None.
  * @return     None.
  */
void TASK_Remarks(void)
{
    uint8_t i;
    for (i = 0; i < APP_TASKS_MAX; i++)
    {
        if (gs_tTaskInfo[i].m_timer)
        {
            gs_tTaskInfo[i].m_timer--;
            if (0 == gs_tTaskInfo[i].m_timer)
            {
                 gs_tTaskInfo[i].m_timer = gs_tTaskInfo[i].m_itvTime;
                 gs_tTaskInfo[i].m_runFlag = 1;
            }
        }
   }
}

/**
  * @brief      任务函数运行处理.
  * @note       该函数由主循环调用
  * @param      None.
  * @return     None.
  */
void TASK_Polling(void)
{
    uint8_t i;
    for (i = 0; i < APP_TASKS_MAX; i++)
    {
        if (gs_tTaskInfo[i].m_runFlag)
        {
            gs_tTaskInfo[i].m_pTaskHook();         // 运行任务
            gs_tTaskInfo[i].m_runFlag = 0;         // 标志清0
        }
    }  
}

这里使用的一种C语言的高级用法[钩子函数],这也是一种高级的代码编写技巧。

总结

对于其他两种方式,这里也不过多说明,总体上来说在轻量级设备中,这总方式可以不用占用过多资源即可实现的一种软件架构。详细文章可以参考:嵌入式软件开发常用的三种架构你知道吗? (qq.com)

posted @ 2024-03-31 17:48  一月一星辰  阅读(39)  评论(0编辑  收藏  举报