传感器驱动模型,对传感器的操作操作提供了一个统一的操作api,这些统一的api可以让我们做如下两个事情:

  • 从传感器读取值
  • 根据设置的传感器阈值,执行某些事情

简介

Zephyrinclude/drivers/sensor.h中定义了统一的传感器驱动接口,由sensor_sample_fetch从指定传感器读取数据到内存,由sensor_channel_get来获取指fetch的数据。对于传感器阈值通知的情况,Zephyr也提供了sensor_trigger_set,注册callback函数,在传感器打到阈值时被执行。
由于不同的传感器测量物理特性值不一样,同一个传感器也会有不同物理特性测量值,zephyr 将不同的物理量抽象为channel,一个channel对应一个物理测量量。

接口API

设置属性值:

  1. //从传感器获取所有数据放到内存
  2. __syscall int sensor_sample_fetch(struct device *dev);
  3. //从传感器获取指定channel的数据到内存
  4. __syscall int sensor_sample_fetch_chan(struct device *dev,
  5. enum sensor_channel type);
  6. //从内存获取指定channel的数据
  7. __syscall int sensor_channel_get(struct device *dev,
  8. enum sensor_channel chan,
  9. struct sensor_value *val);
  10. //设定传感器指定channel的参数,例如采样频率,触发阈值等
  11. __syscall int sensor_attr_set(struct device *dev,
  12. enum sensor_channel chan,
  13. enum sensor_attribute attr,
  14. const struct sensor_value *val);
  15. //获取传感器指定channel的参数,例如采样频率,触发阈值等
  16. __syscall int sensor_attr_get(const struct device *dev,
  17. enum sensor_channel chan,
  18. enum sensor_attribute attr,
  19. const struct sensor_value *val);
  20. //设置传感器触发
  21. static inline int sensor_trigger_set(struct device *dev,
  22. struct sensor_trigger *trig,
  23. sensor_trigger_handler_t handler)

数据结构

channel结构

  1. enum sensor_channel {
  2. SENSOR_CHAN_ACCEL_X, //X轴加速度,m/s^2
  3. SENSOR_CHAN_ACCEL_Y, //y轴加速度,m/s^2
  4. SENSOR_CHAN_ACCEL_Z, //z轴加速度,m/s^2
  5. SENSOR_CHAN_ACCEL_XYZ, //任意加速度
  6. SENSOR_CHAN_ACCEL_ANY = SENSOR_CHAN_ACCEL_XYZ,
  7. SENSOR_CHAN_GYRO_X, //绕X轴角速度,radians/s
  8. SENSOR_CHAN_GYRO_Y, //绕y轴角速度,radians/s
  9. SENSOR_CHAN_GYRO_Z, //绕z轴角速度,radians/s
  10. SENSOR_CHAN_GYRO_XYZ, //任意角速度
  11. SENSOR_CHAN_GYRO_ANY = SENSOR_CHAN_GYRO_XYZ,
  12. SENSOR_CHAN_MAGN_X, //X轴地磁, Gauss
  13. SENSOR_CHAN_MAGN_Y, //y轴地磁, Gauss
  14. SENSOR_CHAN_MAGN_Z, //z轴地磁, Gauss
  15. SENSOR_CHAN_MAGN_XYZ, //任意轴地磁
  16. SENSOR_CHAN_MAGN_ANY = SENSOR_CHAN_MAGN_XYZ,
  17. SENSOR_CHAN_TEMP, //温度,摄氏度
  18. SENSOR_CHAN_DIE_TEMP, //器件温度,摄氏度
  19. SENSOR_CHAN_AMBIENT_TEMP, //环境温度,摄氏度
  20. SENSOR_CHAN_PRESS, //大气压, 千帕
  21. SENSOR_CHAN_PROX, //距离(靠近)传感器,1表示接近
  22. SENSOR_CHAN_HUMIDITY, //湿度, 百分比
  23. SENSOR_CHAN_LIGHT, //可见光强, lux
  24. SENSOR_CHAN_IR, //红外光强, lux
  25. SENSOR_CHAN_RED, //红色光强,lux
  26. SENSOR_CHAN_GREEN, //绿色光强,lux
  27. SENSOR_CHAN_BLUE, //蓝色光强,lux
  28. SENSOR_CHAN_ALTITUDE, //高度传感器, m
  29. SENSOR_CHAN_PM_1_0, //PM1.0传感器,ug/m^3
  30. SENSOR_CHAN_PM_2_5, //PM2.5传感器,ug/m^3
  31. SENSOR_CHAN_PM_10, //PM2.5传感器,ug/m^3
  32. SENSOR_CHAN_DISTANCE, //距离传感器,m
  33. SENSOR_CHAN_CO2, //CO2传感器, ppm
  34. SENSOR_CHAN_VOC, //VOC传感器, ppm
  35. SENSOR_CHAN_VOLTAGE, //电压, V
  36. SENSOR_CHAN_CURRENT, //电流, A
  37. SENSOR_CHAN_ALL,
  38. };

传感器数据格式

  1. struct sensor_value {
  2. s32_t val1; //整数
  3. s32_t val2; //小数
  4. };

