采集与获取
用于读取传感器数据和处理触发器的稳定且长期使用的 API 如下:
这些函数协同工作。采集 API 会阻塞调用上下文(必须是线程),直到请求的 sensor_channel (或所有通道)的数据已采集并存储到驱动实例的私有数据中。
随后,可针对每种通道类型调用 sensor_channel_get() ,以 sensor_value 的形式获取最近一次采集的通道数据。
警告
需要注意,在没有锁定机制的情况下,从多个上下文调用采集和获取函数的行为是未定义的,而且大多数传感器驱动不会在内部确保在这些调用期间或调用之间对设备的独占访问。
轮询
通过采集和获取函数,软件线程可以以轮询方式读取传感器数据。
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/sys/printk.h>
#include <stdio.h>
int main(void)
{
const struct device *const dev = DEVICE_DT_GET(DT_ALIAS(magn0));
struct sensor_value value_x, value_y, value_z;
int ret;
if (!device_is_ready(dev)) {
printk("sensor: device not ready.\n");
return 0;
}
printk("Polling magnetometer data from %s.\n", dev->name);
while (1) {
ret = sensor_sample_fetch(dev);
if (ret) {
printk("sensor_sample_fetch failed ret %d\n", ret);
return 0;
}
ret = sensor_channel_get(dev, SENSOR_CHAN_MAGN_X, &value_x);
ret = sensor_channel_get(dev, SENSOR_CHAN_MAGN_Y, &value_y);
ret = sensor_channel_get(dev, SENSOR_CHAN_MAGN_Z, &value_z);
printf("( x y z ) = ( %f %f %f )\n",
sensor_value_to_double(&value_x),
sensor_value_to_double(&value_y),
sensor_value_to_double(&value_z));
k_sleep(K_MSEC(500));
}
return 0;
}
触发器
使用稳定 API 中的触发器,需要通过设备专用的 Kconfig 选项启用触发器。这些 Kconfig 选项通常允许选择触发器运行的上下文。随后,应用需要使用 sensor_trigger_set() ,为要监听的特定触发器(事件)注册一个函数签名与 sensor_trigger_handler_t 匹配的回调函数。
备注
不能从用户模式线程设置触发器,且回调函数不会在用户模式上下文中运行。
每个驱动通常提供两种运行触发器处理函数的方式:使用系统工作队列线程( 工作队列线程 )或专用线程。BMI160 驱动就是一个很好的例子,它提供了用于选择触发器模式的 Kconfig 选项。请参阅 CONFIG_BMI160_TRIGGER_NONE 、 CONFIG_BMI160_TRIGGER_GLOBAL_THREAD (工作队列)和 CONFIG_BMI160_TRIGGER_OWN_THREAD (专用线程)。
与系统工作队列相比,使用驱动专用线程有以下几个值得注意的特点。
驱动专用线程具有专用栈(RAM),该栈仅供对应的单个触发器处理函数使用。
驱动专用线程通常 确实 具有独立的优先级,因此可以设置触发器处理相对于其他线程的优先级。
使用驱动专用线程时,即使驱动处理触发器需要一定时间,也不会造成队头阻塞。
备注
在所有情况下,从实际中断发生到回调函数运行之间,很可能存在不固定的延迟。使用工作队列(GLOBAL_THREAD)时,工作队列本身就可能是不固定延迟的来源!
/*
* Copyright (c) 2024 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/drivers/sensor.h>
const struct device *const accel0 = DEVICE_DT_GET(DT_ALIAS(accel0));
static struct tap_count_state {
struct sensor_trigger trig;
uint32_t count;
} tap_count_state = {
.trig = {
.chan = SENSOR_CHAN_ACCEL_XYZ,
.type = SENSOR_TRIG_TAP,
},
.count = 0,
};
void tap_handler(const struct device *dev, const struct sensor_trigger *trig)
{
struct tap_count_state *state = CONTAINER_OF(trig, struct tap_count_state, trig);
state->count++;
printk("Tap! Total Taps: %u\n", state->count);
}
int main(void)
{
int rc;
printk("Tap Counter Example (%s)\n", CONFIG_ARCH);
rc = sensor_trigger_set(accel0, &tap_count_state.trig, tap_handler);
if (rc != 0) {
printk("Failed to set trigger handler for taps, error %d\n", rc);
return rc;
}
return rc;
}