STM32上使用UCOSII--软件定时器和任务延时

有关UCOS任务的介绍:
STM32上使用UCOSII–任务
有关UCOS信号量和邮箱的介绍:
STM32上使用UCOSII–信号量和邮箱
有关消息队列和信号量集的介绍:
STM32上使用UCOSII–消息队列和信号量集

一、软件定时器

UCOSII 从 V2.83 版本以后,加入了软件定时器,这使得UCOSII的功能更加完善,在其上的应用程序开发与移植也更加方便。在实时操作系统中一个好的软件定时器实现要求有较高的精度、较小的处理器开销,且占用较少的存储器资源。

UCOSII 通过 OSTimTick函数对时钟节拍进行加1操作,同时遍历任务控制块,以判断任务延时是否到时。软件定时器同样由OSTimTick提供时钟,但是软件定时器的时钟还受OS_TMR_CFG_TICKS_PER_SEC 设置的控制,也就是在UCOSII的时钟节拍上面再做了一次“分频”,软件定时器的最快时钟节拍就等于 UCOSII 的系统时钟节拍。这也决定了软件定时器的精度。

软件定时器定义了一个单独的计数器OSTmrTime,用于软件定时器的计时,UCOSII并不在OSTimTick 中进行软件定时器的到时判断与处理,而是创建了一个高于应用程序中所有其他任务优先级的定时器管理任务 OSTmr_Task,在这个任务中进行定时器的到时判断和处理。时钟节拍函数通过信号量给这个高优先级任务发信号。这种方法缩短了中断服务程序的执行时间,但也使得定时器到时处理函数的响应受到中断退出时恢复现场和任务切换的影响。软件定时器功能实现代码存放在 tmr.c文件中,移植时需只需在os_cfg.h文件中使能定时器和设定定时器的相关参数。

UCOSII 软件定时器实现了 3 类链表的维护:

OS_EXT OS_TMR OSTmrTbl[OS_TMR_CFG_MAX]; //定时器控制块数组
OS_EXT OS_TMR *OSTmrFreeList; //空闲定时器控制块链表指针
OS_EXT OS_TMR_WHEEL OSTmrWheelTbl[OS_TMR_CFG_WHEEL_SIZE];//定时器轮

OS_TMR 为定时器控制块,定时器控制块是软件定时器管理的基本单元,包含软件定时器的名称、定时时间、在链表中的位置、使用状态、使用方式,以及到时回调函数及其参数等基本信息

OSTmrTbl[OS_TMR_CFG_MAX];:以数组的形式静态分配定时器控制块所需的RAM空间,并存储所有已建立的定时器控制块, OS_TMR_CFG_MAX 为最大软件定时器的个数。

OSTmrFreeLiSt:为空闲定时器控制块链表头指针。空闲态的定时器控制块(OS_TMR)中,OSTmrnext 和 OSTmrPrev 两个指针分别指向空闲控制块的前一个和后一个,组织了空闲控制块双向链表。建立定时器时,从这个链表中搜索空闲定时器控制块。

OSTmrWheelTbl[OS_TMR_CFG_WHEEL_SIZE]:该数组的每个元素都是已开启定时器的一个分组,元素中记录了指向该分组中第一个定时器控制块的指针,以及定时器控制块的个数。运行态的定时器控制块(OS_TMR)中,OSTmrnext和OSTmrPrev两个指针同样也组织了所在分组中定时器控制块的双向链表

软件定时器管理任务的流程如图:

这里写图片描述

当运行完软件定时器的到时处理函数之后,需要进行该定时器控制块在链表中的移除和再
插入操作。 插入前需要重新计算定时器下次到时时所处的分组。计算公式如下:

定时器下次到时的 OSTmrTime 值(OSTmrMatch)=定时器定时值+当前 OSTmrTime 值

新分组=定时器下次到时的 OSTmrTime 值(OSTmrMatch)%OS_TMR_CFG_WHEEL_SIZE

定时器相关函数

1. 创建软件定时器函数

