打印
[STM32F1]

【开源】stm32f107vc金龙开发板 uC/OS-II 介绍

[复制链接]
2620|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
实验一、任务创建与删除

本节我们主要介绍的是uC/OS-II及其任务创建与删除。
1uC/OS-II介绍
对于操作系统的学习,创建任务和删除任务是最为基础的工作,uC/OS-II源代码的形式发布,是开源软件, 但并不意味着它是免费软件。可以将其用于教学和私下研究;但是如果将其用于商业用途,那么必须通过Micrium获得商用许可。
uC/OS-II属于抢占式内核,最多可以支持64个任务,分别对应优先级063每个任务只能对应唯一的优先级,其中0为最高优先级。63为最低级,系统保留了4个最高优先级的任务和4个最低优先级的任务,所有用户可以使用的任务数有56个。
uC/OS-II提供了任务管理的各种函数调用,包括创建任务,删除任务,改变任务的优先级,任务挂起和恢复等。
系统初始化时会自动产生两个任务:一个是空闲任务,它的优先级最低,该任务仅给一个整型变量做累加运算;另一个是系统任务,它的优先级为次低,该任务负责统计当前cpu的利用率。
μC/OS-II可管理多达63个应用任务,并可以提供如下服务,本章将针对以下服务分别以例程的方式来介绍
1信号量
2互斥信号量
3事件标识
4消息邮箱
5消息队列
6任务管理
7固定大小内存块管理
8时间管理

2、任务创建与删除
        想让uC/OS-II管理用户的任务,用户必须要先建立任务,在开始多任务调度(即调用OSStart())前,用户必须建立至少一个任务。uC/OS-II提供了两个函数来创建任务:OSTaskCreate()OSTaskCreateExt()可以使用其中任意一个即可,其函数原型如下:
INT8U OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio)
INT8U OSTaskCreateExt (void(*task)(void *pd),void *pdata,SD_STK *ptos,INT8U prio,INT16U                                                 id,OS_STK *pbos,INT32U stk_size,void *pext,INT16U opt)
task:任务代码指针
pdata:任务的参数指针
ptos:任务的堆栈的栈顶指针
prio:任务优先级
id:任务特殊的标识符(uC/OS-II中还未使用)
pbos:任务的堆栈栈底的指针(用于堆栈检验)
stk_size:堆栈成员数目的容量(宽度为4字节)
pext:指向用户附加的数据域的指针
opt:是否允许堆栈检验,是否将堆栈清零,任务是否要进行浮点操作等等
删除任务,是说任务将返回并处于休眠状态,任务的代码不再被uC/OS-II调用,而不是删除任务代码。删除任务主要是把任务控制块从OSTCBList链表中移到OSTCBFreeListuC/OS-II提供了两个函数来删除任务:OSTaskDel()OSTaskDelReq()
INT8U OSTaskDel (INT8U prio)        //删除任务
INT8U RequestorTask (INT8U prio)        //请求删除其他任务
prio:需要删除任务的优先级

3、实验分析
本次实验创建两个任务,任务一每隔两秒秒打印一次“AppTask1”,任务二每隔1s打印一次“AppTask2”,打印6次后打印“删除任务2”并删除任务。其源代码如下:
int  main (void)
{
        SysTick_Configuration();         //系统定时器初始化
        USART_Configuration();          //串口初始化
        LED_Configuration();
        OSInit();              //usos ii初始化
        AppTaskCreate();//创建任务
        OSStart();      //开始任务调度
}
static  void  AppTaskCreate(void)
{
INT8U  err;
OSTaskCreateExt(AppTask1,(void*)0,(OS_STK )&AppTask1Stk[APP_TASK1_STK_SIZE-1],APP_TASK1_PRIO,APP_TASK1_PRIO,(OS_STK )&AppTask1Stk[0],APP_TASK1_STK_SIZE,(void )0,OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);                //创建任务1
OSTaskNameSet(APP_TASK1_PRIO, "AppTask1", &err);
OSTaskCreateExt(AppTask2,(void*)0,(OS_STK )&AppTask2Stk[APP_TASK2_STK_SIZE-1],APP_TASK2_PRIO,APP_TASK2_PRIO,(OS_STK )&AppTask2Stk[0],APP_TASK2_STK_SIZE,(void*)0,OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);                //创建任务2
OSTaskNameSet(APP_TASK2_PRIO, "AppTask2", &err);
}
//任务1
static  void  AppTask1 (void *p_arg)
{
while(1)
{
        printf("\n\rAppTask1\r\n");
        LED1(0);
        OSTimeDlyHMSM(0,0,1,0);
        LED1(1);
        OSTimeDlyHMSM(0,0,1,0);
}
}
//任务2
static  void  AppTask2 (void *p_arg)
{
        INT8U i;
        for(i=0;i<6;i++)
        {
                printf("\n\rAppTask2 \r\n");
                OSTimeDlyHMSM(0,0,0,1);       
        }
        printf("\n\r删除任务2\r\n");
        OSTaskDel(APP_TASK2_PRIO);        //删除任务2
}
如下图是串口打印的数据:

