ucos ii在stm32上使用的时候一些杂记,给自己。
1. 中断嵌套时,在中断服务函数中
OS_CPU_SR cpu_sr;
OS_ENTER_CRITICAL(); //保存全局中断标志,关总中断 Tell uC/OS-II that we are starting an ISR
OSIntNesting++;
OS_EXIT_CRITICAL(); //恢复全局中断标志
......
最后加上 OSIntExit(); //在os_core.c文件里定义,如果有更高优先级的任务就绪了,则执行一次任务切换(必须加上,因为ucosii并不一定回到之前被中断的任务现场)
2. 空闲任务OSTaskIdle永远被设为最低优先级,即os_LOWEST_PRIO,而系统任务的优先级为次低,负责统计当前CPU的利用率。
3.ucos ii一共可以支持64个任务,用户可以使用的是56个。
4.在main()函数里调用多任务OSStart()之前必须已经创建了至少一个任务,因此习惯上,在调用OSStart()之前先创建一个任务,比如命名为App_TaskStart,并赋予它最高的优先级,使其成为启始任务,然后在这个任务中建立其他的任务。
PS: 1 在调用OSStart之前,不要开启全局中断,否则系统就会崩溃。
2 在调用OSStart之前,不要启动时钟节拍器
3 在启示任务中App_TaskStart()中来启动时钟节拍器。
int main(void)
{
CPU_INT08U os_err;
/* 禁止所有中断 */
CPU_IntDis();
/* ucosII 初始化 */
OSInit();
/* 硬件平台初始化 */
BSP_Init();
//建立主任务, 优先级最高 建立这个任务另外一个用途是为了以后使用统计任务
os_err = OSTaskCreate((void (*) (void *)) App_TaskStart,
//指向任务代码的指针
(void *) 0, //任务开始执行时,传递给任务的参数的指针
(OS_STK *) &App_TaskStartStk[APP_TASK_START_STK_SIZE - 1],//分配给任务的堆栈的栈顶指针 从顶向下递减
(INT8U) APP_TASK_START_PRIO);//分配给任务的优先级
OSTimeSet(0); //ucosII的节拍计数器清0 节拍计数器是0-4294967295
OSStart(); //启动ucosII内核
return (0);
}
5 mian()函数只是负责创建任务,但是并不负责调用
6
7 任务调度器:一个是任务级调度器OS_Sched(),一个是中断级调度器OSIntEXT();
- //任务调度
- //uCOS-II总是运行进入就绪态任务中优先级最高的那一个。确定哪个任务优先级最高,下面该哪个任务运行了的工作是
- //由调度器(Scheduler)完成的。任务级的调度是由函数OSSched()完成的。中断级的调度是由另一个函数OSIntExt()完
- //成的Scheduling。
- //注意:1) 这是一个uCOS-II内部函数,你不能在应用程序中使用它
- // 2) 给调度器上锁用于禁止任务调度(查看OSSchedLock()函数)
- //说明:1)任务切换很简单,由以下两步完成,将被挂起任务的微处理器寄存器推入堆栈,然后将较高优先
- // 级的任务的寄存器值从栈中恢复到寄存器中。在uCOS-II中,就绪任务的堆栈结构总是看起来
- // 跟刚刚发生过中断一样,所有微处理器的寄存器都保存在栈中。换句话说,uCOS-II运行就绪态
- // 的任务所要做的一切,只是恢复所有的CPU寄存器并运行中断返回指令。为了做任务切换,运行
- // OS_TASK_SW(),人为模仿了一次中断。多数微处理器有软中断指令或者陷阱指令TRAP来实现上
- // 述操作。中断服务子程序或陷阱处理(Trap hardler),也称作事故处理(exception handler),
- // 必须提供中断向量给汇编语言函数OSCtxSw()。OSCtxSw()除了需要OS_TCBHighRdy指向即将被
- // 挂起的任务,还需要让当前任务控制块OSTCBCur指向即将被挂起的任务,移植uCOS-II,有关于
- // OSCtxSw()的更详尽的解释。
- // 2)OS_Sched()的所有代码都属临界段代码。在寻找进入就绪态的优先级最高的任务过程中,为防止中
- // 断服务子程序把一个或几个任务的就绪位置位,中断是被关掉的。为缩短切换时间,OSSched()全部
- // 代码都可以用汇编语言写。为增加可读性,可移植性和将汇编语言代码最少化,OSSched()是用C写的。
- //任务调度函数
- void OS_Sched (void)
- {
- #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
- OS_CPU_SR cpu_sr;
- #endif
- INT8U y; //定义一个8位整数y
- OS_ENTER_CRITICAL(); //关闭中断
- //如果中断嵌套次数>0,且上锁(调度器)嵌套次数>0,函数退出,不做任何调度
- if ((OSIntNesting == 0) && (OSLockNesting == 0)) {
- //如果函数不是在中断服务子程序中调用的,且调度允许的,则任务调度函数将找出进入就绪态的
- //最高优先级任务,进入就绪态的任务在就绪表中OSRdyTbl[]中相应位置位。
- y = OSUnMapTbl[OSRdyGrp]; /* Get pointer to HPT ready to run */
- OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
- //找到最高优先级任务后,函数检查这个优先级最高的任务是否是当前正在运行的任务,以避免不
- //必要的任务调度,多花时间
- if (OSPrioHighRdy != OSPrioCur) { /* No Ctx Sw if current task is highest rdy */
- //为实现任务切换,OSTCBHighRdy必须指向优先级最高的那个任务控制块OS_TCB,这是通过将
- //以OSPrioHighRdy为下标的OSTCBPrioTbl[]数组中的那个元素赋给OSTCBHighRdy来实现的
- OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
- OSCtxSwCtr++; //统计计数器OSCtxSwCtr加1,以跟踪任务切换次数
- OS_TASK_SW(); //最后宏调用OS_TASK_SW()来完成实际上的任务切换
- }
- }
- OS_EXIT_CRITICAL(); //打开中断
- }
#define OS_TICKS_PER_SEC 1000 /* Set the number of ticks in one second */
void OS_CPU_SysTickInit(void)
{
RCC_ClocksTypeDef rcc_clocks;
INT32U cnts;
RCC_GetClocksFreq(&rcc_clocks); //获得系统时钟的值
cnts = (INT32U)rcc_clocks.HCLK_Frequency/OS_TICKS_PER_SEC;//算出时钟节拍的值
SysTick_Config(cnts); //设置时钟节拍
}
cnts=HCLK_Frequency/OS_TICKS_PER_SEC=72M/1000;
void SysTickHandler(void)
{
OS_CPU_SR cpu_sr;
OS_ENTER_CRITICAL(); //保存全局中断标志,关总中断/* Tell uC/OS-II that we are starting an ISR*/
OSIntNesting++; //是为了中断嵌套
OS_EXIT_CRITICAL(); //恢复全局中断标志
OSTimeTick(); /* 在os_core.c文件里定义,目的是每次时钟节拍到来,μC/OS-II 都将执行OSTimeTick()函数。OSTimeTick()检查处于延时状态的任务是否达到延时时间(用OSTimeDly()或OSTimeDlyHMSM()函数延时),或检查正在等待事件的任务是否超时,如果延时时间到,则在延时函数中进行一次任务调度*/
OSIntExit(); //在os_core.c文件里定义,如果有更高优先级的任务就绪了,则执行一次任务切换
}
9.ucos ii中引起任务调度的函数 :
OSStart(); //系统启动
OSTaskSuspend() //任务挂起
OSTaskResume()//任务恢复、
OSTimeDly()/OSTimeDlyHMSM()//延时
等待事件发生(OSSempend(),OSMutexPend(),OSflagPend(),OSMboxPend(),OSQPend())
10 任务优先级
OSRdyGrp与OSRdyTbl类似于一个二维数组,可大概表达为prio[OSRdyGrp][OSRdyTbl]
要知道哪个任务就绪,只要知道OSRdyGrp,OSRdyTbl的值,然后从表中找出就可以了
验证:例如优先级为22的任务,转为二进制为00 010 110 ,转为x=2,y=6,查表得为22。
未完待续