请问各位,ucos ii中的软件定时器和延时有啥区别?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了请问各位,ucos ii中的软件定时器和延时有啥区别?相关的知识,希望对你有一定的参考价值。

比如说用OSTimeDlyHMSM我可以实现任务每100ms执行一次,那么用软件定时器有什么用?就是os_tmr.c中的函数有什么用?我没发现OSTimeDly或者OSTimeDlyHMSM调用os_tmr.c内的相关函数啊,那么这里面的函数是用来干嘛的?
OSTimeDly和OSTimeDlyHMSM是利用系统定时器来实现的,这跟os_tmr.c有什么关系?

1、你调用OSTimeDly或者OSTimeDlyHMSM,意味着该任务CPU使用权会被没收,然而你开启一个定时器之后,该任务还可以使用CPU。
2、举例子:如下情景,可以使用软件定时器作超时处理,设备A管理设备B、C、E,设备A向设备BCE设备发送某一消息,如果在T时间内,设备BCE没有回应,设备A将重起并初始化BCE;那么可以在一个任务中,依次向BCE发送消息,并且启动软件动定时器TMRa,TMRb,TMRc,定时器时间到时调用各自的重起并初始化函数;另一方面,如果接收到BCE的消息则停止定时器TMRa,TMRb,TMRc。
3、然而如果用OSTimeDly或者OSTimeDlyHMSM处理上面的场景,可能要多开几个任务管理BCE并增加信号量通知OSTimeDly或者OSTimeDlyHMSM之后,到底是“重起并初始化BCE”还是什么都不做。
4、软件定时器和延时都是基于“系统的节拍”来计时/定时的,虽然软件定时器是在一个高优先级的任务中管理,这个任务也是由“系统节拍中断“中向其发送信号量,因此还是基于“系统的节拍”。
5、没必要去对它们的区别做出一个定义,关键还是去理解它们的应用场合,它们都能解决什么问题。
参考技术A OSTimeDly和OSTimeDlyHMSM是利用系统的节拍来定时的,这个其实是利用了ARM自身的一个系统定时器来完成的,像STM32的话就是用它自己的一个24位系统定时器来作为ucos系统的节拍,而软件的定时器也就是ARM的定时器,其实就是它自己的16位或者是其他位的定时器,像STM32就有好多个16位的定时器,这个就是你说的软件定时器,它还有自己的一个24位的系统定时器,平时是不去接触的,正点原子在STM32的这个24位定时器这里讲解的挺好的,有空你可以去看看他的一些资料追问

不是的,我看了源码了,这个os_tmr.c文件下的定时器也是利用时钟节拍的,而不是利用了STM32自带的其他的定时器,只不过它的频率可以与时钟节拍不一样,可以自己设定,由OS_TICKS_PER_SEC / OS_TMR_CFG_TICKS_PER_SEC的商决定,我就不明白,这样到底有什么意思呢,两个相同功能的东西

ucos-ii在ti dsp 28377芯片上的运行过程和移植过程

 

 

1、移植过程

在将ucos移植到28377d平台上时主要遇见了下面几个问题,

  1) 文件怎么组织,是通过修改micrim上提供的28335一直代码修改而成的,下载地址为:https://www.micrium.com/。

  2)移植完成后发现创建任务完成后,任务无法跳转,移植在主函数中来回循环

  3)当使用ostimedly()函数对任务延时,当延时时间已经完成,系统无法跳出空任务循环,移植在IdleTask中运行

  4)任务切换过程中总是跳入到异常中断中。

 

移植思路:

  开始移植过程时,下载了micrium官网上提供的关于28335的移植历程,他的历程导入后整体框架如下图所示:

  

上图中主要包含了5个文件夹分别是APP  BSP  UC-CPU  UC-LIB  UCOS-II

APP 主要包含了应用代码,主要是官方自己编写的一个小程序,其中各种.h文件是对ucos的一些配置

BSP称作板级支持包,这个就按照通俗理解的官方提供的历程中所使用的各种.c文件,比如我需要控制IO口,就要使用F2837xD_GPIO.C中的一些函数,这些就是BSP

