STM32
直播中

李晓鹏

7年用户 1263经验值
私信 关注
[问答]

UCOSIII的基础知识点汇总,总结的太棒了

UCOSIII的基础知识点汇总,总结的太棒了

回帖(1)

陈蓓萤

2021-11-30 10:36:08
功能
  


  • 帮助初学者初识UCOSIII
  • 掌握UCOSIII的基本知识,具体包括任务的创建与删除、任务的挂起与恢复、软件定时器、信号量和互斥信号量、消息的传递等

  一、简介

    μC/OS-II由Micrium公司提供,是一个可移植、可固化的、可裁剪的、占先式多任务实时内核,它适用于多种微处理器,微控制器和数字处理芯片(已经移植到超过100种以上的微处理器应用中)。同时,该系统源代码开放、整洁、一致,注释详尽,适合系统开发。 μC/OS-II已经通过联邦航空局(FAA)商用航行器认证,符合航空无线电技术委员会(RTCA)DO-178B标准。现在最新版的是μC/OS-III。
  μC/OS-II可以大致分成核心、任务处理、时间处理、任务同步与通信,CPU的移植等5个部分。
  

  • 核心部分(OSCore.c)
    是操作系统的处理核心,包括操作系统初始化、操作系统运行、中断进出的前导、时钟节拍、任务调度、事件处理等多部分。能够维持系统基本工作的部分都在这里。
  • 任务处理部分(OSTask.c)
    任务处理部分中的内容都是与任务的操作密切相关的。包括任务的建立、删除、挂起、恢复等等。因为μC/OS-II是以任务为基本单位调度的,所以这部分内容也相当重要。
  • 时钟部分(OSTime.c)
    μC/OS-II中的最小时钟单位是timetick(时钟节拍)。任务延时等操作是在这里完成的。
  • 任务同步和通信部分
    为事件处理部分,包括信号量、邮箱、邮箱队列、事件标志等部分;主要用于任务间的互相联系和对临界资源的访问。
  • 与CPU的接口部分
    是指μC/OS-II针对所使用的CPU的移植部分。由于μC/OS-II是一个通用性的操作系统,所以对于关键问题上的实现,还是需要根据具体CPU的具体内容和要求作相应的移植。这部分内容由于牵涉到SP等系统指针,所以通常用汇编语言编写。主要包括中断级任务切换的底层实现、任务级任务切换的底层实现、时钟节拍的产生和处理、中断的相关处理部分等内容。


二、基础知识
1、任务的创建
①定义相关参数


//任务优先级
#define LED1_TASK_PRIO                5
//任务堆栈大小       
#define LED1_STK_SIZE                 128
//任务控制块
OS_TCB Led1TaskTCB;
//任务堆栈       
CPU_STK LED1_TASK_STK[LED1_STK_SIZE];
//任务函数
void led1_task(void *p_arg);


②创建任务


//创建LED1任务
OSTaskCreate((OS_TCB         * )&Led1TaskTCB,               
                         (CPU_CHAR        * )"led1 task",                
                (OS_TASK_PTR )led1_task,                        
                (void                * )0,                                       
                (OS_PRIO          )LED1_TASK_PRIO,            
                (CPU_STK   * )&LED1_TASK_STK[0],       
                (CPU_STK_SIZE)LED1_STK_SIZE/10,       
                (CPU_STK_SIZE)LED1_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);


③编写任务函数


//led1任务函数
void led1_task(void *p_arg)
{
        OS_ERR err;
        p_arg = p_arg;
        while(1)
        {
                LED1=~LED1;
                OSTimeDlyHMSM(0,0,0,200,OS_OPT_TIME_HMSM_STRICT,&err); //延时500ms
        }
}


