打印
[应用相关]

RTX操作系统-定时器组

[复制链接]
1014|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
ideafor|  楼主 | 2016-3-3 22:28 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
定时器组
    本章节为大家讲解RTX支持的定时器组,或者叫软件定时器,或者叫用户定时器均可。软件定时器的功能比较简单,也容易掌握。被称为定时器组是因为用户可以创建多个定时器,创建的个数是可配置的。
    本章教程配套的例子含Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407。
17.1 定时器组介绍
17.2 定时器组API函数
17.3 实验例程说明
17.4      总结


17.1  定时器组介绍
    RTX提供的定时器功能仅支持单次定时器,也就是用户创建了定时器并启动了定时器后,定时时间到将不再重新执行,此定时器会被删除掉并且就执行一次,下次使用要重新的创建,这个就是单次定时器的含义。另外就是单次定时时间到后会调用定时器的回调函数,用户可以回调函数中加入需要执行的工程代码。
    使用此定时器组注意以下问题:
(1)定时器回调函数os_tmr_call在文件RTX_Conf_CM.c文件中。
(2)定时器回调函数os_tmr_call中仅支持isr_开头的系统函数,os_开头的不支持,因为回调函数是在滴答定时器中断中执行的。
(3)RTX的定时器仅支持单次,不支持周期性执行,如果需要周期执行,需要重复创建。
(4)可以创建的定时器个数可以在RTX配置向导中设置:







沙发
ideafor|  楼主 | 2016-3-3 22:29 | 只看该作者
17.2  定时器组API函数
   使用如下3个函数可以实现RTX的定时器组:
os_tmr_create
os_tmr_kill
os_tmr_call
关于这3个函数的讲解及其使用方法可以看教程第3章3.3小节里面说的参考资料rlarm.chm文件


                              
这里我们重点的说一下函数os_tmr_create和os_tmr_call。

17.2.1  函数os_tmr_create
函数原型:
OS_ID os_tmr_create (
    U16 tcnt,      /* 定时器的时钟节拍个数 */
    U16 info );    /* 定时器回调函数的参数,可用于区分不同的定时器 */

函数描述:
函数os_tmr_create用于创建定时器组并启动定时器,定时时间到后调用回调函数os_tmr_call。函数os_tmr_create的第二个参数也会传递给回调函数os_tmr_call用于区分不同的定时器。
    (1)第1个参数填写定时器的时钟节拍个数。范围0-0xFFFF。
    (2)第2个参数填写回调函数的参数,可用于区分不同的定时器。
    (3)定时器创建成功的话会返回定时器的ID标识,失败的话返回NULL。
使用举例:
#include <rtl.h>

/* 定时器句柄 */
OS_ID  OneShotTimerID1;

__task void task1 (void) {
   ..
  OneShotTimerID1= os_tmr_create (10, 1);
  if (OneShotTimerID1 == NULL) {
    printf ("创建失败\n");
  }
   ..
}


使用特权

评论回复
板凳
ideafor|  楼主 | 2016-3-3 22:30 | 只看该作者
17.2.2 函数os_tmr_call
函数原型:
void os_tmr_call (
    U16 info );    /*定时器回调函数的参数,可用于区分不同的定时器*/

函数描述:
当函数os_tmr_create设置的定时时间到后调用回调函数os_tmr_call。函数os_tmr_create的第二个参数也会传递给回调函数os_tmr_call用于区分不同的定时器。此函数执行完毕后,通过函数os_tmr_create创建的定时器会被删除,下次使用需要重新创建。
(1)此函数的参数不需要用户去添加,系统会自动将函数os_tmr_create第二个参数赋值给这个参数。
使用举例:
#include <rtl.h>

void os_tmr_call (U16 info) {
  /* 定时器回调函数中仅支持isr_开头的系统函数,os_开头的不支持,此回调函数是在
     滴答定时器中断中执行的。
  */
  switch(info)
  {
case 1:          /* 参数为1 */
         isr_sem_send (&semaphore);     
         break;
         
      case 2:          /* 参数为2 */
        bsp_LedToggle(1);   
        break;
  }
}


使用特权

评论回复
地板
ideafor|  楼主 | 2016-3-3 22:31 | 只看该作者
17.3 实验例程说明
17.3.1 STM32F103开发板实验
配套例子:
    V4-416_RTX实验_定时器组
实验目的:
    1.     学习RTX的定时器组
    2.     RTX的定时器仅支持单次,不支持周期性执行,如果需要周期执行,需要重复创建
    3.     定时器回调函数os_tmr_call中仅支持isr_开头的系统函数,os_开头的不支持,此回调函数是在滴答定时器中断中执行的。
    4.     回调函数os_tmr_call在文件RTX_Conf_CM.c文件中。