【1】金龙107_ ucos ii_任务创建与删除.rar (400.74 KB)




评分
参与人数 1威望 +6 收起 理由
WYT440 + 6 很给力!
沙发
mmuuss586| | 2015-5-18 18:43 | 只看该作者

支持下;

使用特权

评论回复
板凳
szopenmcu|  楼主 | 2015-5-19 10:08 | 只看该作者
实验二、任务调度

本节我们主要介绍的是uC/OS-II任务调度。
1uC/OS-II任务调度原理
在uC/OS-II创建的任务中,每个任务都是一个无限循环的函数,实现任务的切换需要操作系统完成。用户任务创建后,调用OSStart()开始进行任务调度。任务调度始终会运行就绪列表中优先级最高的任务。
如下图是任务状态的转换表图,正在运行的任务通过调用OS..Pend和延时函数进入等待状态,同时将其从就绪列表中删除,并加入到等待列表中,此时在就绪列表中查找优先级最高的任务设置为当前任务并运行。正在运行的任务通过调用OS..PostOS..Resume函数使得正在等待挂起的任务进入就绪态,若有任务处于延时等待中,在心跳时钟是延时值减一,当减为零时延时等待任务充等待状态切换到就绪态,同时将其从等待列表中删除,并加入到就绪列表中。如果此任务优先级高于正在运行的任务优先级,则进行任务切换。
下面是系统定时器中断源代码
void SysTick_Handler(void)
{
        OS_CPU_SR  cpu_sr;
    OS_ENTER_CRITICAL();  //保存全局中断标志,关总中断
    OSIntNesting++;
    OS_EXIT_CRITICAL();          //恢复全局中断标志
    OSTimeTick();          //延时计数值减一,判断计数时间到后进行任务切换
    OSIntExit();                  //os_core.c文件里定义,如果有更高优先级的任务                                                        //就绪了,则执行一次任务切换
}
2、实验分析
本次实验创建两个任务,任务一循环从串口打印“AppTask1”后延时2sLED1闪烁一次,任务二循环从串口打印“AppTask2”后延时1sLED2闪烁一次。其源代码如下:
int  main (void)
{
        SysTick_Configuration();         //系统定时器初始化
        USART_Configuration();          //串口初始化
        LED_Configuration();       
OSInit();              //usos ii初始化
AppTaskCreate();//创建任务
OSStart();      //开始任务调度
}
static  void  AppTaskCreate(void)
{
INT8U  err;
OSTaskCreateExt(AppTask1,(void*)0,(OS_STK )&AppTask1Stk[APP_TASK1_STK_SIZE-1],APP_TASK1_PRIO,APP_TASK1_PRIO,(OS_STK )&AppTask1Stk[0],APP_TASK1_STK_SIZE,(void )0,OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);                //创建任务1
OSTaskNameSet(APP_TASK1_PRIO, "AppTask1", &err);
OSTaskCreateExt(AppTask2,(void*)0,(OS_STK )&AppTask2Stk[APP_TASK2_STK_SIZE-1],APP_TASK2_PRIO,APP_TASK2_PRIO,(OS_STK )&AppTask2Stk[0],APP_TASK2_STK_SIZE,(void*)0,OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);                //创建任务2
OSTaskNameSet(APP_TASK2_PRIO, "AppTask2", &err);
}
//任务1
static  void  AppTask1 (void *p_arg)
{
        while(1)
        {
                printf("\n\rAppTask1\r\n");
                LED1(0);
                OSTimeDlyHMSM(0,0,1,0);
                LED1(1);
                OSTimeDlyHMSM(0,0,1,0);
        }
}
//任务2
static  void  AppTask2 (void *p_arg)
{
        while(1)
        {
                printf("\n\rAppTask2 \r\n");
                LED2(0);
                OSTimeDlyHMSM(0,0,0,500);
                LED2(1);
                OSTimeDlyHMSM(0,0,0,500);
        }                    
}
如下图是串口打印的数据,通过修改OSTimeDlyHMSM()的延时值,其中该延时函数的四个参数分别代表时分秒毫秒,可以看到打印速度的变化及两个字符串打印出来的比例。

使用特权

评论回复
地板
WYT440| | 2015-5-19 13:11 | 只看该作者
感谢楼主,辛苦了!

使用特权

