查看: 2822|回复: 6

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

[复制链接]

该用户从未签到

发表于 2015-5-18 14:01:14 | 显示全部楼层 |阅读模式
分享到:
实验一、任务创建与删除
本节我们主要介绍的是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.png


【1】金龙107_ ucos ii_任务创建与删除.rar (400.74 KB, 下载次数: 11)
回复

使用道具 举报

该用户从未签到

 楼主| 发表于 2015-5-19 10:15:54 | 显示全部楼层
实验二、任务调度
本节我们主要介绍的是uC/OS-II任务调度。
1uC/OS-II任务调度原理
在uC/OS-II创建的任务中,每个任务都是一个无限循环的函数,实现任务的切换需要操作系统完成。用户任务创建后,调用OSStart()开始进行任务调度。任务调度始终会运行就绪列表中优先级最高的任务。
如下图是任务状态的转换表图,正在运行的任务通过调用OS..Pend和延时函数进入等待状态,同时将其从就绪列表中删除,并加入到等待列表中,此时在就绪列表中查找优先级最高的任务设置为当前任务并运行。正在运行的任务通过调用OS..PostOS..Resume函数使得正在等待挂起的任务进入就绪态,若有任务处于延时等待中,在心跳时钟是延时值减一,当减为零时延时等待任务充等待状态切换到就绪态,同时将其从等待列表中删除,并加入到就绪列表中。如果此任务优先级高于正在运行的任务优先级,则进行任务切换。
图片2.png
下面是系统定时器中断源代码
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()的延时值,其中该延时函数的四个参数分别代表时分秒毫秒,可以看到打印速度的变化及两个字符串打印出来的比例。
图片1.png


【2】金龙107_ ucos ii_任务调度.rar (399.54 KB, 下载次数: 2)
回复 支持 反对

使用道具 举报

该用户从未签到

 楼主| 发表于 2015-5-19 14:51:18 | 显示全部楼层
实验三、消息队列
本节我们主要介绍的是uC/OS-II的通信方式--消息队列
1、队列介绍
为了使用uC/OS-II的消息队列,需要将OS_CFG.H中的OS_Q_EN及其下面的函数使能宏置位,并设置OS_MAX_QS为应用程序中最多可以设置的消息队列个数。消息队列使用的是先入先出的方式进行异步通信,即对先来的事件先处理,uC/OS-II也可以使用OSQPostFront将消息加入到队列头来实现后入先出。下图是任务、中断服务子程序和消息队列之间的关系。
图片4.png
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);       
        }                    
}
由于写入消息队列的速度快于读出队列的速度,因此到实验做了一段时间后会出现消息队列满的现象,等待消息被读出后,才能继续往队列里面写数据,通过串口打印的现象如下:
图片3.png

回复 支持 反对

使用道具 举报

该用户从未签到

 楼主| 发表于 2015-5-20 14:48:42 | 显示全部楼层
实验四、信号量
本节我们主要介绍的是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.png
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失败”,从串口打印如下:
图片1.png


【4】金龙107_ ucos ii_信号量.rar (398.85 KB, 下载次数: 3)
回复 支持 反对

使用道具 举报

该用户从未签到

 楼主| 发表于 2015-5-21 14:49:34 | 显示全部楼层
实验五、互斥锁
本节我们主要介绍的是uC/OS-II的互斥锁
1、互斥锁
互斥锁即互斥型信号量,是一种特殊的信号量,他除了具有普通信号量的机制外,还有一些其他的特性。互斥信号量可以在应用程序中解决优先级反转问题。当高优先级的任务需要使用某个共享资源,而该资源已被一个低优先级的任务占用时,就会发生优先级反转。为了解决优先级反转,内核可以将低优先级任务的优先级提升到高于那个高优先级的任务,知道低优先级的任务使用完占用的共享资源。
如下图是任务与互斥锁之间的关系流程图,互斥锁智能提供任务使用。
图片2.png
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钟后解锁,这样下个任务才能进行上锁,完成自己的任务。其程序从串口打印如下
图片1.png


【5】金龙107_ ucos ii_互斥锁.rar (399.7 KB, 下载次数: 3)
回复 支持 反对

使用道具 举报

该用户从未签到

 楼主| 发表于 2015-5-22 11:04:12 | 显示全部楼层
实验六、邮箱
【6】金龙107_ucos ii_邮箱.rar (398.67 KB, 下载次数: 2)
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2015-5-23 14:27:22 | 显示全部楼层
实验七、事件标志组
本节我们主要介绍的是uC/OS-II的事件标志组
1、事件标志组介绍
µC/OS-II当某任务要与多个事件同步时,要使用事件标志。若任务需要与任何事件之一发生同步,可称为独立型同步(即逻辑或关系)。任务也可以与若干事件都发生了同步,称之为关联型(逻辑与关系)。独立型及关联型同步如图所示。
图片2.png
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位。任务一等待标志位置位后清除标志位并打印信息。其串口打印如下
图片1.png
【7】金龙107_ ucos ii_事件标志组.rar (400.96 KB, 下载次数: 2)
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /4 下一条



手机版|小黑屋|与非网

GMT+8, 2024-11-25 11:31 , Processed in 0.196843 second(s), 28 queries , MemCache On.

ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

苏公网安备 32059002001037号

Powered by Discuz! X3.4

Copyright © 2001-2024, Tencent Cloud.