实验内容:
    1.K1按键按下,串口打印。
    2.K2键按下,创建单次定时器,10个系统时钟节拍后在定时器回调函数中给任务AppTaskMsgPro发信号量同步信号。
    3.K3键按下,创建单次定时器,10个系统时钟节拍后在定时器回调函数翻转LED1。
    4.各个任务实现的功能如下:
  AppTaskUserIF任务   :按键消息处理。
  AppTaskLED任务     :LED闪烁。
  AppTaskMsgPro任务 :消息处理,等待RTX定时器发来的信号量同步信号。
  AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
RTX配置:
    RTX配置向导详情如下:
                              
Task Configuration
    Number of concurrent running tasks
  允许创建4个任务,实际创建了如下四个任务:
                AppTaskUserIF任务   :按键消息处理。
                AppTaskLED任务     :LED闪烁。
                AppTaskMsgPro任务 :消息处理,等待RTX定时器发来的信号量同步信号。
                AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
    Number of tasks with user-provided stack
  创建的4个任务都是采用自定义堆栈方式。
    Number of user timers
  范围1 – 250,表示用户定时器个数。
  这里创建了1个用户定时器。
RTX任务调试信息:
程序设计:
任务栈大小分配:
staticuint64_t AppTaskUserIFStk[512/8];   /* 任务栈 */
    staticuint64_t AppTaskLEDStk[256/8];      /* 任务栈 */
    staticuint64_t AppTaskMsgProStk[512/8];  /* 任务栈 */
    staticuint64_t AppTaskStartStk[512/8];     /* 任务栈 */
将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数,浮点运算和uint64_t类型数据运算会出问题。
系统栈大小分配:
17.5.png (32.42 KB, 下载次数: 0)
下载附件
2016-2-2 17:27 上传



使用特权

评论回复
5
ideafor|  楼主 | 2016-3-3 22:31 | 只看该作者
RTX初始化:
/*
*********************************************************************************************************
*    函 数 名: main
*    功能说明: 标准c程序入口。
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
int main (void)
{   
     /* 初始化外设 */
     bsp_Init();
   
     /* 创建启动任务 */
     os_sys_init_user (AppTaskStart,             /* 任务函数 */
                       4,                        /* 任务优先级 */
                       &AppTaskStartStk,         /* 任务栈 */
                       sizeof(AppTaskStartStk)); /* 任务栈大小,单位字节数 */
     while(1);
}

RTX任务创建:
/*
*********************************************************************************************************
*    函 数 名: AppTaskCreate
*    功能说明: 创建应用任务
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static void AppTaskCreate (void)
{
     HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任务函数 */
                                           1,                         /* 任务优先级 */
                                           &AppTaskUserIFStk,         /* 任务栈 */
                                           sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */
   
     HandleTaskLED = os_tsk_create_user(AppTaskLED,              /* 任务函数 */
                                        2,                       /* 任务优先级 */
                                        &AppTaskLEDStk,          /* 任务栈 */
                                        sizeof(AppTaskLEDStk));  /* 任务栈大小,单位字节数 */
   
     HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,             /* 任务函数 */
                                           3,                         /* 任务优先级 */
                                           &AppTaskMsgProStk,         /* 任务栈 */
                                           sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */
}


使用特权

评论回复
6
ideafor|  楼主 | 2016-3-3 22:32 | 只看该作者
创建信号量:
OS_SEM semaphore;

