裸机程序架构-时间片轮询架构

XxxTimeSlice

介绍

简介

XxxTimeSlice时间片轮询,是一种裸机程序架构。基于外部提供的tick(systick中断或定时器中断),根据注册生成多种时间片(支持0*tick)提供给任务当tick,让多个任务按指定频率依次执行。其核心思想是定时器的分时复用。适合中小型项目的裸机开发,结合状态机可以有效消除程序中不合理的delay阻塞延时。

获取方式

我的CSDN资源
源码仓库

特性

  • 基于链表,注册时方便且不限数量;
  • 支持0tick,即非定时任务的注册;

本人实际应用场景

1. 资源比较紧张的单片机项目中;

期待别的小伙伴能应用到其他的场景中,最大化开发驱动潜力

格式

编码格式:UTF-8
注释格式:doxygen

文件介绍

Example

提供了示例例程;

README_Picture

README文档内用到的图片

LICENSE

许可证,遵循MIT协议

README.md

说明文档

XxxTimeSlice.c 和 XxxTimeSlice.h

核心代码


注意事项

  • 该架构并没有中途切换任务、上下文切换等操作系统的功能,所以仍然存在裸机开发的通病,每个任务会相互影响实时性,所以应当尽可能设计让任务占用cpu时间越短(特别是频繁执行的),建议结合状态机思想编程,合理让功能分段执行,且有效消除代码中不合理的delay阻塞延时;

使用流程

提醒

  • 由于使用到"for(声明;表达式;表达式)"的特性,请选择C99或以上的标准;

移植

把XxxTimeSlice.c与XxxTimeSlice.h两个文件复制粘贴到自己工程内即可。

应用步骤

  1. 配置好systick或定时器中断;
  2. XxxTimeSlice_Produce()填进对应中断服务函数中;
  3. 定义STR_XxxTimeSlice对象;
  4. 准备好任务函数;
  5. 调用XxxTimeSlice_Register()注册任务;
  6. 调用XxxTimeSlice_Start()启动时间片轮询;
应用模版
#include "XxxTimeSlice.h"
#include "stm32f10x.h"


/********************************************systick中断服务函数********************************************/
/*2.在systick中断服务函数中调用XxxTimeSlice_Produce*/
void SysTick_Handler(void)
{
    XxxTimeSlice_Produce();
}
/********************************************systick中断服务函数 End********************************************/
/*3.定义时间片对象*/
STR_XxxTimeSlice m_timeSlice_1;
/*4.任务函数*/
void Task_1(void)
{
    ...
    return;                         /* 可以仿真打断点看进来的时间是否对应 或 自行添加打印语句 */
}
STR_XxxTimeSlice m_timeSlice_2;
void Task_2(void)
{
    ...
    return;                         /* 可以仿真打断点看进来的时间是否对应 或 自行添加打印语句 */
}


int main(void)
{
    /*1.配置systick*/
    SysTick_Config(SystemCoreClock/ 1000);                  /* 1ms的Tick */

    /*5.注册任务*/
    XxxTimeSlice_Register(&m_timeSlice_1, Task_1, 0);       /* 0,即非定时任务(每次轮询都会执行) */
    XxxTimeSlice_Register(&m_timeSlice_2, Task_2, 10);      /* 10*1ms,即10ms运行一次 */

    /*6.启动时间片轮询*/
    XxxTimeSlice_Start();
}

完整示例MDK工程在源码仓库内


代码说明

头文件XxxTimeSlice.h

数据结构

STR_XxxTimeSlice结构体

typedef struct _STR_XxxTimeSlice{
    volatile unsigned char runFlag;         /**< 可运行标志(1:可运行/0:不可运行) */
    volatile unsigned short count;          /**< 计数器 */
    unsigned short reloadVal;               /**< 重载值 */
    void (*taskFunc)(void);                 /**< 任务函数的函数指针 */
    struct _STR_XxxTimeSlice* pNext;        /**< 指向下一个对象 */
}STR_XxxTimeSlice;
成员
调用者
初始化/读/写
权限
赋值范围限制 作用
runFlag xxx 任务函数可运行标志(1:可运行/0:不可运行)
count xxx 计数器,用于计时
reloadVal ✔xx [0,65535] 重载值,重载值*tick即任务函数的执行间隔。非零则为定时任务,零则非定时任务
taskFunc ✔xx 任务函数的函数指针
pNext xxx 指向下一个对象,用于链表操作

源文件XxxTimeSlice.c

部分源码展示

/**
* @brief        时间片生成(放到systick或定时器中断处理函数内)
* @param        null
* @return       null
* @par          注意事项:
* - null
*/
void XxxTimeSlice_Produce(void)
{
    /*遍历时间片链表*/
    for(STR_XxxTimeSlice* pTemp = pTimeSliceList; pTemp != NULL; pTemp = pTemp->pNext)
    {
        if(pTemp->reloadVal)                            /* 重载值不为0,即定时任务 */
        {
            --pTemp->count;                             /* 计数器递减 */
            if(0 == pTemp->count)                       /* 计数器递减到零 */
            {
                pTemp->runFlag = 1;                     /* 允许执行 */
                pTemp->count = pTemp->reloadVal;        /* 计数器重载 */
            }
        }
	}
}



/**
* @brief        启动时间片错位轮询(代替main的while循环)
* @param        null
* @return       null
* @par          注意事项:
* - null
*/
void XxxTimeSlice_Start(void)
{
    while(1)                                            /* 代替main的while循环 */
    {
        /*遍历时间片链表*/
        for(STR_XxxTimeSlice* pTemp = pTimeSliceList; pTemp != NULL; pTemp = pTemp->pNext)
        {
            if(pTemp->runFlag)                          /* 可运行则调用任务函数 */
            {
                if(pTemp->reloadVal)                    /* 重载值不为0,即定时任务 */
                {
                    pTemp->runFlag = 0;                 /* 可运行标志清零,开启新一轮倒计时 */
                }
                pTemp->taskFunc();
            }
        }
    }
}

完整源码在源码仓库内


你可能感兴趣的:(我的开源驱动,架构,单片机,c语言,stm32)