OS_TMR *OSTmrCreate (INT32U dly, INT32U period, INT8U opt,OS_TMR_CALLBACK callback,void *callback_arg, INT8U *pname, INT8U *perr);

dly,用于初始化定时时间,对单次定时(ONE-SHOT模式)的软件定时器来说,这就是该定时器的定时时间,而对于周期定时(PERIODIC模式)的软件定时器来说,这是该定时器第一次定时的时间,从第二次开始定时时间变为 period

period,在周期定时( PERIODIC 模式),该值为软件定时器的周期溢出时间。

opt,用于设置软件定时器工作模式。可以设置的值为: OS_TMR_OPT_ONE_SHOT
或 OS_TMR_OPT_PERIODIC,如果设置为前者,说明是一个单次定时器;设置为后者则
表示是周期定时器

callback,为软件定时器的回调函数,当软件定时器的定时时间到达时,会调用该函数

callback_arg,回调函数的参数

pname,为软件定时器的名字。

perr,为错误信息

软件定时器的回调函数有固定的格式,我们必须按照这个格式编写,软件定时器的回调函数格式为

void (*OS_TMR_CALLBACK)(void *ptmr, void *parg);

函数名自己设置,而 ptmr这个参数,软件定时器用来传递当前定时器的控制块指针,所以我们一般设置其类型为OS_TMR*类型,第二个参数(parg)为回调函数的参数,这个就可以根据自己需要设置了,你也可以不用,但是必须有这个参数

2. 开启软件定时器函数

BOOLEAN OSTmrStart (OS_TMR *ptmr, INT8U *perr);

ptmr 为要开启的软件定时器指针

perr 为错误信息

3. 停止软件定时器函数

BOOLEAN OSTmrStop (OS_TMR *ptmr,INT8U opt,void *callback_arg,INT8U *perr);

ptmr 为要停止的软件定时器指针

opt 为停止选项,可以设置的值及其对应的意义为:

OS_TMR_OPT_NONE,直接停止,不做任何其他处理
OS_TMR_OPT_CALLBACK,停止,用初始化的参数执行一次回调函数
OS_TMR_OPT_CALLBACK_ARG,停止,用新的参数执行一次回调函数

callback_arg,新的回调函数参数

perr,错误信息

二、 任务延时

µC/OS-Ⅱ提供了这样一个系统服务:申请该服务的任务可以延时一段时间,这段时间的长短是用时钟节拍的数目来确定的。实现这个系统服务的函数叫做OSTimeDly()。调用该函数会使µC/OS-Ⅱ进行一次任务调度,并且执行下一个优先级最高的就绪态任务。任务调用OSTimeDly()后,一旦规定的时间期满或者有其它的任务通过调用OSTimeDlyResume()取消了延时,它就会马上进入就绪状态。注意,只有当该任务在所有就绪任务中具有最高的优先级时,它才会立即运行。

任务延时函数

OSTimeDly

将一个任务延时若干个时钟,无函数返回值。延时时间的长度可从0到65535个时钟节拍,延时时间0表示不进行延时,函数将立即返回调用者,延时的具体时间依赖于系统每秒种有多少时钟节拍

void OSTimeDly(INT16U ticks)

ticks: 要延时的时钟节拍数

OSTimeDlyHMSM

任务延时函数OSTimeDly用于将任务阻塞一段时间,这个时间是以时间片为单位的。如果想以小时、分、秒、毫秒为单位进行任务延时,需要调用以分秒作为单位的任务延时函数OSTimeDlyHMSM

INT8U OSTimeDlyHMSM(INT8U hours, INT8U minutes, INT8U seconds, INT16U milli);

hours 小时数 ; minutes 分钟数 ; second 秒数 ; milli 毫秒数

三、 软件定时器和任务延时的区别

调用OSTimeDly或者OSTimeDlyHMSM,意味着该任务CPU使用权会被没收,然而开启一个定时器之后,该任务还可以使用CPU