/*
*********************************************************************************************************
*    函 数 名: AppObjCreate
*    功能说明: 创建任务通信机制
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static void AppObjCreate (void)
{
     /* 创建信号量计数值是0, 用于任务同步 */
     os_sem_init (&semaphore, 0);
   
}
四个RTX任务的实现,定时器的创建在任务AppTaskUserIF中实现:
/*
/*
*********************************************************************************************************
*    函 数 名: AppTaskUserIF
*    功能说明: 按键消息处理     
*    形    参: 无
*    返 回 值: 无
*   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
*********************************************************************************************************
*/
__task void AppTaskUserIF(void)
{
     uint8_t ucKeyCode;

    while(1)
    {
         ucKeyCode = bsp_GetKey();
        
         if (ucKeyCode != KEY_NONE)
         {
              switch (ucKeyCode)
              {
                   /* K1键按下,打印调试说明 */
                   case KEY_DOWN_K1:
                       printf("K1键按下,使用MDK中自带的RTX调试组件,请务必使用MDK4.74版本进行调试\r\n");
                       break;  
                  
                   /*
                      K2键按下,创建单次定时器,定时时间10个系统时钟节拍, 在定时器回调函数中给任务
                      AppTaskMsgPro发信号量同步信号
                   */
                   case KEY_DOWN_K2:
                       printf("K2键按下,创建单次定时器,10个系统时钟节拍后在定时器回调函数中给任务
AppTaskMsgPro发信号量同步信号\r\n");
                       /*
                         1. RTX的定时器仅支持单次,不支持周期性执行,如果需要周期执行,需要重复创建
                         2. 定时器回调函数os_tmr_call中仅支持isr_开头的系统函数,os_开头的不支持,此回调函
数是在滴答定时器中断中执行的。
                         3. 回调函数os_tmr_call在文件RTX_Conf_CM.c文件中。
                       */
                       OneShotTimerID1 = os_tmr_create(10,  /* 定时10个系统时钟节拍 */
                                                      1);  /* 回调函数的参数,可用于区分不同的定时器 */
                     
                       if (OneShotTimerID1 == NULL)
                       {
                            /* 没有创建成功,用户可以在这里加入创建失败的处理机制 */
                       }
                       break;
                     
                   case KEY_DOWN_K3:
                       printf("K3键按下,创建单次定时器,10个系统时钟节拍后在定时器回调函数翻转LED1\r\n");
                       OneShotTimerID2 = os_tmr_create(10,  /* 定时10个系统时钟节拍 */
                                                       2);  /* 回调函数的参数,可用于区分不同的定时器 */
                     
                       if (OneShotTimerID2 == NULL)
                       {
                            /* 没有创建成功,用户可以在这里加入创建失败的处理机制 */
                       }
                       break;

                   /* 其他的键值不处理 */
                   default:                    
                       break;
              }
         }
        
         os_dly_wait(20);
     }
}

/*
*********************************************************************************************************
*    函 数 名: AppTaskLED
*    功能说明: LED闪烁。
*    形    参: 无
*    返 回 值: 无
*   优 先 级: 2
*********************************************************************************************************
*/
__task void AppTaskLED(void)
{
     const uint16_t usFrequency = 200; /* 延迟周期 */
   
     /* 设置延迟周期 */
     os_itv_set(usFrequency);
   
    while(1)
    {
         bsp_LedToggle(2);
         bsp_LedToggle(3);

         /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/
         os_itv_wait();
    }
}

/*
*********************************************************************************************************
*    函 数 名: AppTaskMsgPro
*    功能说明: 消息处理,等待RTX定时器发来的信号量同步信号
*    形    参: 无
*    返 回 值: 无
*   优 先 级: 3
*********************************************************************************************************
*/
__task void AppTaskMsgPro(void)
{
     OS_RESULT xResult;
     const uint16_t usMaxBlockTime = 200; /* 延迟周期 */
   
    while(1)
    {
         xResult = os_sem_wait (&semaphore, usMaxBlockTime);
        
         switch (xResult)
         {
              /* 无需等待接受到信号量同步信号 */
              case OS_R_OK:
                   printf("无需等待接受到信号量同步信号\r\n");
                   break;  

              /* 信号量不可用,usMaxBlockTime等待时间内收到信号量同步信号 */
              case OS_R_SEM:
                   printf("信号量不可用,usMaxBlockTime等待时间内收到信号量同步信号\r\n");
                   break;

              /* 超时 */
              case OS_R_TMO:
                   bsp_LedToggle(4);
                   break;
            
              /* 其他值不处理 */
              default:                    
                   break;
         }   
    }
}

/*
*********************************************************************************************************
*    函 数 名: AppTaskStart
*    功能说明: 启动任务,也就是最高优先级任务。这里实现按键扫描。
*    形    参: 无
*    返 回 值: 无
*   优 先 级: 4
*********************************************************************************************************
*/
__task void AppTaskStart(void)
{
     /* 创建任务 */
     AppTaskCreate();
   
     /* 创建任务通信机制 */
     AppObjCreate();
   
    while(1)
    {
         /* 按键扫描 */
         bsp_KeyScan();
        os_dly_wait(10);
    }
}


使用特权

评论回复
7
ideafor|  楼主 | 2016-3-3 22:33 | 只看该作者
定时器回调函数的实现,在文件RTX_Conf_CM.c:
/*--------------------------- os_tmr_call -----------------------------------*/
#include "bsp.h"
extern OS_SEM semaphore;
void os_tmr_call (U16 info) {
  /* This function is called when the user timer has expired. Parameter   */
  /* 'info' holds the value, defined when the timer was created.          */

  /* HERE: include optional user code to be executed on timeout. */
  /* 定时器回调函数中仅支持isr_开头的系统函数,os_开头的不支持,此回调函数是在
     滴答定时器中断中执行的。
  */
  switch(info)
  {
     case 1:          /* 参数为1 */
      isr_sem_send (&semaphore);     
      break;
   
     case 2:          /* 参数为2 */
       bsp_LedToggle(1);   
      break;
  }
}
17.3.2 STM32F407开发板实验
配套例子:
    V4-416_RTX实验_定时器组
实验目的:
    1.     学习RTX的定时器组。
    2.     RTX的定时器仅支持单次,不支持周期性执行,如果需要周期执行,需要重复创建。
    3.     定时器回调函数os_tmr_call中仅支持isr_开头的系统函数,os_开头的不支持,此回调函数是在滴答定时器中断中执行的。
    4.     回调函数os_tmr_call在文件RTX_Conf_CM.c文件中。
实验内容:
    1.K1按键按下,串口打印。
    2.K2键按下,创建单次定时器,10个系统时钟节拍后在定时器回调函数中给任务AppTaskMsgPro发信号量同步信号。
    3.K3键按下,创建单次定时器,10个系统时钟节拍后在定时器回调函数翻转LED1。
    4.各个任务实现的功能如下:
    AppTaskUserIF任务   :按键消息处理。
    AppTaskLED任务     :LED闪烁。
    AppTaskMsgPro任务 :消息处理,等待RTX定时器发来的信号量同步信号。
    AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
RTX配置:  
    RTX配置向导详情如下:
                              
Task Configuration
Number of concurrent running tasks
  允许创建4个任务,实际创建了如下四个任务:
                AppTaskUserIF任务   :按键消息处理。
                AppTaskLED任务     :LED闪烁。
                AppTaskMsgPro任务 :消息处理,等待RTX定时器发来的信号量同步信号。
                AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
    Number of tasks with user-provided stack
  创建的4个任务都是采用自定义堆栈方式。
    Number of user timers
  范围1 – 250,表示用户定时器个数。
  这里创建了1个用户定时器。
RTX任务调试信息:

使用特权

评论回复
8
ideafor|  楼主 | 2016-3-3 22:34 | 只看该作者
将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数,浮点运算和uint64_t类型数据运算会出问题。
系统栈大小分配:


RTX初始化:
/*
*********************************************************************************************************
*    函 数 名: main
*    功能说明: 标准c程序入口。
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
int main (void)
{   
     /* 初始化外设 */
     bsp_Init();
   
     /* 创建启动任务 */
     os_sys_init_user (AppTaskStart,             /* 任务函数 */
                       4,                        /* 任务优先级 */
                       &AppTaskStartStk,         /* 任务栈 */
                       sizeof(AppTaskStartStk)); /* 任务栈大小,单位字节数 */
     while(1);
}

