定义
UCOSIII下即使是同一优先级下,也是可以存在多个任务的。所以在同一优先级下的任务一起跑的时候,可以给每个任务设定时间(以时间片单位),当这个任务的时间片运行完了之后,就运行下一个任务(任务之间是轮回的)。
这样1->2->3->4->1这样无线轮回的。
开启
在UCOSIII配置文件中,把它打开就可以了
使用
完整代码
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "lcd.h"
#include "includes.h"
#define START_TASK_PRIO 3
#define START_STK_SIZE 128
OS_TCB StartTaskTCB;
CPU_STK START_TASK_STK[START_STK_SIZE];
void start_task(void *p_arg);
#define TASK1_TASK_PRIO 4
#define TASK1_STK_SIZE 128
OS_TCB Task1_TaskTCB;
CPU_STK TASK1_TASK_STK[TASK1_STK_SIZE];
void task1_task(void *p_arg);
#define TASK2_TASK_PRIO 4
#define TASK2_STK_SIZE 128
OS_TCB Task2_TaskTCB;
CPU_STK TASK2_TASK_STK[TASK2_STK_SIZE];
void task2_task(void *p_arg);
int main(void)
{
OS_ERR err;
CPU_SR_ALLOC();
delay_init(168);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
LCD_Init();
OSInit(&err);
OS_CRITICAL_ENTER(); //进入临界区
//创建start任务
OSTaskCreate((OS_TCB * )&StartTaskTCB,
(CPU_CHAR * )"start task",
(OS_TASK_PTR )start_task,
(void * )0,
(OS_PRIO )START_TASK_PRIO,
(CPU_STK * )&START_TASK_STK[0],
(CPU_STK_SIZE)START_STK_SIZE/10,
(CPU_STK_SIZE)START_STK_SIZE,
(OS_MSG_QTY )0,
(OS_TICK )0,
(void * )0,
(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
(OS_ERR * )&err);
OS_CRITICAL_EXIT(); //退出临界区
OSStart(&err);
}
void start_task(void *p_arg)
{
OS_ERR err;
CPU_SR_ALLOC();
p_arg = p_arg;
//代码是根据正点原子改的,这段目前没怎么看懂,但是没删,以后因该会了解到
CPU_Init();
#if OS_CFG_STAT_TASK_EN > 0u
OSStatTaskCPUUsageInit(&err);
#endif
#ifdef CPU_CFG_INT_DIS_MEAS_EN
CPU_IntDisMeasMaxCurReset();
#endif
#if OS_CFG_SCHED_ROUND_ROBIN_EN
OSSchedRoundRobinCfg(DEF_ENABLED,1,&err);
#endif
OS_CRITICAL_ENTER();
//开任务1
OSTaskCreate((OS_TCB * )&Task1_TaskTCB,
(CPU_CHAR * )"Task1 task",
(OS_TASK_PTR )task1_task,
(void * )0,
(OS_PRIO )TASK1_TASK_PRIO,
(CPU_STK * )&TASK1_TASK_STK[0],
(CPU_STK_SIZE)TASK1_STK_SIZE/10,
(CPU_STK_SIZE)TASK1_STK_SIZE,
(OS_MSG_QTY )0,
(OS_TICK )400, //时间片 400*5=2000ms
(void * )0,
(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
(OS_ERR * )&err);
//开任务2
OSTaskCreate((OS_TCB * )&Task2_TaskTCB,
(CPU_CHAR * )"task2 task",
(OS_TASK_PTR )task2_task,
(void * )0,
(OS_PRIO )TASK2_TASK_PRIO,
(CPU_STK * )&TASK2_TASK_STK[0],
(CPU_STK_SIZE)TASK2_STK_SIZE/10,
(CPU_STK_SIZE)TASK2_STK_SIZE,
(OS_MSG_QTY )0,
(OS_TICK )200, //时间片 200*5=1000ms
(void * )0,
(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
(OS_ERR * )&err);
OS_CRITICAL_EXIT();
OSTaskDel((OS_TCB*)0,&err);
}
void task1_task(void *p_arg)
{
OS_ERR err;
p_arg = p_arg;
while(1)
{
POINT_COLOR = BLUE;//蓝色
LCD_ShowString(30,130,110,16,16,"Task");
}
}
void task2_task(void *p_arg)
{
OS_ERR err;
p_arg = p_arg;
while(1)
{
POINT_COLOR = RED;//红色
LCD_ShowString(30,130,110,16,16,"Task");
}
}
效果:
根据时间片轮转调度,显示蓝色的任务执行2s之后,显示红色的任务执行1s,依次轮回。
临界区
在上面代码中,我们可以发现在创建初始任务的时候用到了一个临界区的开启和后来的关闭。为什么要开它嘞?开了它之后又啥作用嘞?
开了临界区代码保护之后,可以保护那些必须是连续执行的,不可被打断的代码在执行的时候不会被打断。
可通过宏来改变它的保护方式
当OS_CFG_ISR_POST_DEFERRED_EN
为0时,UCOSIII采用的时关中断的方式来保护,当它为1时,采用的是给调度器上锁的方式保护。