额, 一般情况下, 如果项目不是很复杂, 我们倾向于采用裸机开发, 如果项目稍微复杂点, 我们就倾向于采用RTOS, 例如UCOS, FreeRTOS...
其实, 我们还有一条更加"中庸"的道路...
注意事项如下:
1> 如下代码参考于<<时间触发嵌入式系统设计模式>>...
2> 我的demo实验环境: MDK5 + 战舰F1开发板
3> 代码的注释部分请直接代码(我在代码关键部分都写中文注释了)
4> 此部分代码我只是在实验中验证过, 用在项目上请自行修改和评估(书上代码被我修改了一点).
5> 欢迎大家批评指正, 期望能看到大神修改,优化,并最终产生一个可供大家用在实际项目的源码...
6> 最后附上程序demo (<<时间触发嵌入式系统设计模式>>pdf太大, 大家自行到网上下载...)
/***********************************************************************************************
* 移植注意事项:
* <1> 调度器最多支持任务数目不能超过SCHEDULER_MAX_TASK_NUM.
* <2> SCHEDULER_DEBUG=1开启调试, =0关闭调试.
* <3> 每个任务的运行时间应当小于时标间隔, 可以通过SCHEDULER_DispatchTask()中的SCHEDULER_Assert()进行测试.
* <4> 尽量不要让任务运行时间重叠, 可使用Delay进行调节.
* <5> 如果有必要的话, 可以让MCU在运行完任务之后, 未进入下一个时标的时间间隔内进入休眠模式(通过定时中断唤醒), 降低功耗.
* <6> 所有的任务都必须是非阻塞的, 包括任务中所调用的函数.
*
* 混合式调度器临界问题:
* <1> 抢占式任务 因为它们不能被中断, 所以不存在在检查和加锁之间出现中断.
* <2> 合作式任务 可能会在检查和加锁之间被中断, 但是抢占式任务会一直执行到完成, 所以系统的状态会恢复到抢占式任务抢占之前的状态.
* if (xxx == LOCKED) return;
* xxx = LOCKED;
* 处理数据...
* xxx = UNLOCKED;
*
* 混合式调度器注意事项:
* <1> 必须保证任务不会重叠.
* <2> 实现一个抢占式任务, 该任务一般(然而并非一定)将在每个时标被调用, 该抢占式任务一般用来处理紧急事件(快速响应外部事件).
* <3> 抢占式任务必须尽量简短, 不要超过时标间隔一半!!!
***********************************************************************************************/
主要数据结构:
[mw_shl_code=c,true]typedef struct
{
volatile uint32_t Delay; /* 任务具体的延时时间(以定时器的时标为单位) */
volatile uint32_t Period; /* 任务两次运行的时间间隔(如果是周期运行的任务) */
volatile uint32_t RunCounts; /* 任务可运行的次数(如果是0, 表示当前任务没有运行的权限) */
volatile uint32_t Cooperation; /* =1表示是合作式调度任务, =0表示是抢占式调度任务 */
TaskCallBack_t Task; /* 任务回调函数 */
void *Arg; /* 任务回调函数参数 */
}Scheduler_t;[/mw_shl_code]
1> 任务队列
[mw_shl_code=c,true]/* 任务队列池(所有的任务都是放在这个队列池中) */
static Scheduler_t SchedulerTasksPool[SCHEDULER_MAX_TASK_NUM]; [/mw_shl_code]
2> 初始化调度器
[mw_shl_code=c,true]void SCHEDULER_Init(void)
{
uint32_t index;
/* 初始化硬件定时器, 以产生标准的定时时标 */
TIM2_Init();
/* 调用SCHEDULER_DeleteTask初始化任务相关成员 */
for (index=0; index<SCHEDULER_MAX_TASK_NUM; index++)
{
SCHEDULER_DeleteTask(index);
}
}[/mw_shl_code]
3> 添加任务
[mw_shl_code=c,true]uint32_t SCHEDULER_AddTask(TaskCallBack_t const Task, void * const Arg, uint32_t Delay, uint32_t Period, uint32_t Cooperation)
{
uint32_t index = 0;
while ((SchedulerTasksPool[index].Task) && (index<SCHEDULER_MAX_TASK_NUM)) index++;
#if SCHEDULER_DEBUG
SCHEDULER_Assert(index>=SCHEDULER_MAX_TASK_NUM, "The task index is out of range!!!");
#endif
SchedulerTasksPool[index].Delay = Delay;
SchedulerTasksPool[index].Period = Period;
SchedulerTasksPool[index].RunCounts = 0;
SchedulerTasksPool[index].Cooperation = Cooperation;
SchedulerTasksPool[index].Task = Task;
SchedulerTasksPool[index].Arg = Arg;
return index;
}[/mw_shl_code]
4> 删除任务
[mw_shl_code=c,true]void SCHEDULER_DeleteTask(uint32_t TaskIndex)
{
if (TaskIndex >= SCHEDULER_MAX_TASK_NUM) return;
if (SchedulerTasksPool[TaskIndex].Task == NULL) return;
SchedulerTasksPool[TaskIndex].Delay = 0;
SchedulerTasksPool[TaskIndex].Period = 0;
SchedulerTasksPool[TaskIndex].RunCounts = 0;
//SchedulerTasksPool[TaskIndex].Cooperation = 1;
SchedulerTasksPool[TaskIndex].Task = NULL;
SchedulerTasksPool[TaskIndex].Arg = NULL;
}[/mw_shl_code]
5>启动任务
[mw_shl_code=c,true]void SCHEDULER_StartTask(void)
{
TIM_Cmd(TIM2, ENABLE);
}[/mw_shl_code]
6> 调度和运行任务
[mw_shl_code=c,true]void SCHEDULER_DispatchTask(void)
{
uint32_t index;
for (index=0; index<SCHEDULER_MAX_TASK_NUM; index++)
{
/* 如果当前任务Task未被注册呢?
* 由于一开始已经初始化了调度器, 如果未初始化Task, 那此时Count肯定=0 */
if ((SchedulerTasksPool[index].RunCounts > 0) && (SchedulerTasksPool[index].Cooperation))
{
SchedulerTasksPool[index].RunCounts--;
SchedulerTasksPool[index].Task(SchedulerTasksPool[index].Arg);
if (SchedulerTasksPool[index].Period == 0)
{
SCHEDULER_DeleteTask(index);
}
/* 为了保证所有任务的运行时间<时标间隔, 最好的测试方法是将每个任务的Period设置为1, 并开启SCHEDULER_DEBUG,
测试RunCounts是否会一直增加, 如果会的话, 说明当前任务的运行时间超过一个时标间隔. */
#if SCHEDULER_DEBUG
SCHEDULER_Assert(SchedulerTasksPool[index].RunCounts>1, "The task execution time is out of range!!!");
#endif
}
}
//如果满足任务运行条件, 如果任务运行时间小于时标间隔, 那么剩余时间可以让MCU进行休眠, 降低功耗...
//如果不满足任务运行条件, 那么整个时标间隔(的所有时间)都让MCU进行休眠, 降低功耗...
}
[/mw_shl_code]
7>调度更新
[mw_shl_code=c,true]void SCHEDULER_Update(void)
{
uint32_t index;
for (index=0; index<SCHEDULER_MAX_TASK_NUM; index++)
{
if (SchedulerTasksPool[index].Task)
{
if (SchedulerTasksPool[index].Delay == 0)
{
/* 合作式调度任务 */
if (SchedulerTasksPool[index].Cooperation)
{
SchedulerTasksPool[index].RunCounts++;
}
/* 抢占式调度任务 */
else
{
SchedulerTasksPool[index].Task(SchedulerTasksPool[index].Arg);
/* 如果是抢占式调度任务, 保留RunCounts似乎没有意义 */
//SchedulerTasksPool[index].RunCounts--;
if (SchedulerTasksPool[index].Period == 0)
{
SchedulerTasksPool[index].Task = NULL;
}
}
if (SchedulerTasksPool[index].Period > 0)
{
SchedulerTasksPool[index].Delay = SchedulerTasksPool[index].Period;
}
}
else
{
SchedulerTasksPool[index].Delay--;
}
}
}
}
[/mw_shl_code]
一周热门 更多>