评论回复
5
szopenmcu|  楼主 | 2015-5-19 14:50 | 只看该作者
实验三、消息队列

本节我们主要介绍的是uC/OS-II的通信方式--消息队列
1、队列介绍
为了使用uC/OS-II的消息队列,需要将OS_CFG.H中的OS_Q_EN及其下面的函数使能宏置位,并设置OS_MAX_QS为应用程序中最多可以设置的消息队列个数。消息队列使用的是先入先出的方式进行异步通信,即对先来的事件先处理,uC/OS-II也可以使用OSQPostFront将消息加入到队列头来实现后入先出。下图是任务、中断服务子程序和消息队列之间的关系。
2、队列操作
uC/OS-II提供了一系列函数对队列进行创建、接收和发送等。
1)创建队列OSQCreate()
OS_EVENT *OSQCreate(void **start, INT16U size)
start                                 二级指针,类型为void  数组的起始地址
size                                        队列长度
返回值                                NULL表示没有空闲的事件控制块
OS_EVENT类型的指针指向生成的队列
2)将数据发送到队列尾OSQPost()与头OSQPostFront()
INT8U OSQPost (OS_EVENT *pevent, void *msg)
INT8U OSQPostFront (OS_EVENT *pevent, void*msg)
pevent                                创建队列时返回的指针
msg                                        发送数据的指针。
返回值                          有三个可能的返回值:
1.OS_NO_ERR                                 数据被成功发送到队列中。
2.OS_ERR_EVENT_TYPE         事件类型错误
3.OS_Q_FULL                                队列满
3)从消息队列中获取一个消息OSQPend()等待和OSQAccept()立即返回
void *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
void *OSQAccept (OS_EVENT *pevent)
pevent                        创建队列时返回的指针
timeout                        阻塞超时时间
err                                错误类型指针
返回值                  有两个可能的返回值:
1.NULL                没有获取到数据
2.数据指针
4)清空消息队列OSQFlush()
INT8U OSQFlush (OS_EVENT *pevent)
pevent                        创建队列时返回的指针
返回值                  有两个可能的返回值:
1.OS_NO_ERR                                清空成功
2.OS_ERR_EVENT_TYPE        事件类型错误
5)查询队列的当前状态OSQQuery()
INT8U OSQQuery (OS_EVENT *pevent, OS_Q_DATA *pdata)
pevent                        创建队列时返回的指针
pdata                        消息队列的信息
返回值                  有两个可能的返回值:
1.OS_NO_ERR                                清空成功
2.OS_ERR_EVENT_TYPE        事件类型错误
3、实验分析
实验创建两个任务,并创建一个长度为10的队列,一个任务用于每500ms向队列发送字符串,另一个任务用于每隔1s等待接收字符串。接收到字符串后将其打印出来,由于发送间隔时间比接收间隔时间短,因此实验到后来会出现队列满的现象。其源代码如下:
OS_EVENT *CommQ;               
void *CommMsg[OS_MAX_QS];        //OS_MAX_QS(在os_cfg.h里定义)个指针的数组
int  main (void)
{
        INT8U   err;
        SysTick_Configuration();         //系统定时器初始化
        USART_Configuration();          //串口初始化
        LED_Configuration();
        OSInit();              //usos ii初始化
        CommQ= OSQCreate(&CommMsg[0], 10); //建立消息队列 长度为10
        OSQFlush(CommQ);
        AppTaskCreate();//创建任务
        OSStart();      //开始任务调度
}
static  void  AppTaskCreate(void)
{
        INT8U  err;
OSTaskCreateExt(AppTask1,(void*)0,(OS_STK )&AppTask1Stk[APP_TASK1_STK_SIZE-1],APP_TASK1_PRIO,APP_TASK1_PRIO,(OS_STK)&AppTask1Stk[0],APP_TASK1_STK_SIZE,(void )0,OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);                        //创建任务1
        OSTaskNameSet(APP_TASK1_PRIO, "AppTask1", &err);
        OSTaskCreateExt(AppTask2,(void*)0,(OS_STK )&AppTask2Stk[APP_TASK2_STK_SIZE-1],APP_TASK2_PRIO,APP_TASK2_PRIO,(OS_STK )&AppTask2Stk[0],APP_TASK2_STK_SIZE,(void*)0,OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);                        //创建任务2
        OSTaskNameSet(APP_TASK2_PRIO, "AppTask2", &err);
}
//任务1
static  void  AppTask1 (void *p_arg)
{
        INT8U err;
        void *msg;
        while(1)
        {
                msg= OSQPend(CommQ, 100, &err);
                if (err == OS_NO_ERR){//读取成功,打印消息               
                        printf("\n\r读取队列成功:%s\r\n",(INT8U *)msg);               
} else{
                        printf("\n\r读取失败\r\n");                //读取失败
                }               
                OSTimeDlyHMSM(0,0,0,500);
                LED1(1);
                OSTimeDlyHMSM(0,0,0,500);
                LED1(0);
        }
}
INT8U *CommRxBuf="bbs.openmcu.com";
//任务2
static  void  AppTask2 (void *p_arg)
{
        INT8U err;
        while(1)
        {
                err= OSQPost(CommQ, (void *)&CommRxBuf[0]);
                if (err == OS_NO_ERR){
                        printf("\n\r消息加入队列中 \r\n");        //将消息放入消息队列                
                } else{
                        printf("\n\r队列已满 \r\n");                        //消息队列已满        
                }
                OSTimeDlyHMSM(0,0,0,500);       
        }                    
}
由于写入消息队列的速度快于读出队列的速度,因此到实验做了一段时间后会出现消息队列满的现象,等待消息被读出后,才能继续往队列里面写数据,通过串口打印的现象如下:

使用特权

评论回复
6
szopenmcu|  楼主 | 2015-5-20 14:54 | 只看该作者
实验四、信号量

本节我们主要介绍的是uC/OS-II的信号量
1、信号量介绍
信号量的本质是一种数据操作锁,它本身不具有数据交换的功能,而是通过控制其他的通信资源(文件,外部设备)来实现进程间通信,它本身只是一种外部资源的标识。信号量在此过程中负责数据操作的互斥、同步等功能。当请求一个使用信号量来表示的资源时,进程需要先读取信号量的值来判断资源是否可用。如果大于0则资源可以请求,等于0则无资源可用,进程会进入睡眠状态直至资源可用。
µC/OS-II中的信号量由两部分组成:一个是信号量的计数值,它是一个16位的无符号整数(065,535之间);另一个是由等待该信号量的任务组成的等待任务表。用户要在 OS_CFG.H中将 OS_SEM_EN 开关量常数置成 1,这样µC/OS-II才能支持信号量。在使用一个信号量之前, 首先要建立该信号量, 也即调用 OSSemCreate()函数,对信号量的初始计数值赋值。该初始值为065,535之间的一个数。如果信号量是用来表示一个或者多个事件的发生, 那么该信号量的初始值应设为0。如果信号量是用于对共享资源的访问,那么该信号量的初始值应设为1(例如,把它当作二值信号量使用)。最后,如果该信号量是用来表示允许任务访问n 个相同的资源,那么该初始值显然应该是n,并把该信号量作为一个可计数的信号量使用。如下图是任务、中断服务子程序和信号量之间的关系。
2、信号量操作
µC/OS-II提供了一系列函数对信号量进行创建、获取和给出等。
1)创建信号量OSSemCreate()
OS_EVENT *OSSemCreate (INT16U cnt)
cnt                                信号量的初始值
返回值                  NULL创建失败  
否则返回事件控制块指针
2)信号量获取OSSemPend( )等待和OSSemAccept()立即返回
void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
INT16U OSSemAccept (OS_EVENT *pevent)
pevent                        创建队列时返回的指针
Timeout                        阻塞超时时间。
err                                错误类型
返回值                  信号量计数值减一
3)发出信号量OSSemPost()
INT8U OSSemPost (OS_EVENT *pevent)
pevent                        创建队列时返回的指针
返回值                        有两个可能的返回值:
1.OS_NO_ERR                                清空成功
2.OS_ERR_EVENT_TYPE        事件类型错误
3.OS_SEM_OVF                        溢出
3)查询一个信号量的当前状态OSSemQuery()
INT8U OSSemQuery (OS_EVENT *pevent,OS_SEM_DATA *pdata)
pevent                        创建队列时返回的指针
pdata                        用于记录信号量信息的数据结构
返回值                        有三个可能的返回值:
1.OS_NO_ERR                                清空成功
2.OS_ERR_EVENT_TYPE        事件类型错误
3.OS_SEM_OVF                        溢出
3、实验分析
实验创建两个任务,任务二每隔500ms发送发送两次信号量,并打印发送状态,任务一则一直等待接收信号,并接下来进行两次无等待接收信号,并打印两次接收的状态。其实验代码如下:
int  main (void)
{
        INT8U   err;
        SysTick_Configuration();         //系统定时器初始化
        USART_Configuration();          //串口初始化
        LED_Configuration();
        OSInit();              //usos ii初始化
        DispSem= OSSemCreate(1); //建立显示设备的信号量
        AppTaskCreate();//创建任务
        OSStart();      //开始任务调度
}
static  void  AppTaskCreate(void)
{
        INT8U  err;
OSTaskCreateExt(AppTask1,(void*)0,(OS_STK )&AppTask1Stk[APP_TASK1_STK_SIZE-1],APP_TASK1_PRIO,APP_TASK1_PRIO,(OS_STK)&AppTask1Stk[0],APP_TASK1_STK_SIZE,(void )0,OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);                        //创建任务1
        OSTaskNameSet(APP_TASK1_PRIO, "AppTask1", &err);
        OSTaskCreateExt(AppTask2,(void*)0,(OS_STK )&AppTask2Stk[APP_TASK2_STK_SIZE-1],APP_TASK2_PRIO,APP_TASK2_PRIO,(OS_STK )&AppTask2Stk[0],APP_TASK2_STK_SIZE,(void*)0,OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);                        //创建任务2
        OSTaskNameSet(APP_TASK2_PRIO, "AppTask2", &err);
}
//任务1
static  void  AppTask1 (void *p_arg)
{
        INT8U err;
        while(1)
        {
                OSSemPend(DispSem, 0, &err);       
//P操作等待信号量置起才继续运行,最大为65535个时钟节拍,0为无限等待
                printf("\n\rOSSemPend成功\r\n");
                err= OSSemAccept(DispSem); //P操作,立即返回,若成功err大于0
                if (err> 0){
                printf("\n\rOSSemAccept成功\r\n");        //P操作成功               
                }else       
                {
                        printf("\n\rOSSemAccept失败\r\n");        //P操作失败       
                }
                err= OSSemAccept(DispSem); //P操作,立即返回,若成功err大于0
                if (err> 0){
                        printf("\n\rOSSemAccept成功\r\n");        //P操作成功               
                }else       
                {
                        printf("\n\rOSSemAccept失败\r\n");        //P操作失败       
                }
               
        }
}
//任务2
static  void  AppTask2 (void *p_arg)
{
        INT8U err;
        while(1)
        {
                err= OSSemPost(DispSem);        //V操作
                err= OSSemPost(DispSem);        //V操作
                if (err == OS_NO_ERR){
                        printf("\n\r信号量置起\r\n");//V操作成功
                }else{
                        printf("\n\r信号量溢出\r\n");//V操作失败
                }
                OSTimeDlyHMSM(0,0,0,500);       
        }                    
}
任务2500ms发送两次V操作(发送信号),操作成功打印“信号量置起”,任务1循环查询一次等待获取信号量,后两次立即返回获取信号量,由于每次循环任务2进行两次V操作,而任务1进行一次等待获取信号量后,又立即获取两次(时间间隔很短),所以第一个立即获取成功,第二个立即获取失败。打印输出“OSSemPend成功”“OSSemAccept成功”和“OSSemAccept失败”,从串口打印如下:

【4】金龙107_ ucos ii_信号量.rar (398.85 KB)




使用特权

评论回复
7
szopenmcu|  楼主 | 2015-5-21 14:51 | 只看该作者
实验五、互斥锁

本节我们主要介绍的是uC/OS-II的互斥锁
1、互斥锁
互斥锁即互斥型信号量,是一种特殊的信号量,他除了具有普通信号量的机制外,还有一些其他的特性。互斥信号量可以在应用程序中解决优先级反转问题。当高优先级的任务需要使用某个共享资源,而该资源已被一个低优先级的任务占用时,就会发生优先级反转。为了解决优先级反转,内核可以将低优先级任务的优先级提升到高于那个高优先级的任务,知道低优先级的任务使用完占用的共享资源。
如下图是任务与互斥锁之间的关系流程图,互斥锁智能提供任务使用。
2、互斥锁操作
µC/OS-II提供了一系列函数对互斥锁进行创建、上锁与解锁等。
1)创建互斥锁OSMutexCreate();
OS_EVENT  *OSMutexCreate (INT8U prio, INT8U *perr)
prio                                优先级
perr                                错误类型
返回值                  NULL创建失败  
否则返回事件控制块指针
2)上锁OSMutexPend( )等待和OSMutexAccept()立即返回
void  OSMutexPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr)
BOOLEAN  OSMutexAccept (OS_EVENT *pevent, INT8U *perr)
pevent                        创建互斥锁时返回的指针
timeout                        阻塞超时时间。
err                                错误类型
返回值                  OS_TRUE上锁成功
OS_FALSE上锁失败
3)解锁OSMutexPost()
INT8U  OSMutexPost (OS_EVENT *pevent)
pevent                        创建队列时返回的指针
返回值                        有六个可能的返回值:
1.OS_ERR_POST_ISR                不能从中断程序中发送
2.OS_ERR_PEVENT_NULL        不存在
3.OS_ERR_EVENT_TYPE        事件类型错误
4.OS_ERR_NOT_MUTEX_OWNER        不是本任务上锁
5.OS_ERR_PIP_LOWER                互斥锁的优先级低于当前任务的优先级
6.OS_ERR_NONE                        解锁成功
4)获取互斥锁当前状态OSMutexQuery()
INT8U OSMutexQuery (OS_EVENT *pevent, OS_MUTEX_DATA *p_mutex_data)
pevent                        创建队列时返回的指针
pdata                        用于记录互斥锁的数据结构
返回值                        有五个可能的返回值:
1.OS_ERR_QUERY_ISR                        不能从中断程序中发送
2.OS_ERR_PEVENT_NULL                不存在
3.OS_ERR_PDATA_NULL                记录数据结构不存在
4.OS_ERR_EVENT_TYPE                事件类型错误
5.OS_ERR_NONE                                获取成功
3、实验分析
实验创建两个任务,两个任务依次进行上锁,上锁后打印出字符串,然后解锁。其实验代码如下:
OS_EVENT *ResourceMutex;
int  main (void)
{
        INT8U   err;
        SysTick_Configuration();         //系统定时器初始化
        USART_Configuration();          //串口初始化
        LED_Configuration();
        OSInit();              //usos ii初始化
        ResourceMutex=OSMutexCreate(9, &err);         //创建互斥锁优先级为9
        AppTaskCreate();//创建任务
        OSStart();      //开始任务调度
}
static  void  AppTaskCreate(void)
{
        INT8U  err;
OSTaskCreateExt(AppTask1,(void*)0,(OS_STK )&AppTask1Stk[APP_TASK1_STK_SIZE-1],APP_TASK1_PRIO,APP_TASK1_PRIO,(OS_STK)&AppTask1Stk[0],APP_TASK1_STK_SIZE,(void )0,OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);                        //创建任务1
        OSTaskNameSet(APP_TASK1_PRIO, "AppTask1", &err);
        OSTaskCreateExt(AppTask2,(void*)0,(OS_STK )&AppTask2Stk[APP_TASK2_STK_SIZE-1],APP_TASK2_PRIO,APP_TASK2_PRIO,(OS_STK )&AppTask2Stk[0],APP_TASK2_STK_SIZE,(void*)0,OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);                        //创建任务2
        OSTaskNameSet(APP_TASK2_PRIO, "AppTask2", &err);
}
//任务1
static  void  AppTask1 (void *p_arg)
{
        INT8U err;
        while(1)
{
                OSMutexPend(ResourceMutex, 0, &err); //获取资源,无限等待
LED1(1);               
printf("\n\r任务1获取资源\r\n");
                OSTimeDlyHMSM(0,0,1,0);
                printf("\n\r任务1释放资源\r\n");
                OSMutexPost(ResourceMutex);
//释放资源时进行任务调度        所以把输出写前面
                 LED1(0);
}
}
//任务2
static  void  AppTask2 (void *p_arg)
{
        INT8U err;
        while(1)
{        
                OSMutexPend(ResourceMutex, 0, &err); // 获取资源,无限等待
                printf("\n\r任务2获取资源 \r\n");
LED2(1);
                OSTimeDlyHMSM(0,0,0,500);        
                printf("\n\r任务2释放资源\r\n");
//释放资源时进行任务调度        所以把输出写前面        
                OSMutexPost(ResourceMutex);
LED2(0);
        }                    
}
程序中每个任务获得互斥锁后打印字符串,并延时1s钟后解锁,这样下个任务才能进行上锁,完成自己的任务。其程序从串口打印如下