2、任务的挂起与恢复
在这里插入代码片//task1任务函数
void task1_task(void *p_arg)
{
        u8 task1_num=0;
        OS_ERR err;
        CPU_SR_ALLOC();
        p_arg = p_arg;
       
        POINT_COLOR = BLACK;
        OS_CRITICAL_ENTER();
        LCD_DrawRectangle(5,110,115,314);         //画一个矩形       
        LCD_DrawLine(5,130,115,130);                //画线
        POINT_COLOR = BLUE;
        LCD_ShowString(6,111,110,16,16,"Task1 Run:000");
        OS_CRITICAL_EXIT();
        while(1)
        {
                task1_num++;        //任务1执行次数加1 注意task1_num1加到255的时候会清零!!
                LED0= ~LED0;
                printf("任务1已经执行:%d次rn",task1_num);
                if(task1_num==5)
                {
                        OSTaskSuspend((OS_TCB*)&Task2_TaskTCB,&err);//任务1执行5次后挂起任务2
                        printf("任务1挂起了任务2!rn");
                }
                if(task1_num==10)
                {
                        OSTaskResume((OS_TCB*)&Task2_TaskTCB,&err);        //任务1运行10次后恢复任务2
                        printf("任务1恢复了任务2!rn");
                }
                LCD_Fill(6,131,114,313,lcd_discolor[task1_num%14]); //填充区域
                LCD_ShowxNum(86,111,task1_num,3,16,0x80);        //显示任务执行次数
                OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err); //延时1s
               
        }
}


3、任务同步
①定义信号量


OS_SEM        MY_SEM;                                                            //定义一个信号量,用于访问共享资源


②在开始任务中创建信号量


OSSemCreate ((OS_SEM*        )&MY_SEM,                        //创建一个信号量
                (CPU_CHAR*        )"MY_SEM",
                (OS_SEM_CTR)1,               
                (OS_ERR*        )&err);


③使用信号量


//led0任务函数
void led0_task(void *p_arg)
{
        OS_ERR err;
        p_arg = p_arg;
        while(1)
        {
                OSSemPend(&MY_SEM,0,OS_OPT_PEND_BLOCKING,0,&err);         //请求信号量
                LED0=~LED0;
               
//                share_resource=share_resource+1;
//                printf("任务1执行次数:%drn",share_resource);
//                delay_ms(1000);
//                OSSemPost (&MY_SEM,OS_OPT_POST_1,&err);                                //发送信号量
                OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err); //延时500ms
        }
}


//led1任务函数
void led1_task(void *p_arg)
{
        OS_ERR err;
        p_arg = p_arg;
        while(1)
        {
                LED1=~LED1;
                OSSemPost (&MY_SEM,OS_OPT_POST_1,&err);
//                OSSemPend(&MY_SEM,0,OS_OPT_PEND_BLOCKING,0,&err);         //请求信号量
//                share_resource=share_resource+1;
//                printf("任务2执行次数:%drn",share_resource);
                //delay_ms(2000);
                                                //发送信号量
                OSTimeDlyHMSM(0,0,2,0,OS_OPT_TIME_HMSM_STRICT,&err); //延时500ms
        }
}


4、消息传递
①定义消息队列


#define KEYMSG_Q_NUM        1        //按键消息队列的数量
#define DATAMSG_Q_NUM        4        //发送数据的消息队列的数量
OS_Q KEY_Msg;                                //定义一个消息队列,用于按键消息传递,模拟消息邮箱
OS_Q DATA_Msg;                                //定义一个消息队列,用于发送数据


②创建消息队列


//创建消息队列KEY_Msg
OSQCreate ((OS_Q*                )&KEY_Msg,        //消息队列
               (CPU_CHAR*        )"KEY Msg",        //消息队列名称
               (OS_MSG_QTY        )KEYMSG_Q_NUM,        //消息队列长度,这里设置为1
               (OS_ERR*        )&err);                //错误码
//创建消息队列DATA_Msg
OSQCreate ((OS_Q*                )&DATA_Msg,       
               (CPU_CHAR*        )"DATA Msg",       
               (OS_MSG_QTY        )DATAMSG_Q_NUM,       
               (OS_ERR*        )&err);       


③任务函数


