XxxTimeSlice
介绍
简介
XxxTimeSlice时间片轮询,是一种裸机程序架构。基于外部提供的tick(systick中断或定时器中断),根据注册生成多种时间片(支持0*tick)提供给任务当tick,让多个任务按指定频率依次执行。其核心思想是定时器的分时复用。适合中小型项目的裸机开发,结合状态机可以有效消除程序中不合理的delay阻塞延时。
获取方式
特性
- 基于链表,注册时方便且不限数量;
- 支持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两个文件复制粘贴到自己工程内即可。
应用步骤
- 配置好systick或定时器中断;
- 把
XxxTimeSlice_Produce()
填进对应中断服务函数中; - 定义
STR_XxxTimeSlice
对象; - 准备好任务函数;
- 调用
XxxTimeSlice_Register()
注册任务; - 调用
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();
}
}
}
}
完整源码在源码仓库内