转换方式:

  1. val = val1 + val2 * 10^(-6)

例如:

  1. 0.5: val1 = 0, val2 = 500000
  2. -0.5: val1 = 0, val2 = -500000
  3. -1.0: val1 = -1, val2 = 0
  4. -1.5: val1 = -1, val2 = -500000

传感器参数

  1. enum sensor_attribute {
  2. SENSOR_ATTR_SAMPLING_FREQUENCY, //传感器采样频率(具体含义由实际驱动实现决定,例如:一秒测量多少次)
  3. SENSOR_ATTR_LOWER_THRESH, //低触发阈值
  4. SENSOR_ATTR_UPPER_THRESH, //高触发阈值
  5. SENSOR_ATTR_SLOPE_TH, //斜率(任意运动)触发
  6. SENSOR_ATTR_SLOPE_DUR, //斜率维持超过一定时间触发
  7. SENSOR_ATTR_OVERSAMPLING, //过采样参数
  8. SENSOR_ATTR_FULL_SCALE, //传感器量程
  9. SENSOR_ATTR_OFFSET, //传感器值校正,sensor_channel_get返回的传感器值将被改值偏置final_value = sensor_value + offset
  10. SENSOR_ATTR_CALIB_TARGET, //传感器自身校正,用芯片内部的算法校正传感器的某个或者所有轴(传感器内部校正功能)
  11. };

传感器触发方式

对于有中断输出的传感器,通常有不同的触发方式或者在实现驱动中有thread驱动的传感器

  1. enum sensor_trigger_type {
  2. SENSOR_TRIG_TIMER, //定时触发
  3. SENSOR_TRIG_DATA_READY, //传感器数据准备好触发
  4. SENSOR_TRIG_DELTA, //通道量有连续变化时触发(需设置SENSOR_ATTR_SLOPE_TH和SENSOR_ATTR_SLOPE_DUR)
  5. SENSOR_TRIG_NEAR_FAR, //接近或者远离触发
  6. SENSOR_TRIG_THRESHOLD, //超过配置阈值触发(需设置SENSOR_ATTR_LOWER_THRESH和SENSOR_ATTR_UPPER_THRESH)
  7. SENSOR_TRIG_TAP, //单击触发
  8. SENSOR_TRIG_DOUBLE_TAP, //双击触发
  9. };

传感器的使用

主动获取传感器数据

  1. void main(void)
  2. {
  3. //获取传感器设备
  4. struct device *dev = device_get_binding("DHT11"); //根据Device name获取驱动
  5. printf("dev %p name %s\n", dev, dev->config->name);
  6. while (1) {
  7. //定义传感器数据
  8. struct sensor_value temp, humidity;
  9. //获取传感器数据
  10. sensor_sample_fetch(dev); //从dh11读取数据
  11. sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &temp); //读取温度
  12. sensor_channel_get(dev, SENSOR_CHAN_HUMIDITY, &humidity); //读取湿度
  13. printf("temp: %d.%06d; humidity: %d.%06d\n",
  14. temp.val1, temp.val2, humidity.val1, humidity.val2);
  15. k_sleep(1000);
  16. }
  17. }

Trigger获取传感器数据

  1. static void trigger_handler(struct device *dev, struct sensor_trigger *trig)
  2. {
  3. struct sensor_value temp;
  4. sensor_sample_fetch(dev);
  5. sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &temp);
  6. printf("trigger fired, temp %d.%06d\n", temp.val1, temp.val2);
  7. }
  8. void main(void)
  9. {
  10. struct device *dev = device_get_binding("MCP9808");
  11. if (dev == NULL) {
  12. printf("device not found. aborting test.\n");
  13. return;
  14. }
  15. struct sensor_value val;
  16. struct sensor_trigger trig;
  17. val.val1 = 26;
  18. val.val2 = 0;
  19. //设置26度为高阈值
  20. sensor_attr_set(dev, SENSOR_CHAN_AMBIENT_TEMP,
  21. SENSOR_ATTR_UPPER_THRESH, &val);
  22. trig.type = SENSOR_TRIG_THRESHOLD;
  23. trig.chan = SENSOR_CHAN_AMBIENT_TEMP;
  24. //当温度超过26度时触发,呼叫trigger_handler
  25. if (sensor_trigger_set(dev, &trig, trigger_handler)) {
  26. printf("Could not set trigger. aborting test.\n");
  27. return;
  28. }
  29. while (1) {
  30. k_sleep(2000);
  31. }
  32. }

传感器驱动实现

驱动API的模型