【5】金龙107_ ucos ii_互斥锁.rar (399.7 KB)




使用特权

评论回复
8
fanxsd| | 2015-5-21 17:30 | 只看该作者
灰常的好啊! 我是看了N久 任哲的书才入门的。

使用特权

评论回复
9
Thor9| | 2015-5-21 20:42 | 只看该作者

使用特权

评论回复
10
szopenmcu|  楼主 | 2015-5-22 11:05 | 只看该作者
fanxsd 发表于 2015-5-21 17:30
灰常的好啊! 我是看了N久 任哲的书才入门的。

实验六、邮箱

【6】金龙107_ucos ii_邮箱.rar (398.67 KB)



本节我们主要介绍的是uC/OS-II的邮箱
1、邮箱介绍
µC/OS-II中的邮箱也称为消息邮箱, 是用一个指针型变量, 通过内核服务, 一个任务或一个中断服务程序可以把一则消息(即一个指针)放到邮箱里去。同样,一个或多个任务可以通过内核服务接收这则消息。发送消息的任务和接收消息的任务约定,该指针指向的内容就是那则消息。消息邮箱与消息队列类似,消息邮箱相当于消息队列的一个成员,消息队列实际上是邮箱阵列。如下图是任务、中断服务子程序和邮箱之间的关系。
2、邮箱操作
µC/OS-II提供了一系列函数对邮箱进行创建、获取和给出等。
1)创建邮箱OSMboxCreate()
OS_EVENT *OSMboxCreate (void *msg)
msg                                邮箱的初始指针为0则无初值
返回值                  NULL创建失败  
否则返回事件控制块指针
2)信号量获取OSSemPend( )等待和OSMboxAccept()立即返回
void *OSMboxPend (OS_EVENT *pevent,INT16Utimeout, INT8U*err)
void *OSMboxAccept (OS_EVENT *pevent)
pevent                        创建邮箱时返回的指针
Timeout                        阻塞超时时间。
err                                错误类型
返回值                  NULL获取失败
邮件指针
3)发出邮箱OSMboxPost()
INT8U OSMboxPost (OS_EVENT *pevent,void *msg)
pevent                        创建邮箱时返回的指针
msg                                要发送的邮箱指针
返回值                        有两个可能的返回值:
1.OS_NO_ERR                                清空成功
2.OS_ERR_EVENT_TYPE        事件类型错误
3.OS_MBOX_FULL                        邮箱满
3)查询一个信号量的当前状态OSMboxQuery()
INT8U OSMboxQuery (OS_EVENT*pevent, OS_MBOX_DATA *pdata)
pevent                        创建邮箱时返回的指针
pdata                        用于记录邮箱信息的数据结构
返回值                        有两个可能的返回值:
1.OS_NO_ERR                                清空成功
2.OS_ERR_EVENT_TYPE        事件类型错误
3、实验分析
实验创建两个任务,任务二每隔500ms发送发送一次邮箱,并打印发送状态,任务一则一直阻塞等待接收邮箱,并打印接受到的邮箱。其实验代码如下:
int  main (void)
{
        INT8U   err;
        SysTick_Configuration();         //系统定时器初始化
        USART_Configuration();          //串口初始化
        LED_Configuration();
        OSInit();              //usos ii初始化
CommMbox = OSMboxCreate((void *)0); //建立消息邮箱
AppTaskCreate();//创建任务
        OSStart();      //开始任务调度
}
static  void  AppTaskCreate(void)
{
        INT8U  err;
OSTaskCreateExt(AppTask1,(void*)0,(OS_STK )&AppTask1Stk[APP_TASK1_STK_SIZE-1],APP_TASK1_PRIO,APP_TASK1_PRIO,(OS_STK)&AppTask1Stk[0],APP_TASK1_STK_SIZE,(void )0,OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);                        //创建任务1
        OSTaskNameSet(APP_TASK1_PRIO, "AppTask1", &err);
        OSTaskCreateExt(AppTask2,(void*)0,(OS_STK )&AppTask2Stk[APP_TASK2_STK_SIZE-1],APP_TASK2_PRIO,APP_TASK2_PRIO,(OS_STK )&AppTask2Stk[0],APP_TASK2_STK_SIZE,(void*)0,OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);                        //创建任务2
        OSTaskNameSet(APP_TASK2_PRIO, "AppTask2", &err);
}
//邮箱接收任务
static  void  AppTask1 (void *p_arg)
{
        INT8U err;
void *msg;
        while(1)
{
msg=OSMboxPend(CommMbox,600,&err);//等待接收邮箱最大时间600ms
        if (err == OS_NO_ERR){               
                printf("接收到消息%s\r\n",(INT8U *)msg);//消息正确的接受        
        } else{
                printf("没有接收到消息\r\n");//在指定时间内没有接受到消息
        }
}
}
//邮箱发送任务
static  void  AppTask2 (void *p_arg)
{
INT8U CommRxBuf[100]="bbs.openmcu.com";
INT8U err;
while(1)
{
        err= OSMboxPost(CommMbox, (void *)CommRxBuf);
        if (err == OS_NO_ERR){               
                printf("发送成功\r\n");//发送成功               
        } else{
                printf("发送失败\r\n");//发送失败       
        }
        OSTimeDlyHMSM(0,0,0,500);       
}                    
}
本程序为ucos的另一种通信方式邮箱,工程创建两个任务,一个每隔500ms发送一个邮箱,一个等待接收邮箱最大等待时间600ms,任务二发送邮箱并打印“发送成功”,任务一接收到邮箱后打印“接收到消息bbs.openmcu.com”。

