内核对象和各种内核机制的函数接口都在os.h里声明,实现在各自的.c文件,比如os_tmr.cos_time.c

C语言全局变量一般会默认初始化;局部变量如若不初始化,会分配垃圾数据的;建议使用时都手动初始化。

其实使用内核对象时,就类似与使用任务,只不过在创建对象之前,要先声明一个内核对象。

好了,上面闲聊了几句,今天来说说ucosiii的几个内核对象。

首先说“软件定时器”,其实单纯的讲就是定时作用,这里我们要注意的就是,使用它方法和使用任务类似;那么我们就先来分析分析任务的执行过程:

  1. main会初始化ucos;调用一个起始任务创建函数(它的参数就是就是任务的工作模式,任务信息,任务函数指针)来创建任务;启动多任务管理。
  2. 任务函数指针指向起始任务函数会初始化操作系统;调用若干普通任务创建函数(与上一致)来创建任务;删除起始任务本身。
  3. 任务函数就会完成具体的操作。

那继续说软件定时器,在上面的3里任务函数会声明一个定时器对象,然后调用一个定时器创建函数(它的参数为定时器信息,工作模式,回调函数指针等)来创建任务,回调函数完成一些自定义的操作(每次定时完成会调用此回调函数),最后调用OSTmrStart()启动软件定时器;接下来就可以使用它了。

 

 

我们可以知道,用OSTimeDly是将任务置为等待态,CPU的使用权暂时被剥夺,开启定时器之后,该任务还是可以使用CPU

通过debug我们也可以发现,运行完OSTimeDly之后(也可以说定时了指定时间之后),会完成一次回调函数里面的操作。也就验证了这个结论“定时完成之后会调用回调函数”。

下面我们就具体看一下源码,声明:这是秉火例程里的代码,我只是做了稍加修改。

 

#include <includes.h>

CPU_TS             ts_start;       //时间戳变量
CPU_TS             ts_end; 

static  OS_TCB   AppTaskStartTCB;                                //任务控制块

static  OS_TCB   AppTaskTmrTCB;



static  CPU_STK  AppTaskStartStk[APP_TASK_START_STK_SIZE];       //任务堆栈

static  CPU_STK  AppTaskTmrStk [ APP_TASK_TMR_STK_SIZE ];


static  void  AppTaskStart  (void *p_arg);                       //任务函数声明

static  void  AppTaskTmr  ( void * p_arg );


int  main (void)
{
    OS_ERR  err;


    OSInit(&err);                                                           //初始化 uC/OS-III

      /* 创建起始任务 */
    OSTaskCreate((OS_TCB     *)&AppTaskStartTCB,                            //任务控制块地址
                 (CPU_CHAR   *)"App Task Start",                            //任务名称
                 (OS_TASK_PTR ) AppTaskStart,                               //任务函数
                 (void       *) 0,                                          //传递给任务函数(形参p_arg)的实参
                 (OS_PRIO     ) APP_TASK_START_PRIO,                        //任务的优先级
                 (CPU_STK    *)&AppTaskStartStk[0],                         //任务堆栈的基地址
                 (CPU_STK_SIZE) APP_TASK_START_STK_SIZE / 10,               //任务堆栈空间剩下1/10时限制其增长
                 (CPU_STK_SIZE) APP_TASK_START_STK_SIZE,                    //任务堆栈空间(单位:sizeof(CPU_STK))
                 (OS_MSG_QTY  ) 5u,                                         //任务可接收的最大消息数
                 (OS_TICK     ) 0u,                                         //任务的时间片节拍数(0表默认值OSCfg_TickRate_Hz/10)
                 (void       *) 0,                                          //任务扩展(0表不扩展)
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), //任务选项
                 (OS_ERR     *)&err);                                       //返回错误类型

    OSStart(&err);                                                          //启动多任务管理(交由uC/OS-III控制)
        
        
}

