2 个不稳定版本
0.3.0 | 2024年7月11日 |
---|---|
0.2.0 | 2024年2月16日 |
225 在 嵌入式开发
在 coap-zero 中使用
53KB
520 行
embedded-timers
此crate为no_std
环境中的单调非递减时钟提供了一个通用基础。它定义了Clock
和Instant
特质作为接口,并根据这些特质实现定时器和延迟。
通过将Clock
特质作为依赖项,设备驱动程序和应用可以以平台无关的方式开发。因此,此crate对于时钟的作用与embedded-hal
或embedded-nal
crate对于外围或网络抽象的作用相同。
此crate仅关注单调非递减时钟,即与std::time::Instant
类型具有相同目的的时钟。它们可以用于测量瞬间之间的持续时间、创建计时器/超时或仅仅等待/延迟程序执行。此crate不涉及时间库可能包含的任何其他内容:此crate不涉及系统时间或墙上的时钟时间,这些时间可能在时钟同步时跳跃。此外,此crate不涵盖时区处理或日历。
设计决策
为了在no_std
环境中创建处理时钟的通用接口,此crate旨在做出许多用例和许多用户可接受的决策。在这方面,它试图尽可能简单(枯燥),并避免过于主观或可辩论的决策。例如
- 使用已定义在
core
中的任何内容。具体来说,虽然其12字节内存布局似乎对于许多嵌入式应用来说有点过度,但core::time::Duration
类型用于持续时间。但它涵盖了从高精度到多年定时等所有用例,并在社区中得到一致同意。 - 《Clock》和《Instant》特性受《std::time::Instant》的启发,这对于Rust开发者来说应该很熟悉。但与《std::time::Instant》不同,没有假设全球时钟可用。因此,功能被分为两个不同的特性。
使用方法
大多数用户(应用程序、库或设备驱动程序开发者)将依赖于《Clock》特性。然后,可以使用时钟进行计时器或延迟,而不必关心底层的《Instant》类型。
fn application(clock: &impl embedded_timers::clock::Clock) {
// Get the current instant, the instant type is inferred from the generic Clock
let earlier = clock.now();
let later = clock.now();
// The instant type is guaranteed to support calculations due to the Instant trait
let time_passed: core::time::Duration = later - earlier;
// Timers and delays can easily be written manually
let deadline = clock.now() + core::time::Duration::from_secs(1); // 1 second timer/delay
loop {
// By comparing clock.now() with the deadline, we determine if the timer has expired.
// When doing nothing in the loop, this is a simple busy wait delay.
if clock.now() > deadline {
break;
}
}
// Alternatively, the provided helper types for timer and delay can be used
let mut timer = embedded_timers::timer::Timer::new(clock);
timer.try_start(core::time::Duration::from_secs(1)).unwrap();
let is_expired = timer.is_expired().unwrap();
}
在平台级别,需要为时钟类型实现《Clock》特性。《Instant》相关类型需要实现《Instant》特性。如果启用了《std》特性,则《std::time::Instant》实现《Instant》特性,并且可以用于一个非常简单的时钟。
struct StdClock;
impl embedded_timers::clock::Clock for StdClock {
type Instant = std::time::Instant;
fn now(&self) -> Self::Instant {
std::time::Instant::now()
}
}
在实际的《no_std》环境中,需要手动实现时钟。对于相关的《Instant》类型,它可能使用在instant
模块中定义的类型之一。它需要设置适当的中断处理程序,并同步对滴答变量的访问。这可能看起来像这样:
// Global tick counter variable which is incremented in the tick interrupt handler. By using an
// atomic variable, we can do this without unsafe code. Note that using a 32 bit counter for
// milliseconds will wrap around after around 50 days so this might not be feasible in a real
// scenario.
static TICKS: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0);
// This tick interrupt handler is assumed to be called once per millisecond
fn tick_handler() {
TICKS.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
}
struct MilliSecondClock32;
impl embedded_timers::clock::Clock for MilliSecondClock32 {
type Instant = embedded_timers::instant::Instant32<1000>;
fn now(&self) -> Self::Instant {
let ticks = TICKS.load(core::sync::atomic::Ordering::Relaxed);
embedded_timers::instant::Instant32::<1000>::new(ticks)
}
}
延迟
从时钟中可以创建延迟。这将执行忙等待延迟。
use embedded_timers::clock::Clock;
use embedded_hal::blocking::delay::DelayMs;
#[derive(Debug)]
pub struct MilliSecondClock;
let clock = MilliSecondClock;
let mut delay = embedded_timers::delay::Delay::new(&clock);
loop {
println!("This shows every second");
delay.delay_ms(1000_u32);
}
计时器
该库提供了一个方便的计时器接口,具有检查计时器是否《is_running》或《is_expired》以及《duration_left》剩余时间的功能。
use embedded_timers::clock::Clock;
use embedded_timers::timer::Timer;
use embedded_hal::timer::CountDown;
#[derive(Debug)]
pub struct MilliSecondClock;
let clock = MilliSecondClock;
let mut timer = embedded_timers::timer::Timer::new(&clock);
timer.start(core::time::Duration::from_secs(1));
loop {
if let Ok(expired) = timer.is_expired() {
if expired {
println!("This shows every second");
timer.start(core::time::Duration::from_secs(1));
}
}
}
《embedded_timers::Timer》还实现了《embedded_hal::timer::CountDown》,因为这通常是嵌入式计时器的通用接口。
use embedded_timers::clock::Clock;
use embedded_timers::timer::Timer;
use embedded_hal::timer::CountDown;
use embedded_hal::blocking::delay::DelayMs;
#[derive(Debug)]
pub struct MilliSecondClock;
let clock = MilliSecondClock;
let mut timer = embedded_timers::timer::Timer::new(&clock);
let mut delay = embedded_timers::delay::Delay::new(&clock);
timer.start(core::time::Duration::from_secs(1));
loop {
match timer.wait() {
Err(nb::Error::WouldBlock) => {
println!("Timer still running");
delay.delay_ms(50_u32);
}
Err(_) => panic!("TIMER ERROR"),
Ok(_) => {
println!("This shows every second");
timer.start(core::time::Duration::from_secs(1));
}
}
}
许可证
开放物流基金会许可证
版本 1.3,2023 年 1 月
请参阅顶级目录中的《LICENSE》文件。
联系方式
弗劳恩霍费尔 IML 嵌入式 Rust 团队 - [email protected]
依赖项
~71KB