举例子:如下情景,可以使用软件定时器作超时处理,设备A管理设备B、C、E,设备A向设备BCE设备发送某一消息搜索,如果在T时间内,设备BCE没有回应,设备A将重起并初始化BCE;那么可以在一个任务中,依次向BCE发送消息,并且启动软件动定时器TMRa,TMRb,TMRc,定时器时间到时调用各自的重起并初始化函数;另一方面,如果接收到BCE的消息则停止定时器TMRa,TMRb,TMRc

然而如果用OSTimeDly或者OSTimeDlyHMSM处理上面的场景,可能要多开几个任务管理BCE并增加信号量通知OSTimeDly或者OSTimeDlyHMSM之后,到底是“重起并初始化BCE”还是什么都不做

软件定时器和延时都是基于“系统的节拍”来计时/定时的,虽然软件定时器是在一个高优先级的任务中管理,这个任务也是由“系统节拍中断“中向其发送信号量,因此还是基于“系统的节拍”

没必要去对它们的区别做出一个定义,关键还是去理解它们的应用场合,它们都能解决什么问题

四、 stm32上使用UCOSII的软件定时器和任务延时

led0通过软件定时器,每500ms执行一次回掉函数,来实现闪烁
led1通过任务延时,每500ms执行一次led1任务,来实现闪烁

/////////////////////////UCOSII任务设置///////////////////////////////////
//START 任务
//设置任务优先级
#define START_TASK_PRIO                 10 //开始任务的优先级设置为最低
//设置任务堆栈大小
#define START_STK_SIZE                  64
//任务堆栈  
OS_STK START_TASK_STK[START_STK_SIZE];
//任务函数
void start_task(void *pdata);   


//定时器设置任务
//设置任务优先级
#define TIMER_TASK_PRIO                     5
//设置任务堆栈大小
#define TIMER_STK_SIZE                      64
//任务堆栈
OS_STK TIMER_TASK_STK[TIMER_STK_SIZE];
//任务函数
void timer_task(void *pdata);


//LED1任务
//设置任务优先级
#define LED1_TASK_PRIO                      4
//设置任务堆栈大小
#define LED1_STK_SIZE             64
//任务堆栈
OS_STK LED1_TASK_STK[LED1_STK_SIZE];
//任务函数
void led1_task(void *pdata);

///////////////////////////////////////////////////////////////////////////////////////////////
OS_TMR   * tmr1;            //软件定时器1

int main(void)
{   
    delay_init();            //延时函数初始化  
    NVIC_Configuration();    
    LED_Init();         //初始化与LED连接的硬件接口
    OSInit();   
    OSTaskCreate(start_task,(void *)0,(OS_STK *)&START_TASK_STK[START_STK_SIZE-1],START_TASK_PRIO);//创建起始任务
    OSStart();  
 }

//开始任务
void start_task(void *pdata)
{
    u8 err;
  OS_CPU_SR cpu_sr=0;
    pdata = pdata; 

    OS_ENTER_CRITICAL();            //进入临界区(无法被中断打断)    
    OSTaskCreate(timer_task,(void *)0,(OS_STK*)&TIMER_TASK_STK[TIMER_STK_SIZE-1],TIMER_TASK_PRIO);
    OSTaskCreate(led1_task,(void *)0,(OS_STK*)&LED1_TASK_STK[LED1_STK_SIZE-1],LED1_TASK_PRIO);
    OSTaskSuspend(START_TASK_PRIO); //挂起起始任务.
    OS_EXIT_CRITICAL();             //退出临界区(可以被中断打断)
}