include/drivers/sensor.h中定义传感器的API模型:

  1. /**
  2. * @typedef sensor_trigger_handler_t
  3. * @brief Callback API upon firing of a trigger
  4. *
  5. * @param dev Pointer to the sensor device
  6. * @param trigger The trigger
  7. */
  8. typedef void (*sensor_trigger_handler_t)(const struct device *dev,
  9. struct sensor_trigger *trigger);
  10. /**
  11. * @typedef sensor_attr_set_t
  12. * @brief Callback API upon setting a sensor's attributes
  13. *
  14. * See sensor_attr_set() for argument description
  15. */
  16. typedef int (*sensor_attr_set_t)(const struct device *dev,
  17. enum sensor_channel chan,
  18. enum sensor_attribute attr,
  19. const struct sensor_value *val);
  20. /**
  21. * @typedef sensor_attr_get_t
  22. * @brief Callback API upon getting a sensor's attributes
  23. *
  24. * See sensor_attr_get() for argument description
  25. */
  26. typedef int (*sensor_attr_get_t)(const struct device *dev,
  27. enum sensor_channel chan,
  28. enum sensor_attribute attr,
  29. struct sensor_value *val);
  30. /**
  31. * @typedef sensor_trigger_set_t
  32. * @brief Callback API for setting a sensor's trigger and handler
  33. *
  34. * See sensor_trigger_set() for argument description
  35. */
  36. typedef int (*sensor_trigger_set_t)(const struct device *dev,
  37. const struct sensor_trigger *trig,
  38. sensor_trigger_handler_t handler);
  39. /**
  40. * @typedef sensor_sample_fetch_t
  41. * @brief Callback API for fetching data from a sensor
  42. *
  43. * See sensor_sample_fetch() for argument description
  44. */
  45. typedef int (*sensor_sample_fetch_t)(const struct device *dev,
  46. enum sensor_channel chan);
  47. /**
  48. * @typedef sensor_channel_get_t
  49. * @brief Callback API for getting a reading from a sensor
  50. *
  51. * See sensor_channel_get() for argument description
  52. */
  53. typedef int (*sensor_channel_get_t)(const struct device *dev,
  54. enum sensor_channel chan,
  55. struct sensor_value *val);
  56. __subsystem struct sensor_driver_api {
  57. sensor_attr_set_t attr_set;
  58. sensor_attr_get_t attr_get;
  59. sensor_trigger_set_t trigger_set;
  60. sensor_sample_fetch_t sample_fetch;
  61. sensor_channel_get_t channel_get;
  62. };

驱动的系统调用

include/drivers/sensor.h中定义传感器的系统调用接口。例如:sensor_attr_set的系统调用:

  1. /**
  2. * @brief Set an attribute for a sensor
  3. *
  4. * @param dev Pointer to the sensor device
  5. * @param chan The channel the attribute belongs to, if any. Some
  6. * attributes may only be set for all channels of a device, depending on
  7. * device capabilities.
  8. * @param attr The attribute to set
  9. * @param val The value to set the attribute to
  10. *
  11. * @return 0 if successful, negative errno code if failure.
  12. */
  13. __syscall int sensor_attr_set(const struct device *dev,
  14. enum sensor_channel chan,
  15. enum sensor_attribute attr,
  16. const struct sensor_value *val);
  17. static inline int z_impl_sensor_attr_set(const struct device *dev,
  18. enum sensor_channel chan,
  19. enum sensor_attribute attr,
  20. const struct sensor_value *val)
  21. {
  22. const struct sensor_driver_api *api =
  23. (const struct sensor_driver_api *)dev->api;
  24. if (api->attr_set == NULL) {
  25. return -ENOSYS;
  26. }
  27. return api->attr_set(dev, chan, attr, val);
  28. }

从上可以看出我们只需要在驱动中实现API模型中函数就可以了。

传感器驱动实现

在实现驱动时按照sensor_driver_api成员的接口和功能定义进行实现,例如dht.c

  1. static int dht_channel_get(struct device *dev,
  2. enum sensor_channel chan,
  3. struct sensor_value *val)
  4. {
  5. ...
  6. }

在驱动初始化的时候将对应的sensor_driver_api注册,上层驱动模型就可以通过device name来寻找到驱动实现

  1. static const struct sensor_driver_api dht_api = {
  2. .sample_fetch = &dht_sample_fetch,
  3. .channel_get = &dht_channel_get,
  4. };
  5. DEVICE_AND_API_INIT(dht_dev, DHT11, &dht_init, &dht_data,
  6. NULL, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, &dht_api);

DEVICE_AND_API_INIT宏是定义在include/device.h中的:

  1. /**
  2. * @def DEVICE_AND_API_INIT
  3. *
  4. * @brief Invoke DEVICE_DEFINE() with no power management support (@p
  5. * pm_control_fn).
  6. */
  7. #define DEVICE_AND_API_INIT(dev_name, drv_name, init_fn, \
  8. data_ptr, cfg_ptr, level, prio, api_ptr) \
  9. __DEPRECATED_MACRO \
  10. DEVICE_DEFINE(dev_name, drv_name, init_fn, \
  11. NULL, \
  12. data_ptr, cfg_ptr, level, prio, api_ptr)
  • dev_name:设备名称
  • drv_name:驱动名称,通过device_get_binding来查找
  • init_fn: 初始化函数
  • data_ptr: 驱动中data数据指针
  • cfg_ptr: 驱动中的config数据指针
  • level:注册级别
  • prio:注册级别中优先级
  • api_ptr:驱动中的api数据指针

驱动实现范围

struct sensor_driver_apisample_fetchchannel_get必须实现,而attr_setattr_gettrigger_set可选,但应用层一定要注意使用同一接口时可选的驱动方法可能无效。