RTX任务创建:
/*
*********************************************************************************************************
*    函 数 名: AppTaskCreate
*    功能说明: 创建应用任务
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static void AppTaskCreate (void)
{
     HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任务函数 */
                                           1,                         /* 任务优先级 */
                                           &AppTaskUserIFStk,         /* 任务栈 */
                                           sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */
   
     HandleTaskLED = os_tsk_create_user(AppTaskLED,              /* 任务函数 */
                                        2,                       /* 任务优先级 */
                                        &AppTaskLEDStk,          /* 任务栈 */
                                        sizeof(AppTaskLEDStk));  /* 任务栈大小,单位字节数 */
   
     HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,             /* 任务函数 */
                                           3,                         /* 任务优先级 */
                                           &AppTaskMsgProStk,         /* 任务栈 */
                                           sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */
}
创建信号量:
OS_SEM semaphore;

/*
*********************************************************************************************************
*    函 数 名: AppObjCreate
*    功能说明: 创建任务通信机制
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static void AppObjCreate (void)
{
     /* 创建信号量计数值是0, 用于任务同步 */
     os_sem_init (&semaphore, 0);
   
}


使用特权

评论回复
9
ideafor|  楼主 | 2016-3-3 22:35 | 只看该作者
四个RTX任务的实现,定时器的创建在任务AppTaskUserIF中实现:
/*--------------------------- os_tmr_call -----------------------------------*/
#include "bsp.h"
extern OS_SEM semaphore;
void os_tmr_call (U16 info) {
  /* This function is called when the user timer has expired. Parameter   */
  /* 'info' holds the value, defined when the timer was created.          */

  /* HERE: include optional user code to be executed on timeout. */
  /* 定时器回调函数中仅支持isr_开头的系统函数,os_开头的不支持,此回调函数是在
     滴答定时器中断中执行的。
  */
  switch(info)
  {
     case 1:          /* 参数为1 */
      isr_sem_send (&semaphore);     
      break;
   
     case 2:          /* 参数为2 */
       bsp_LedToggle(1);   
      break;
  }
}


使用特权

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

本版积分规则

30

主题

149

帖子

1

粉丝