UC-CPU暂时未用,好像有包含

UC-LIB暂时未用,貌似是一些支持库,但是F28377D本身自带就有一些运算支持库

UCOS-II这个是重头戏,里面包含了两个文件夹

      source 文件夹下是ucos的无关核代码,这些不需要修改

      prots->c28x->generic->ccs里面的代码是和内核有关的代码,无非也就是操作堆栈,保存cpu的当前寄存器值以及恢复等等,这些是需要修改的

                    但是下载的代码已经帮我们修改好了。直接使用

 

最开始的移植思路是 : 

BSP 板级支持包不使用micrum提供的,查阅代码可以发现BSP中无非就是对外设的控制和上电初始化芯片的过程,这些完全可以倒入一个F28377D的历程

使用历程中的例子来完成初始化,这样更加方便

 

提供给ucos的时间中断,这个就人为的使用cputimer来做一个中断,中断函数里面调用ostimetick函数来实现。

 

步骤如下:

首先在28377D的历程中导入一个blink灯闪的历程,修改后的框架如下图所示:

同样包含了下面几个文件夹,这个只是我自己用的,和历程不一样,这个是随意的:

cmd  driver  pcore  uc-cpu  uc-lib  ucos-ii

cmd中存放的是历程的cmd文件

driver存放的就是那些调用外设的驱动程序,也就是用来替换BSP的

pcore是放置应用程序的。h文件的定义,直接从micrum中复制过来的

uc-cpu  uc-lib  ucos-ii  是和micrum提供的源码一样的(复制过来的)

主函数被放置在了processflow中,这里没有打开显示。

 

代码如下所示:

 

修改后的mian函数如下:

#include <string.h>
#include "F28x_Project.h"
#include "F2837xD_Ipc_drivers.h"
#include <app_cfg.h>
#include <ucos_ii.h>
#include <cpu_core.h>
#include <lib_def.h>
__interrupt void cpu_timer0_isr(void);
//#pragma CODE_SECTION(App_TaskStartStk , "RAMGS0");
//#pragma CODE_SECTION(App_TaskPendStk , "RAMGS0");
//#pragma CODE_SECTION(App_TaskPostStk , "RAMGS0");
CPU_STK_SIZE App_TaskStartStk[APP_CFG_TASK_STK_SIZE];
/* Ping Task\'s    stack.*/
CPU_STK_SIZE App_TaskPendStk[APP_CFG_TASK_STK_SIZE];
/* Pong Task\'s    stack.*/
CPU_STK_SIZE App_TaskPostStk[APP_CFG_TASK_STK_SIZE];
static OS_EVENT *AppTaskObjSem;
/*********************************************************************************************
************
* FUNCTION PROTOTYPES
**********************************************************************************************
***********
*/
/* Start Task.*/
static void App_TaskStart(void *p_arg);
/* Ping Task. */
//static void App_TaskPing (void *p_arg);
/* Pong Task. */
static void App_TaskPong (void *p_arg);
void cpu_timer0_isr(void)
{
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
OSIntEnter();
OSTimeTick();
OSIntExit();
}
void CPU_Initfunc(void){
InitSysCtrl();
//memcpy(&RamfuncsRunStart,&RamfuncsLoadStart,(size_t)&RamfuncsLoadSize);
InitFlash();
//IPCBootCPU2(C1C2_BROM_BOOTMODE_BOOT_FROM_FLASH);
//CsmUnlock();
InitGpio();
DINT;
InitPieCtrl();
IER = 0x0000;
IFR = 0x0000;
InitPieVectTable();
EINT; // Enable Global interrupt INTM
ERTM; // Enable Global realtime interrupt DBG
}
void BSP_INIT(void){
GPIO_SetupPinMux(10, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(10, GPIO_OUTPUT, GPIO_ASYNC);
}
void BSP_LED_Off(void){
GpioDataRegs.GPADAT.bit.GPIO10 = 0;
}
void BSP_Tick_Init(void){
EALLOW; // This is needed to write to EALLOW protected registers
PieVectTable.TIMER0_INT = &cpu_timer0_isr;
EDIS; // This is needed to disable write to EALLOW protected registers
InitCpuTimers();
//CpuTimer0 时间为设置扫频之间的等待时间 1000 代表1ms
//CpuTimer1为采样定时器时间设置
ConfigCpuTimer(&CpuTimer0, 200, 100000);
CpuTimer0Regs.TCR.all = 0x4000; // Use write-only instruction to set TSS bit = 0
IER |= M_INT1;
IER |= M_INT13;
//IER |= M_INT14;
CpuTimer0Regs.TCR.bit.TSS = 1;
PieCtrlRegs.PIEIER1.bit.INTx7 = 1;
EINT; // Enable Global interrupt INTM
ERTM; // Enable Global realtime interrupt DBGM
CpuTimer0Regs.TCR.all = 0x4000;
}
void BSP_LED_Toggle(void){
GpioDataRegs.GPATOGGLE.bit.GPIO10 = 1;
}
int main (void) { /* Initialize the CPU and Board.*/ //CPU_Init(); //BSP_Init(); CPU_Initfunc(); BSP_INIT(); OSInit(); DELAY_US(1000000); /* Create the Start task.*/ OSTaskCreateExt(App_TaskStart, (void *)0, (CPU_STK *)&App_TaskStartStk[0], (INT8U )APP_CFG_TASK_START_PRIO, (INT16U )APP_CFG_TASK_START_PRIO, (CPU_STK *)&App_TaskStartStk[APP_CFG_TASK_STK_SIZE - 1u], (INT32U )APP_CFG_TASK_STK_SIZE, (void *)0, (INT16U )(OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR)); /* Start multitasking (i.e. give control to uC/OS-II). */ OSStart(); /* Should never get here.*/ while (DEF_TRUE) { ; } } /* ********************************************************************************************** *********** * App_TaskStart() * * Description : First task to be scheduled. Creates the application tasks. * * Argument(s) : p_arg the argument passed by \'OSTaskCreateExt()\'. * * Return(s) : none. * * Caller(s) : This is a task. * * Note(s) : (1) This task creates the application task. The application is a simple LED blinking * demo where LD1 and LD4 blink at a 4:3 polyrhythm. ********************************************************************************************** *********** */ static void App_TaskStart (void *p_arg) { CPU_INT08U os_err; /* Prevent compiler warning for not using \'p_arg\' */ (void)&p_arg; /* Clear the LEDs.*/ BSP_LED_Off(); /* Start the Ticker.*/ BSP_Tick_Init(); /* Create the Ping task.*/ AppTaskObjSem = OSSemCreate(0); // OSTaskCreateExt(App_TaskPing, // (void *)0, // (CPU_STK *)&App_TaskPendStk[0], // (INT8U )APP_CFG_TASK_PEND_PRIO, // (INT16U )APP_CFG_TASK_PEND_PRIO, // (CPU_STK *)&App_TaskPendStk[APP_CFG_TASK_STK_SIZE - 1u], // (INT32U )APP_CFG_TASK_STK_SIZE, // (void *)0, /* Create the Pongtask.*/ OSTaskCreateExt(App_TaskPong, (void *)0, (CPU_STK *)&App_TaskPostStk[0], (INT8U )APP_CFG_TASK_POST_PRIO, (INT16U )APP_CFG_TASK_POST_PRIO, (CPU_STK *)&App_TaskPostStk[APP_CFG_TASK_STK_SIZE - 1u], (INT32U )APP_CFG_TASK_STK_SIZE, (void *)0, (INT16U )(OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR)); /* All tasks should be written as an infinite loop. */ while (DEF_TRUE) { //os_err = OSSemPost(AppTaskObjSem); //OSTimeDlyHMSM(0, 0, 0, 500); OSTimeDly(80); DELAY_US(1000000); } } /* ********************************************************************************************** *********** * App_TaskPing() * * Description : \'Ping\' task, toggles LD1. * * Argument(s) : p_arg the argument passed by \'OSTaskCreateExt()\'. * * Return(s) : none. * * Caller(s) : This is a task. ********************************************************************************************** *********** */ //static void App_TaskPing (void *p_arg) //{ // CPU_INT08U os_err; // /* Prevent compiler warning for not using \'p_arg\' */ // (void)&p_arg; // // /* Task body, always written as an infinite loop. */ // while (DEF_TRUE) { // OSSemPend( AppTaskObjSem, // 0, // &os_err); // } //} /* ********************************************************************************************** *********** * App_TaskPong) * * Description : \'Pong\' task, toggles LD4. * * Argument(s) : p_arg the argument passed by \'OSTaskCreateExt()\'. * * Return(s) : none. * * Caller(s) : This is a task. ********************************************************************************************** *********** */ static void App_TaskPong (void *p_arg) { /* Prevent compiler warning for not using \'p_arg\' */ (void)&p_arg; /* Task body, always written as an infinite loop. */ while (DEF_TRUE) { BSP_LED_Toggle(); OSTimeDly(2); } }

 

micrum提供的历程中app.c里面的mian()函数是包含了CPU_Init();和BSP_Init()两个函数,分别是用来初始化芯片以及初始化ucos。在我的函数中

同样提供了两个函数分别为CPU_Initfunc()和BSP_INIT();

 

CPU_Initfunc()函数主要是对cpu进行必要的初始化,复制的历程的初始化代码流程

BSP_INIT()的代码代码段是初始化GPIO10,我的板子上GPIO10连着一个灯。

之后就是创建了第一个任务APP_TASKSTART任务,

之后调用OSSTART()函数去执行当前优先任务最好的任务,至于osstart()函数中的内容,请自己去看

 

void BSP_Tick_Init(void)
void cpu_timer0_isr(void)

函数为ucos系统提供时钟节拍,第一个函数是初始化timer,代码是参考28377d的历程中有关于timer定时器的设置,此处设置的是50的定时

50ms定时一到就会跳入中断函数,也就是第二个函数,在第二个函数中调用ostimetick()函数为ucos提供时钟节拍,ostimetick()请

自己参考函数内容。

 

下面来说明产生问题的原因以及解决:

 

1\\文件组织问题上面已经显示了

 

2、移植完成后系统无法跳转进入任务执行:

  产生原因 :在任务跳转的时候,ucos其实是模拟了返回中断的过程,在创建任务的时候,将创建任务的各种信息(创建的时候其实只有sp指针以及返回地址有用),虽然

  创建的时候cpu的值是使用的假信息,具体自己去看创建代码。

 

  在需要做任务切换时,系统是将对应任务tcb中的堆栈指针返回到cpu的堆栈sp中,然后通过出栈过程将信息返回,然后执行回调跳回到需要执行的任务的代码处。

 

  问题就出现在cpu的sp寄存器是16位的,所以在创建task过程中,指定的App_TaskPostStk的内存必须要指定在一个地址低于16位的内存当中,他的指定是在cmd中完成的。

  最开始出错是应为我将App_TaskPostStk内存映射到了0x10000的内存当中,所以16位sp获取到的sp的值就为0x0000调转到初始代码处,所以一直在循环:

OSTaskCreateExt(App_TaskPong,
(void *)0,
(CPU_STK *)&App_TaskPostStk[0],
(INT8U )APP_CFG_TASK_POST_PRIO,
(INT16U )APP_CFG_TASK_POST_PRIO,
(CPU_STK *)&App_TaskPostStk[APP_CFG_TASK_STK_SIZE - 1u],
(INT32U )APP_CFG_TASK_STK_SIZE,
(void *)0,
(INT16U )(OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR));


  下面是调试过程的截图:

  图1  :  

 

  

 

 

图2 

 

 

图1 中任务启动后会跳转到osstarthigtrdy函数中,然后在跳转到OS_CTX_RESTORE这个函数在asm文件中自己看,

主要的目的就是把最高优先级的任务返回到cpu中,看反汇编代码中0119a4地址中的指令时将sp返回的,最右边的sp的值是DA35

如果超过16位那就被结尾了,再然后调用IRET函数将保存在任务栈中的task地址返回到pc中执行。这样就完成了任务的切换。至于创建任务的时候,各种值是怎么保存到栈中的,请

自己查看代码。

 

3、当使用ostimedly()函数对任务延时,当延时时间已经完成,系统无法跳出空任务循环,移植在IdleTask中运行

通过ostimedly函数,任务就有一个延时参数,每次中断完成调用ostimetick函数,延迟参数减一,知道递减到0,然后ostimetick函数将

任务又重新插入到就绪表里,具体参考ostimetick函数。

 

但是 但是 但是 ostimetick函数里是没有任务切换的  ostimetick函数里是没有任务切换的   ostimetick函数里是没有任务切换的;

重要的事情说三遍,所以添加上osIntEnter()和OsIntExit()函数。

OsIntExit()函数里有任务切换函数。这才会导致任务从IdleTask中重新调回任务中执行。

void cpu_timer0_isr(void)
{
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
OSIntEnter();
OSTimeTick();
OSIntExit();
}

 

4、任务切换过程中总是跳入到异常中断中

首先必须要明白一个问题,任务的切换还是穿件ucos都是将他作为一个中断过程来处理的。比如在上面的程序中,任务延时2个时钟节拍后要继续执行,

在timer定时器的中断中,调用osIntExit()函数。

 

看看看 重要的地方出现了,任务的跳转是调用了OSiNTcTXsW这个宏定义。

这个宏定义就是 : asm("  TRAP  #16");

跳转到中断列表中第16个中断,请翻阅28377d的芯片手册,第16个中断的为位置真好是在默认包含了所有中断表的。c文件即

F28377xD_DefaultISR.c中。

第16个中断对应的地址就是 : inrerrupt  void  RTOS_ISR(void)中;

就是说,这个时候ucos通过指令就把指针调转到了 inrerrupt  void  RTOS_ISR(void)中来执行。

按照ucos的设想,在这个函数中呢就包含了两个步骤,保存当前cpu寄存器值,

将最高优先级任务sp指针返回,并当做中断回调到任务中去。

 

但是坑就在这个地方;因为我使用的是TI的历程,历程中这个函数是空的,关于cpu寄存器的操作是在ucos-ii->prots->generic->ccs->os_cpu_a.asm

这个文件中的_os_cpu_rtosint_handler:函数,这个自己去看,是有的。

 

最初的做法,我是在 inrerrupt  void  RTOS_ISR(void)中断函数中调用_os_cpu_rtosint_handler;这就相当于进了两次中断,子啊保存的时候保存了两次,

保存在堆栈中断返回地址就已近不是任务的返回地址而是其他的值了。

 

所以这个点我做了一点修改,中断函数是按照名字来区别的(实际是名字所对应的地址),所以我就将:

ucos-ii->prots->generic->ccs->os_cpu_a.asm文件下_os_cpu_rtosint_handler的名字更换为_RTOS_ISR;让中断直接运行,不经过两次调用

在F28377xD_DefaultISR.c中将 inrerrupt  void  RTOS_ISR(void)函数屏蔽。

 

运行成功。

 

整个移植过程就完成了,并且能够让这个ucos运行起来。至于他更精妙的用法我暂时还没有领会到。

慢慢在用起来把。

 

如果上文有错误之处,请指正:

邮箱 havihouston@outlook.com

 

以上是关于请问各位,ucos ii中的软件定时器和延时有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

请问我在stm32上移植了ucos,现在需要使用到DS18B20采集温度

ucos-ii在ti dsp 28377芯片上的运行过程和移植过程

请问51单片机定时器延时的调用是怎么调用的我有点不明白,谢谢

μC/OS-II中使用软件定时器

UCOS iii 定时器

单片机中用写delay函数做延时和用定时器做延时有啥区别?