//定时器1的回调函数
void tmr1_callback(void *p_tmr,void *p_arg)
{
        u8 *pbuf;
        static u8 msg_num;
        OS_ERR err;
        pbuf = mymalloc(SRAMIN,10);        //申请10个字节
        if(pbuf)        //申请内存成功
        {
                msg_num++;
                sprintf((char*)pbuf,"ALIENTEK %d",msg_num);
                //发送消息
                OSQPost((OS_Q*                )&DATA_Msg,               
                                (void*                )pbuf,
                                (OS_MSG_SIZE)10,
                                (OS_OPT                )OS_OPT_POST_FIFO,
                                (OS_ERR*        )&err);
                if(err != OS_ERR_NONE)
                {
                        myfree(SRAMIN,pbuf);        //释放内存
                        OSTmrStop(&tmr1,OS_OPT_TMR_NONE,0,&err); //停止定时器1
                        tmr1sta = !tmr1sta;
                        LCD_ShowString(10,150,100,16,16,"TMR1 STOP! ");
                }
        }       
}


//主任务的任务函数
void main_task(void *p_arg)
{
        u8 key,num;
        OS_ERR err;
        u8 *p;
        while(1)
        {
                key = KEY_Scan(0);  //扫描按键
                if(key)
                {
                        //发送消息
                        OSQPost((OS_Q*                )&KEY_Msg,               
                                        (void*                )&key,
                                        (OS_MSG_SIZE)1,
                                        (OS_OPT                )OS_OPT_POST_FIFO,
                                        (OS_ERR*        )&err);
                }
                num++;
                if(num%10==0) check_msg_queue(p);//检查DATA_Msg消息队列的容量
                if(num==50)
                {
                        num=0;
                        LED0 = ~LED0;
                }
                OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_PERIODIC,&err);   //延时10ms
        }
}


//按键处理任务的任务函数
void Keyprocess_task(void *p_arg)
{       
        u8 num;
        u8 *key;
        OS_MSG_SIZE size;
        OS_ERR err;
        while(1)
        {
                //请求消息KEY_Msg
                key=OSQPend((OS_Q*                        )&KEY_Msg,   
                                        (OS_TICK                )0,
                    (OS_OPT                        )OS_OPT_PEND_BLOCKING,
                    (OS_MSG_SIZE*        )&size,               
                    (CPU_TS*                )0,
                    (OS_ERR*                )&err);
                switch(*key)
                {
                        case WKUP_PRES:                //KEY_UP控制LED1
                                LED1 = ~LED1;
                                break;
                        case KEY2_PRES:                //KEY2控制蜂鸣器
                                BEEP = ~BEEP;
                                break;
                        case KEY0_PRES:                //KEY0刷新LCD背景
                                num++;
                                LCD_Fill(126,111,233,313,lcd_discolor[num%14]);
                                break;
                        case KEY1_PRES:                //KEY1控制定时器1
                                tmr1sta = !tmr1sta;
                                if(tmr1sta)
                                {
                                        OSTmrStart(&tmr1,&err);
                                        LCD_ShowString(10,150,100,16,16,"TMR1 START!");
                                }
                                else
                                {
                                        OSTmrStop(&tmr1,OS_OPT_TMR_NONE,0,&err); //停止定时器1
                                        LCD_ShowString(10,150,100,16,16,"TMR1 STOP! ");
                                }
                                break;
                }
        }
}


//显示消息队列中的消息
void msgdis_task(void *p_arg)
{
        u8 *p;
        OS_MSG_SIZE size;
        OS_ERR err;
        while(1)
        {
                //请求消息
                p=OSQPend((OS_Q*                )&DATA_Msg,   
                                  (OS_TICK                )0,
                  (OS_OPT                )OS_OPT_PEND_BLOCKING,
                  (OS_MSG_SIZE*        )&size,       
                  (CPU_TS*                )0,
                  (OS_ERR*                )&err);
                LCD_ShowString(5,270,100,16,16,p);
                myfree(SRAMIN,p);        //释放内存
                OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err); //延时1s
        }
}
举报

更多回帖

发帖
×
20
完善资料,
赚取积分