Rust嵌入式时间队列驱动库embassy-time-queue-driver的使用,高效管理异步任务与定时事件

Rust嵌入式时间队列驱动库embassy-time-queue-driver的使用,高效管理异步任务与定时事件

embassy-time-queue-driver crate 包含了 embassy-time 定时器队列使用的驱动 trait。

通常情况下不需要直接使用这个 crate,只有在实现自定义定时器队列时才需要用到它。

目前有两个定时器队列实现:

  1. 在 embassy-time 中,通过 generic-queue 特性启用
  2. 在 embassy-executor 中,通过 integrated-timers 特性启用

示例代码

use embassy_time_queue_driver::{TimerQueueDriver, TimerQueueInstant};

// 自定义定时器队列驱动实现示例
struct MyTimerDriver;

impl TimerQueueDriver for MyTimerDriver {
    type Instant = MyInstant;
    type Ticks = u64;
    
    fn now(&self) -> Self::Instant {
        // 实现获取当前时间
        MyInstant(0)
    }
    
    fn ticks_from_nanos(&self, nanos: u64) -> Self::Ticks {
        // 实现纳秒转ticks
        nanos / 1000
    }
    
    fn set_alarm(&self, _timestamp: Self::Instant, _ticks: Self::Ticks) {
        // 实现设置闹钟
    }
    
    fn disable_alarm(&self) {
        // 实现禁用闹钟
    }
}

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
struct MyInstant(u64);

impl TimerQueueInstant for MyInstant {
    fn checked_add(self, duration: embassy_time::Duration) -> Option<Self> {
        self.0.checked_add(duration.as_nanos() as u64).map(MyInstant)
    }
    
    fn checked_sub(self, duration: embassy_time::Duration) -> Option<Self> {
        self.0.checked_sub(duration.as_nanos() as u64).map(MyInstant)
    }
}

// 使用示例
#[embassy_executor::main]
async fn main(_spawner: embassy_executor::Spawner) {
    let driver = MyTimerDriver;
    
    // 创建定时器队列
    let queue = embassy_time::TimerQueue::new(driver);
    
    // 设置定时任务
    queue.set_timeout(embassy_time::Duration::from_secs(1), || {
        println!("1秒后执行");
    });
}

完整示例demo

以下是一个更完整的示例,展示了如何使用embassy-time-queue-driver创建一个简单的定时任务系统:

use embassy_time::{Duration, TimerQueue};
use embassy_time_queue_driver::{TimerQueueDriver, TimerQueueInstant};
use embassy_executor::Spawner;

// 自定义时间点类型
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
struct MyInstant(u64);

impl TimerQueueInstant for MyInstant {
    fn checked_add(self, duration: Duration) -> Option<Self> {
        self.0.checked_add(duration.as_nanos() as u64).map(MyInstant)
    }
    
    fn checked_sub(self, duration: Duration) -> Option<Self> {
        self.0.checked_sub(duration.as_nanos() as u64).map(MyInstant)
    }
}

// 自定义定时器驱动实现
struct MyTimerDriver {
    current_time: core::sync::atomic::AtomicU64,
}

impl TimerQueueDriver for MyTimerDriver {
    type Instant = MyInstant;
    type Ticks = u64;
    
    fn now(&self) -> Self::Instant {
        MyInstant(self.current_time.load(core::sync::atomic::Ordering::Relaxed))
    }
    
    fn ticks_from_nanos(&self, nanos: u64) -> Self::Ticks {
        nanos / 1000  // 将纳秒转换为微秒
    }
    
    fn set_alarm(&self, timestamp: Self::Instant, ticks: Self::Ticks) {
        println!("设置闹钟在 {} ticks 后触发 ({} 绝对时间)", ticks, timestamp.0);
    }
    
    fn disable_alarm(&self) {
        println!("禁用闹钟");
    }
}

#[embassy_executor::main]
async fn main(spawner: Spawner) {
    // 创建定时器驱动实例
    let driver = MyTimerDriver {
        current_time: core::sync::atomic::AtomicU64::new(0),
    };
    
    // 创建定时器队列
    let queue = TimerQueue::new(driver);
    
    // 设置多个定时任务
    queue.set_timeout(Duration::from_secs(1), || {
        println!("任务1: 1秒后执行");
    });
    
    queue.set_timeout(Duration::from_secs(3), || {
        println!("任务2: 3秒后执行");
    });
    
    queue.set_timeout(Duration::from_millis(500), || {
        println!("任务3: 500毫秒后执行");
    });
    
    // 模拟时间流逝
    for i in 1..=5 {
        println!("当前时间: {}秒", i);
        // 更新时间
        driver.current_time.store(i * 1_000_000_000, core::sync::atomic::Ordering::Relaxed);
        // 检查定时任务
        queue.check_alarms();
        embassy_time::Timer::after(Duration::from_secs(1)).await;
    }
}

安装

在项目目录中运行以下Cargo命令:

cargo add embassy-time-queue-driver

或者在Cargo.toml中添加:

embassy-time-queue-driver = "0.1.0"

许可证

MIT OR Apache-2.0


1 回复

embassy-time-queue-driver: Rust嵌入式时间队列驱动库

介绍