static  void  AppTaskStart (void *p_arg)
{
    CPU_INT32U  cpu_clk_freq;
    CPU_INT32U  cnts;
    OS_ERR      err;


   (void)p_arg;

    BSP_Init();                                                 //板级初始化
    CPU_Init();                                                 //初始化 CPU 组件(时间戳、关中断时间测量和主机名)

    cpu_clk_freq = BSP_CPU_ClkFreq();                           //获取 CPU 内核时钟频率(SysTick 工作时钟)
    cnts = cpu_clk_freq / (CPU_INT32U)OSCfg_TickRate_Hz;        //根据用户设定的时钟节拍频率计算 SysTick 定时器的计数值
    OS_CPU_SysTickInit(cnts);                                   //调用 SysTick 初始化函数,设置定时器计数值和启动定时器

    Mem_Init();                                                 //初始化内存管理组件(堆内存池和内存池表)

#if OS_CFG_STAT_TASK_EN > 0u                                    //如果使能(默认使能)了统计任务
    OSStatTaskCPUUsageInit(&err);                               //计算没有应用任务(只有空闲任务)运行时 CPU 的(最大)
#endif                                                          //容量(决定 OS_Stat_IdleCtrMax 的值,为后面计算 CPU 
                                                                //使用率使用)。
    CPU_IntDisMeasMaxCurReset();                                //复位(清零)当前最大关中断时间

    
        /* 创建 AppTaskTmr 任务 */
    OSTaskCreate((OS_TCB     *)&AppTaskTmrTCB,                             //任务控制块地址
                 (CPU_CHAR   *)"App Task Tmr",                             //任务名称
                 (OS_TASK_PTR ) AppTaskTmr,                                //任务函数
                 (void       *) 0,                                          //传递给任务函数(形参p_arg)的实参
                 (OS_PRIO     ) APP_TASK_TMR_PRIO,                         //任务的优先级
                 (CPU_STK    *)&AppTaskTmrStk[0],                          //任务堆栈的基地址
                 (CPU_STK_SIZE) APP_TASK_TMR_STK_SIZE / 10,                //任务堆栈空间剩下1/10时限制其增长
                 (CPU_STK_SIZE) APP_TASK_TMR_STK_SIZE,                     //任务堆栈空间(单位:sizeof(CPU_STK))
                 (OS_MSG_QTY  ) 5u,                                         //任务可接收的最大消息数
                 (OS_TICK     ) 0u,                                         //任务的时间片节拍数(0表默认值OSCfg_TickRate_Hz/10)
                 (void       *) 0,                                          //任务扩展(0表不扩展)
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), //任务选项
                 (OS_ERR     *)&err);                                       //返回错误类型
                                 
        OSTaskDel ( & AppTaskStartTCB, & err );                     //删除起始任务本身,该任务不再运行
        
        
}


/*
*********************************************************************************************************
*                                          TMR TASK
*********************************************************************************************************
*/
void TmrCallback (OS_TMR *p_tmr, void *p_arg) //软件定时器MyTmr的回调函数
{
    CPU_INT32U       cpu_clk_freq;    
    CPU_SR_ALLOC();      //使用到临界段(在关/开中断时)时必需该宏,该宏声明和定义一个局部变
                                             //量,用于保存关中断前的 CPU 状态寄存器 SR(临界段关中断只需保存SR)
                                             //,开中断时将该值还原。  
  printf ( "%s", ( char * ) p_arg );
    
    cpu_clk_freq = BSP_CPU_ClkFreq();                   //获取CPU时钟,时间戳是以该时钟计数
    
    macLED1_TOGGLE (); 
    
  ts_end = OS_TS_GET() - ts_start;     //获取定时后的时间戳(以CPU时钟进行计数的一个计数值)
                                         //,并计算定时时间。
    OS_CRITICAL_ENTER();                 //进入临界段,不希望下面串口打印遭到中断
    
    printf ( "\r\n定时1s,通过时间戳测得定时 %07d us,即 %04d ms。\r\n", 
                        ts_end / ( cpu_clk_freq / 1000000 ),     //将定时时间折算成 us 
                        ts_end / ( cpu_clk_freq / 1000 ) );      //将定时时间折算成 ms 
    
    OS_CRITICAL_EXIT();                               

    ts_start = OS_TS_GET();                            //获取定时前时间戳
    
}


static  void  AppTaskTmr ( void * p_arg )
{
    OS_ERR      err;
    OS_TMR      my_tmr;   //声明软件定时器对象

    
    (void)p_arg;


  /* 创建软件定时器 */
  OSTmrCreate ((OS_TMR              *)&my_tmr,             //软件定时器对象
               (CPU_CHAR            *)"MySoftTimer",       //命名软件定时器
               (OS_TICK              )10,                  //定时器初始值,依10Hz时基计算,即为1s
               (OS_TICK              )10,                  //定时器周期重载值,依10Hz时基计算,即为1s
               (OS_OPT               )OS_OPT_TMR_PERIODIC, //周期性定时
               (OS_TMR_CALLBACK_PTR  )TmrCallback,         //回调函数
               (void                *)"Timer Over!",       //传递实参给回调函数
               (OS_ERR              *)err);                //返回错误类型
                             
    /* 启动软件定时器 */                         
  OSTmrStart ((OS_TMR   *)&my_tmr, //软件定时器对象
              (OS_ERR   *)err);    //返回错误类型
                     
    ts_start = OS_TS_GET();                       //获取定时前时间戳
                             
    while (DEF_TRUE) {                            //任务体,通常写成一个死循环DEF_TRUE
        printf("将任务置为等待态1s");
        OSTimeDly ( 1000, OS_OPT_TIME_DLY, & err ); //给任务提供定时 

    }
    
}

 

那再啰嗦一下回调函数,上面这个回调函数的类型声明如下:

typedef  void                      (*OS_TMR_CALLBACK_PTR)(void *p_tmr, void *p_arg);

显而易见的是,我们自定义的回调函数的返回类型OS_TMR_CALLBACK_PTR其实就是一个void指针(而这个指针是一个函数指针),为了避免晦涩的基础类型,所以typedef一下,便于理解。

 那再说一下void

1.当函数返回为空或参数列表为空使用。

2.void*指向任何类型,只不过使用时要转换成具体类型,才能操作。(上面的回调函数的实现有应用到)。

仔细将这些话与代码对应起来体会,很有意思的。。。

posted on 2018-08-17 22:09  lzd626  阅读(1334)  评论(0编辑  收藏  举报