本笔记学习 Zephyr 的 Counter/Timer 驱动,用于定时器中断和闹钟功能。
zephyr/samples/drivers/counter/alarm/
在 Zephyr 中:
具体由哪个底层定时外设实现 Counter,要看当前 SoC 和设备树配置。
#include <zephyr/drivers/counter.h>
#define TIMER DT_CHOSEN(counter) // 设备树选择的 counter
const struct device *const counter_dev = DEVICE_DT_GET(TIMER);
if (!device_is_ready(counter_dev)) {
printk("Counter device is not ready\n");
return;
}
int counter_start(const struct device *dev);
uint32_t now_ticks;
int err = counter_get_value(counter_dev, &now_ticks);
bool counter_is_counting_up(const struct device *dev);
uint32_t top_value = counter_get_top_value(counter_dev);
struct counter_alarm_cfg {
counter_alarm_callback_t callback; // 回调函数
void *user_data; // 用户数据
uint32_t ticks; // 闹钟触发计数值
uint32_t flags; // 标志位
};
#define ALARM_CHANNEL_ID 0
struct counter_alarm_cfg alarm_cfg;
alarm_cfg.ticks = counter_us_to_ticks(counter_dev, 2000000); // 2秒
alarm_cfg.callback = alarm_callback;
alarm_cfg.user_data = &alarm_cfg;
alarm_cfg.flags = 0;
int err = counter_set_channel_alarm(counter_dev, ALARM_CHANNEL_ID, &alarm_cfg);
void alarm_callback(const struct device *counter_dev,
uint8_t chan_id,
uint32_t ticks,
void *user_data)
{
struct counter_alarm_cfg *cfg = (struct counter_alarm_cfg *)user_data;
printk("!!! Alarm !!!\n");
// 设置下一个闹钟(双倍时间)
cfg->ticks = cfg->ticks * 2;
counter_set_channel_alarm(counter_dev, ALARM_CHANNEL_ID, cfg);
}
if (-EINVAL == err) {
printk("Alarm settings invalid\n");
} else if (-ENOTSUP == err) {
printk("Alarm setting request not supported\n");
} else if (err != 0) {
printk("Error\n");
}
uint32_t ticks = counter_us_to_ticks(counter_dev, delay_us);
uint64_t us = counter_ticks_to_us(counter_dev, ticks);
int sec = (int)(us / USEC_PER_SEC);
#include <zephyr/kernel.h>
#include <zephyr/drivers/counter.h>
#include <zephyr/sys/printk.h>
#define DELAY 2000000 // 2秒
static void alarm_callback(const struct device *counter_dev,
uint8_t chan_id, uint32_t ticks,
void *user_data)
{
struct counter_alarm_cfg *cfg = user_data;
uint32_t now_ticks;
counter_get_value(counter_dev, &now_ticks);
if (!counter_is_counting_up(counter_dev)) {
now_ticks = counter_get_top_value(counter_dev) - now_ticks;
}
printk("!!! Alarm !!!\n");
printk("Now: %u sec\n",
(uint32_t)(counter_ticks_to_us(counter_dev, now_ticks) / USEC_PER_SEC));
// 设置下一个闹钟
cfg->ticks *= 2;
counter_set_channel_alarm(counter_dev, 0, cfg);
}
int main(void)
{
const struct device *const counter_dev = DEVICE_DT_GET(TIMER);
struct counter_alarm_cfg alarm_cfg;
alarm_cfg.flags = 0;
alarm_cfg.ticks = counter_us_to_ticks(counter_dev, DELAY);
alarm_cfg.callback = alarm_callback;
alarm_cfg.user_data = &alarm_cfg;
counter_start(counter_dev);
counter_set_channel_alarm(counter_dev, 0, &alarm_cfg);
while (1) {
k_sleep(K_FOREVER);
}
return 0;
}
/ {
chosen {
counter = &timer0; // 或 rtc0
};
};
&timer0 {
status = "okay";
};
cd /home/wangpei/ncs-sdk
west build -p -b nrf54l15dk/nrf54l15/cpuapp zephyr/samples/drivers/counter/alarm
west flash
Counter alarm sample
Set alarm in 2 sec (xxxxx ticks)
!!! Alarm !!!
Now: 2
Set alarm in 4 sec (xxxxx ticks)
!!! Alarm !!!
Now: 6
Set alarm in 8 sec (xxxxx ticks)
...
counter_get_num_of_channels() 确认支持的闹钟通道数counter_is_counting_up()*小白 🤖 - 2026-03-16*