embassy-time-queue-driver 是 Embassy 嵌入式框架中的一个时间队列驱动库,专门为嵌入式系统设计,用于高效管理异步任务和定时事件。它提供了轻量级的时间管理功能,特别适合在资源受限的嵌入式环境中使用。

主要特性

  • 轻量级实现,适合资源受限的嵌入式环境
  • 精确的时间管理功能
  • 支持异步任务调度
  • 与 Embassy 异步运行时无缝集成
  • 低功耗设计,适用于电池供电设备

使用方法

添加依赖

首先,在 Cargo.toml 中添加依赖:

[dependencies]
embassy-time-queue-driver = "0.1"
embassy-executor = "0.1"
embassy-time = { version = "0.1", features = ["time-driver"] }

基本示例

use embassy_time::{Duration, Timer};
use embassy_executor::Spawner;

#[embassy_executor::main]
async fn main(_spawner: Spawner) {
    // 简单的延时示例
    Timer::after(Duration::from_millis(500)).await;
    println!("500ms elapsed");
    
    // 周期性任务
    loop {
        Timer::after(Duration::from_secs(1)).await;
        println!("1 second elapsed");
    }
}

定时任务管理

use embassy_time::{Duration, Timer};
use embassy_executor::Spawner;

#[embassy_executor::task]
async fn periodic_task(interval: Duration) {
    loop {
        // 执行周期性工作
        println!("Periodic task executed");
        Timer::after(interval).await;
    }
}

#[embassy_executor::main]
async fn main(spawner: Spawner) {
    // 启动周期性任务,每2秒执行一次
    spawner.spawn(periodic_task(Duration::from_secs(2))).unwrap();
    
    // 主任务可以做其他工作
    loop {
        Timer::after(Duration::from_secs(5)).await;
        println!("Main task check-in");
    }
}

超时处理

use embassy_time::{Duration, Timer, TimeoutError};

async fn do_something_with_timeout() -> Result<(), TimeoutError> {
    // 模拟一个可能超时的操作
    Timer::after(Duration::from_millis(100)).await;
    Ok(())
}

#[embassy_executor::main]
async fn main(_spawner: Spawner) {
    // 设置500ms超时
    match embassy_time::with_timeout(Duration::from_millis(500), do_something_with_timeout()).await {
        Ok(_) => println!("Operation completed successfully"),
        Err(TimeoutError) => println!("Operation timed out"),
    }
}

硬件定时器集成

use embassy_time::driver::{Driver, AlarmHandle};
use embassy_time::{Duration, Instant};

struct MyDriver;

impl Driver for MyDriver {
    fn now(&self) -> u64 {
        // 实现获取当前时间的逻辑
        // 通常从硬件定时器读取
        0
    }
    
    unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
        // 分配警报句柄
        Some(AlarmHandle::new(0))
    }
    
    fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) {
        // 设置硬件定时器在指定时间触发
    }
}

#[embassy_executor::main]
async fn main(_spawner: Spawner) {
    let driver = MyDriver;
    embassy_time_driver::impl_driver_global!(driver);
    
    // 现在可以使用embassy_time的各种功能
    Timer::after(Duration::from_millis(100)).await;
}

完整示例:嵌入式系统多任务定时器

下面是一个完整的嵌入式应用示例,展示如何使用embassy-time-queue-driver管理多个定时任务:

use embassy_executor::Spawner;
use embassy_time::{Duration, Timer};
use core::fmt::Write;
use heapless::String;

// 定义两个异步任务
#[embassy_executor::task]
async fn task_led_controller(interval: Duration) {
    loop {
        // 模拟LED切换
        println!("LED state toggled");
        Timer::after(interval).await;
    }
}

#[embassy_executor::task]
async fn task_sensor_reader(interval: Duration) {
    let mut count = 0;
    loop {
        // 模拟传感器读数
        let mut buf: String<32> = String::new();
        write!(&mut buf, "Sensor reading #{}: {}", count, 42).unwrap();
        println!("{}", buf);
        
        count += 1;
        Timer::after(interval).await;
    }
}

#[embassy_executor::main]
async fn main(spawner: Spawner) {
    println!("Starting embedded application with embassy-time-queue-driver");
    
    // 启动LED控制任务,每秒执行一次
    spawner.spawn(task_led_controller(Duration::from_secs(1))).unwrap();
    
    // 启动传感器读取任务,每2秒执行一次
    spawner.spawn(task_sensor_reader(Duration::from_secs(2))).unwrap();
    
    // 主任务打印系统状态
    let mut system_uptime = 0;
    loop {
        println!("System uptime: {} seconds", system_uptime);
        system_uptime += 5;
        Timer::after(Duration::from_secs(5)).await;
    }
}

最佳实践

  1. 合理设置时间精度:根据应用需求选择合适的时间精度,过高的精度会增加功耗。

  2. 避免长时间阻塞:在异步任务中避免长时间阻塞操作,以免影响其他定时任务的执行。

  3. 错误处理:总是处理可能的超时错误,特别是在网络或外设操作中。

  4. 低功耗设计:在电池供电设备中,合理使用Timer可以让处理器在等待期间进入低功耗模式。

embassy-time-queue-driver 为嵌入式Rust开发提供了强大而高效的时间管理功能,特别适合需要精确时间控制和低功耗设计的应用场景。

回到顶部