RT-Thread callback 介绍与示例


RT-Thread callback 介绍与示例

在这里插入图片描述

在这里插入图片描述


定义

  • 用来定义某些情况发生了,系统该做的事情
  • 在RT-Thread中,回调函数(callback)是一种非常重要的机制,它允许用户定义某些事件发生时应该执行的函数。这在编程中非常常见,特别是在嵌入式系统、操作系统或任何事件驱动的程序中。
  • 回调通常用于中断处理、定时器、线程或任何异步事件处理中。在RT-Thread中,回调的使用非常广泛,从定时器回调到设备驱动回调等都有应用。

类型

  • 从执行上看:
    • 可分为 中断回调 和 系统调度回调
    • 中断回调(直接在ISR中调用的回调):如果一个回调函数是作为中断服务例程(ISR)的一部分直接调用的,那么这个回调函数确实是在中断发生时立即执行的。在这种情况下,中断触发意味着CPU会立即跳转到ISR执行,ISR中的代码(包括调用的回调函数)会在其他常规任务或线程之前执行。在这种情况下,回调的执行是快速的,但应该注意回调函数需要保持简短和高效,以避免影响系统的响应时间和性能。
    • 系统调度的回调(如基于信号量或事件队列):在另一种情况下,中断可能只是设置一个标志、发送一个信号量或将消息放入队列,而实际的回调函数执行则是在中断上下文之外进行的。例如,一个线程可能在等待这个信号量或读取这个消息队列,并在接收到之后执行一个“回调”函数。在这种模式下,回调函数的执行不是立即发生的,而是取决于操作系统的调度和线程的优先级。这种方式通常用于处理较复杂的逻辑,以避免在ISR中进行耗时操作。

  • 从触发方式上看:
    • 可分为中断触发和定时器触发
    • 在中断处理中,回调函数通常用于在特定的硬件事件(如按钮按下、传感器触发等)发生时执行预定义的任务。这些回调函数通常在中断服务例程(ISR)中直接调用,以快速响应硬件事件。
    • 定时器回调允许开发者定义一段代码,在定时器超时时自动执行。这对于需要定期执行的任务特别有用,如周期性检查、更新UI、读取传感器值等。

示例

定时器触发

- 以下是一个简单的示例,演示如何在RT-Thread中创建一个定时器并设置一个回调函数。
- 在这个示例中,定时器每秒钟触发一次,每次触发时调用一个用户定义的函数来打印一条消息。
---
- rt_timer_create:函数用于创建一个新的定时器实例。它的参数包括定时器名称、回调函数、回调函数参数、定时器超时时间以及定时器模式(在这里是周期性的)。
- timer_callback:是定时器的回调函数。每当定时器超时时,这个函数就会被调用。在这个示例中,它仅仅打印出"Timer tick"- rt_timer_start:函数用于启动定时器。一旦启动,定时器将在设定的周期后触发,并调用其回调函数。
---
- 演示了回调函数在RT-Thread中的典型用法。你可以通过修改回调函数和定时器参数来适应不同的应用场景。
- 例如,你可以使用定时器回调来检查设备状态、更新系统测量值或者执行其他周期性任务。
#include <rtthread.h>

// 定义定时器句柄
static rt_timer_t timer;

// 定时器回调函数
static void timer_callback(void *parameter)
{
    rt_kprintf("Timer tick\n");
}

// 初始化并启动定时器
static int rt_application_init(void)
{
    // 创建定时器
    timer = rt_timer_create("ticker",          // 定时器名称
                            timer_callback,   // 定时器回调函数
                            RT_NULL,          // 传给回调函数的参数
                            RT_TICK_PER_SECOND, // 定时器周期,这里设置为1秒
                            RT_TIMER_FLAG_PERIODIC); // 定时器模式,周期性执行

    // 判断定时器是否创建成功
    if (timer != RT_NULL)
    {
        // 启动定时器
        rt_timer_start(timer);
    }

    return 0;
}
// 自动初始化
INIT_APP_EXPORT(rt_application_init);

int main(void)
{
    while(1){
        rt_hw_us_delay(100);
    }


    return 0;
}

中断触发