使用特权

评论回复
11
szopenmcu|  楼主 | 2015-5-23 14:28 | 只看该作者
实验七、事件标志组

本节我们主要介绍的是uC/OS-II的事件标志组
1、事件标志组介绍
µC/OS-II当某任务要与多个事件同步时,要使用事件标志。若任务需要与任何事件之一发生同步,可称为独立型同步(即逻辑或关系)。任务也可以与若干事件都发生了同步,称之为关联型(逻辑与关系)。独立型及关联型同步如图所示。
2、事件标志组操作
µC/OS-II提供了一系列函数对邮箱进行创建、获取和给出等。
1)创建事件标志组OSFlagCreate ()
OS_FLAG_GRP  *OSFlagCreate (OS_FLAGS flags, INT8U *perr)
flags                        事件标志组初始化值
Perr                                错误标志
返回值                  标志组指针  
2)等待标志置位获取OSFlagPend ()
OS_FLAGS  OSFlagPend (OS_FLAG_GRP *pgrp, OS_FLAGS flags, INT8U wait_type, INT16U timeout, INT8U *perr)
pgrp                        标志组指针
flags                        等待标志位
wait_type                设置操作类型‘与’‘或’
Timeout                        等待事件
Perr                                错误类型
3)发出邮箱OSFlagPost()
OS_FLAGS  OSFlagPost (OS_FLAG_GRP *pgrp, OS_FLAGS flags, INT8U opt, INT8U *perr)
pgrp                        标志组指针
flags                        等待标志位
opt                                置位还是清零
Perr                                错误类型
3、实验分析
实验创建三个任务,任务一等待事件标志组bit0bit1置位,任务二置位标志组bit1位,任务三置位标志组bit0位。其实验代码如下:
int  main (void)
{
SysTick_Configuration();         //系统定时器初始化
USART_Configuration();          //串口初始化
LED_Configuration();
OSInit();              //usos ii初始化
        Sem_F=OSFlagCreate(0,&err);  
OSFlagPost(Sem_F,(OS_FLAGS)0,OS_FLAG_CLR,&err);
AppTaskCreate();//创建任务
        OSStart();      //开始任务调度
}
static  void  AppTaskCreate(void)
{
        INT8U  err;
OSTaskCreateExt(AppTask1,(void*)0,(OS_STK )&AppTask1Stk[APP_TASK1_STK_SIZE-1],APP_TASK1_PRIO,APP_TASK1_PRIO,(OS_STK)&AppTask1Stk[0],APP_TASK1_STK_SIZE,(void )0,OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);                        //创建任务1
        OSTaskNameSet(APP_TASK1_PRIO, "AppTask1", &err);
        OSTaskCreateExt(AppTask2,(void*)0,(OS_STK )&AppTask2Stk[APP_TASK2_STK_SIZE-1],APP_TASK2_PRIO,APP_TASK2_PRIO,(OS_STK )&AppTask2Stk[0],APP_TASK2_STK_SIZE,(void*)0,OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);                        //创建任务2
        OSTaskNameSet(APP_TASK2_PRIO, "AppTask2", &err);
        OSTaskCreateExt(AppTask3,(void*)0,(OS_STK )&AppTask3Stk[APP_TASK3_STK_SIZE-1],APP_TASK3_PRIO,APP_TASK3_PRIO,(OS_STK )&AppTask3Stk[0],APP_TASK3_STK_SIZE,(void*)0,OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);                //创建任务3
        OSTaskNameSet(APP_TASK2_PRIO, "AppTask3", &err);
}
//任务1
static  void  AppTask1 (void *p_arg)
{
        while(1)
{
OSFlagPend(Sem_F,(OS_FLAGS)3,OS_FLAG_WAIT_SET_ALL+OS_FLAG_CONSUME, 0,&err);  //等待bit0 bit1置位,全部置位后清除
                printf("\n\r等待的标志位置位,清除\r\n");
                LED1(0);
                OSTimeDlyHMSM(0,0,1,0);
                LED1(1);
                OSTimeDlyHMSM(0,0,1,0); }
}
//任务2
static  void  AppTask2 (void *p_arg)
{
while(1)
{
        OSFlagPost(Sem_F,(OS_FLAGS)2,OS_FLAG_SET,&err);  //置位bit1
        printf("\n\r标志位1位置高\r\n");
        OSTimeDlyHMSM(0,0,1,500);       
}                    
}
//任务3
static  void  AppTask3 (void *p_arg)
{
        while(1)
        {
                OSFlagPost(Sem_F,(OS_FLAGS)1,OS_FLAG_SET,&err);  //置位bit0
                printf("\n\r标志位0位置高 \r\n");
                OSTimeDlyHMSM(0,0,1,500);       
        }                    
}

本程序为ucos的另一种通信方式邮箱,程序创建三个任务,任务一等待事件标志组bit0bit1置位,任务二置位标志组bit1位,任务三置位标志组bit0位。任务一等待标志位置位后清除标志位并打印信息。其串口打印如下

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:专业生产销售STM32开发板,仿真器,http://openmcu.taobao.com/

71

主题

283

帖子

11

粉丝