RT-THREAD 内核快速入门(二)定时器

系列文章目录

RT-THREAD 内核快速入门(一)线程

RT-THREAD 内核快速入门(三) 信号量,互斥量,事件

RT-THREAD 内核快速入门(四)邮箱,消息队列,信号

RT-THREAD 内核快速入门(五)内存管理与中断管理

基于STM32Cubemx移植Rt-thread-nano
这是这个系列的第二篇,快速入门定时器篇,使用RT-THREAD创建定时器。


节拍

节拍,是RTOS的心脏,是记录系统运行的最小时长的单位,在中断里面进行周期更新,与时间有关的操作都涉及节拍。比如上一篇中的系统运行时间片,怎么记录运行时间,就需要节拍作为基准。系统休眠时间rt_thread_mdelay();这个函数休眠时长也是需要节拍作为基准的。

中断的周期就是节拍,时钟节拍的长度可以根据 RT_TICK_PER_SECOND 的定义来调整,等于 1/RT_TICK_PER_SECOND 秒。

系统调度也是根据节拍进行的,一般来说系统节拍越快,实时响应越快。

一、定时器

定时器的作用是计时一段时间,然后通知去做某件事。RT-THREAD,一般分为硬件定时器与软件定时器。下面对这两者的异同做一个简单的概述。

相同:

作用都一样,定时通知,分为周期性和一次性定时器。周期性定时器就是每隔一段时间通知一次,一次性定时器就是仅通知一次。

定时器的周期都是时钟节拍OS Tick的整数倍,因为时钟节拍计算时间是OS Tick +1 的方式进行计时的。

区别:
软硬件定时器的区别主要在于,定时器运行的方式不一样。硬件定时器的超时函数运行在中断里面(更新节拍时的中断区),不能被线程打断。软件定时器是创建一个线程,超时函数运行在线程里面,该线程具有线程的属性,优先级,栈大小等,不过没有时间片的概念。

运行过程:
在系统时钟中断里面进行时钟节拍OS Tick +1 并进行定时器是否超时判断,超时就执行超时函数。硬件超时的超时函数在系统时钟中断里面执行,而软件超时的超时函数创建的线程里面进行,会对线程进行激活,在线程里面运行超时函数。

二、创建定时器

这个例程会创建两个动态定时器,一个是单次定时,一个是周期性定时。动态的静态的区别就是静态的内存是编译的时候确定的,动态是运行的时候通过malloc函数进行分配的,使用起来是一样的。

这里对RT官方的例程稍作修改


/*
* 程序清单:定时器例程
*
* 这个例程会创建两个动态定时器,一个是单次定时,一个是周期性定时
* 并让周期定时器运行一段时间后停止运行,同时理解与线程的区别
*/
#include <rtthread.h>

/* 定时器的控制块 */
static rt_timer_t timer1;
static rt_timer_t timer2;
static	  int cnt2=0;

/* 定时器1超时函数 */
static void timeout1(void *parameter)
{
	  int cnt1=0;
    rt_kprintf("periodic timer is timeout cnt1  %d\n", cnt1);
	  rt_kprintf("periodic timer is timeout cnt2  %d\n", cnt2);
		cnt1++;
		cnt2++;
    /* 运行第10次,停止周期定时器 */
    if (cnt1++ >= 3 ||cnt2>3)
    {
        rt_timer_stop(timer1);
        rt_kprintf("periodic timer was stopped! \n");
    }
}

/* 定时器2超时函数 */
static void timeout2(void *parameter)
{
    rt_kprintf("one shot timer is timeout\n");
}

int timer_sample(void)
{
    /* 创建定时器1  周期定时器 */
    timer1 = rt_timer_create("timer1", timeout1,
                             RT_NULL, 10,
                             RT_TIMER_FLAG_PERIODIC);

    /* 启动定时器1 */
    if (timer1 != RT_NULL) rt_timer_start(timer1);

    /* 创建定时器2 单次定时器 */
    timer2 = rt_timer_create("timer2", timeout2,
                             RT_NULL,  30,
                             RT_TIMER_FLAG_ONE_SHOT);

    /* 启动定时器2 */
    if (timer2 != RT_NULL) rt_timer_start(timer2);
    return 0;
}

/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(timer_sample, timer sample);


运行结果
在这里插入图片描述

例程分析

通过上面的结果发现,这个中断运行退出的时候,是不会将变量和函数的出入口等方式压入栈中,也就是不能保存,定时器超时函数运行方式和函数的运行方式是一样的。

总结

  • 定时器的超时函数的运行方式和函数是一样的
  • 软定时器的超时函数在线程中运行,硬件定时器的超时函数运行是在中断里面运行,因此硬件定时的超时函数应该尽可能短。
  • 定时的周期是OS Tick的整数倍(线程系统时间片也是如此)

版权声明:本文为CSDN博主「Silent Knight」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_46185705/article/details/122855936

生成海报
点赞 0

Silent Knight

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

串口不定长接收

一、保留接收区和开启接收的语句    uint8_t buffer[5];HAL_UART_Transmit_IT(&huart1,buffer,3); 二、写入开启空闲中断的语句    __HAL_UART_ENABLE_IT(&huart