- 在RT-Thread中,回调函数通常用于处理中断服务例程(ISR)或者当特定事件发生时执行预定义的操作。
- 一个回调函数基本上是一个函数指针,它指向要执行的函数。当事件发生时,这个指向的函数就会被调用。
---
- 配置GPIO为外部中断模式。
- 创建一个中断回调函数。
- 在主函数中初始化GPIO中断并使能中断。
---
- GET_PIN(A, 0) 宏用于获取引脚编号,这取决于你使用的具体硬件平台和RT-Thread的板级支持包配置。
- rt_pin_mode 函数设置指定的GPIO引脚为输入模式,并启用内部上拉电阻。
- rt_pin_attach_irq 函数将一个回调函数绑定到指定的GPIO引脚上,以便当引脚检测到下降沿信号时,回调函数会被调用。
- rt_pin_irq_enable 函数使能指定引脚的中断功能。
#include <rtthread.h>
#include <rtdevice.h>
#include <drv_common.h>

// 假设中断引脚为PIN_NUM,具体值需要根据您的硬件确定
#define PIN_NUM GET_PIN(C, 13)

// 中断触发的回调函数
void irq_callback(void *args)
{
    rt_kprintf("Interrupt triggered!\n");
    // 这里可以添加更多的处理逻辑
}

int main(void)
{
    // 初始化指定的引脚为输入模式
    rt_pin_mode(PIN_NUM, PIN_MODE_INPUT_PULLUP); // 或者PIN_MODE_INPUT_PULLDOWN

    // 绑定中断回调函数,设置为边缘触发,这里以下降沿为例
    rt_pin_attach_irq(PIN_NUM, PIN_IRQ_MODE_FALLING, irq_callback, RT_NULL);

    // 使能中断
    rt_pin_irq_enable(PIN_NUM, PIN_IRQ_ENABLE);

    return 0;
}

中断回调

- rt_pin_mode 设置了引脚的模式(这里是上拉输入),
- rt_pin_attach_irq 绑定了一个回调函数 
- irq_callback 到指定的引脚上,以便当引脚检测到下降沿(即从高电平变为低电平)时,回调函数会被自动调用。最后,
- rt_pin_irq_enable 启用了引脚上的中断。
#include <rtthread.h>
#include <rtdevice.h>
#include <drv_common.h>


// 假设中断引脚为PIN_NUM,具体值需要根据您的硬件确定
#define PIN_NUM GET_PIN(C, 13)

// 中断触发的回调函数
void irq_callback(void *args)
{
    rt_kprintf("Interrupt triggered!\n");
    // 这里可以添加更多的处理逻辑
}

int main(void)
{
    // 初始化指定的引脚为输入模式
    rt_pin_mode(PIN_NUM, PIN_MODE_INPUT_PULLUP); // 或者PIN_MODE_INPUT_PULLDOWN

    // 绑定中断回调函数,设置为边缘触发,这里以下降沿为例
    rt_pin_attach_irq(PIN_NUM, PIN_IRQ_MODE_FALLING, irq_callback, RT_NULL);

    // 使能中断
    rt_pin_irq_enable(PIN_NUM, PIN_IRQ_ENABLE);

    return 0;
}

系统调度回调

- 在这个示例中,scheduler_hook 函数就是我们定义的任务切换钩子函数。每当系统准备从一个任务切换到另一个任务时,都会调用这个函数。
- 通过这个钩子,我们可以监控任务切换的情况,例如,可以用来测量任务切换的频率或调试多任务程序的行为。
- 请注意,过多地在钩子函数中执行操作(尤其是复杂或耗时的操作)可能会影响系统的性能和响应时间。
- 通常,钩子函数应该尽可能地保持简单和高效。
#include <rtthread.h>
#include <rtdevice.h>
#include <drv_common.h>



// 任务切换钩子函数
void scheduler_hook(rt_thread_t from, rt_thread_t to)
{
    // 输出当前切换的任务信息
    rt_kprintf("Switching from thread %s to thread %s\n", from->name, to->name);
}

int main(void)
{
    // 设置任务切换钩子
    rt_scheduler_sethook(scheduler_hook);

    // 下面可以初始化其他应用程序组件和启动任务

    return 0;
}

  • 基础知识部分到此就结束了接下来是一些开发中会用到的,在项目优化时需要注意到的,需要考虑的Tips;
  • 是一些相对进阶的内容,感兴趣的可以跳转进行查看
    在这里插入图片描述

Tips

  • 强调 回调执行操作时,关于中断回调和系统调度回调两种方式 在性能上的区别
  • 在以下连接中对此 进行了分析,并提供原码作为示例
  • 详情 请参考 RT-Thread callback - Tips

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值