//软件定时器1的回调函数
//每500ms执行一次,用于LED0偏转
void tmr1_callback(OS_TMR *ptmr,void *p_arg)
{
    LED0=!LED0;
}
//定时器设置任务
void timer_task(void *pdata)
{
    u8 err;
    tmr1=OSTmrCreate(0,50,OS_TMR_OPT_PERIODIC,(OS_TMR_CALLBACK)tmr1_callback,0,"tmr1",&err);//500ms执行一次
    OSTmrStart(tmr1,&err);//启动软件定时器1
    while(1)
    {
        delay_ms(500);
    }
}
void led1_task(void *pdata)
{
    while(1)
    {
        //OSTimeDly(100);//500ms执行一次
        OSTimeDlyHMSM(0,0,0,500);//500ms执行一次
        LED1=!LED1;

    }
}
  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: STM32 uCOS-II 多任务实验是一种基于STM32微控制器和uCOS-II操作系统的多任务应用程序实验。该实验旨在通过使用uCOS-II操作系统,实现多个任务同时运行,提高系统的效率和可靠性。 在该实验中,我们可以使用STM32开发板和uCOS-II操作系统,创建多个任务并分配不同的优先级。每个任务可以执行不同的操作,例如读取传感器数据、控制外设、处理数据等。通过使用uCOS-II操作系统的任务调度机制,可以确保每个任务按照其优先级顺序执行,从而实现多任务并发执行的效果。 在实验过程中,我们需要学习uCOS-II操作系统的基本概念和使用方法,包括任务创建、任务调度、信号量、消息队列等。同时,还需要了解STM32微控制器的硬件资源和编程方法,以便实现任务的具体功能。 总之,STM32 uCOS-II 多任务实验是一种非常有意义的实验,可以帮助我们深入了解嵌入式系统的多任务编程和操作系统原理,提高我们的实际应用能力。 ### 回答2: stm32是一款基于arm cortex-m内核的微控制器,其具有高性能和低功耗的优点,可广泛应用于嵌入式系统、智能家居、机器人等领域。同时,ucos-ii是一款实时操作系统,能够提供多任务管理、资源管理、时间管理等功能,可帮助开发人员快速构建嵌入式系统。 stm32 ucos-ii多任务实验是指在stm32平台上实现ucos-ii操作系统的多任务管理功能,以实现任务之间的并发执行。该实验通常包括以下几个步骤: 1.准备工作:在开发板上搭建环境,包括stm32开发环境、ucos-ii环境以及相关工具的配置。 2.任务定义:定义多个任务,每个任务都是一个独立的程序模块,应包括任务的初始化、任务功能、任务清理等步骤。 3.任务调度:ucos-ii操作系统会根据任务的优先级、状态等因素进行任务调度,确保任务可以及时得到执行。 4.任务通信:在多任务实验中,由于各个任务之间具有相互制约关系,因此需要进行任务通信,以确保任务能够协同工作。 5.调试测试:在实现多任务后,需要进行调试测试,确保各个任务能够正常运行,系统具有稳定性和健壮性。 综上所述,stm32 ucos-ii多任务实验可以帮助开发人员深入了解stm32的基本功能和ucos-ii实时操作系统的特点,提高系统的并发处理能力,为嵌入式系统的开发和应用提供有力支持。 ### 回答3: STM32 uCOS-II多任务实验是一种在STM32芯片上使用uC/OS-II操作系统进行多任务开发的实验。该实验旨在帮助学生和工程师熟悉uC/OS-II操作系统,学习多任务的开发和调试技术。 在这个实验中,我们需要使用一些基本的硬件和软件,如STM32开发板、uC/OS-II操作系统、Keil或者IAR嵌入式开发工具、以及一些基本的电子元器件。我们需要编写一些任务代码,在uC/OS-II操作系统上进行多任务的协作开发。我们需要学习如何在uC/OS-II操作系统上创建任务、删除任务、挂起任务、恢复任务、设置任务优先级等等。 在进行STM32 uCOS-II多任务实验时,我们需要注意一些事项。首先,我们需要根据实际需要分析任务的资源需求和优先级,为每个任务分配适当的资源和优先级。其次,我们需要了解uC/OS-II操作系统的机制和原理,例如任务调度、消息传递、事件通知等等,以便正确使用和调试操作系统的各种功能。 总之,STM32 uCOS-II多任务实验是一个非常有价值和有意义的实验,它能够帮助我们提高多任务开发和调试的能力。通过这个实验,我们能够掌握uC/OS-II操作系统的使用方法和技能,提高我们的嵌入式开发能力和技术水平。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值