RT-thread ultrasonic sensor drive module development ---- Example HC-SR04

Disclaimer: This article is a blogger original article, shall not be reproduced without the bloggers allowed. https://blog.csdn.net/m0_37697335/article/details/90680207

First, preparation

Ultrasonic Module HC-SR04 Introduction: https://blog.csdn.net/super828/article/details/84112824 .

Sensor Driver Development Guide: https://www.rt-thread.org/document/site/development-guide/sensor/sensor_driver_development/# .

Sensor drive frame description: https://www.rt-thread.org/document/site/development-guide/sensor/sensor_driver/ .

Two, Sensor drive frame

Effect Sensor drive frame is: to provide for the upper unified user interface , to improve the upper layer code reusability; simplified difficulty bottom-driven development, as long as to achieve a simple ops (operations: an operation command) to the sensor can be registered on the system.

That sensor registered with the system, becoming the device file, and then the upper layer application can call a unified API to control the sensor, such as sensor data acquisition operation of the class.

Sensor FIG overall structure of the drive frame as follows:

It provided for the upper layer is a standard device interfaces open/close/read/write/control .

Provided for the underlying driver is a simple interface to ops: fetch_data/control.

Module1 and support frame (block), there is a coupling of the bottom sensor device providing services. 

2.1, works

Sensor device is standard equipment in fact  a rich, is the addition of Sensor own unique part of the standard equipment on the basis of the original   and  , as shown below: rt_device属性控制命令 

Sensor entire apparatus comprises two parts:

1, inherits some of the characteristics from the standard apparatus, comprising: a standard control interface 回调函数, device_id and the like.

2, Sensor device unique portion , Sensor 的类型comprising: 相关的信息, 特有的控制命令, , ops, and some  数据的结构.

.Sensor device structure is as follows:

struct rt_sensor_device
{
    struct rt_device             parent;    /* The standard device */

​    struct rt_sensor_info        info;      /* The sensor info data */
​    struct rt_sensor_config      config;    /* The sensor config data */

​    void                        *data_buf;  /* The buf of the data received */
​    rt_size_t                    data_len;  /* The size of the data received */

​    const struct rt_sensor_ops  *ops;       /* The sensor ops 操作命令*/

​    struct rt_sensor_module     *module;    /* The sensor module */
};
typedef struct rt_sensor_device *rt_sensor_t;

Which, struct rt_sensor_info info stored in some information related to the Sensor itself, in providing devices registered when the Sensor should not modify its contents during use. Individual members as shown in FIG.

struct rt_sensor_info
{
    rt_uint8_t     type;                    /* The sensor type */
    rt_uint8_t     vendor;                  /* Vendor of sensors 供应商*/
    const char    *model;                   /* model name of sensor 比如MPU6050*/
    rt_uint8_t     unit;                    /* unit of measurement */
    rt_uint8_t     intf_type;               /* Communication interface type ,such as IIc */
    rt_int32_t     range_max;    /* maximum range of this sensor's value. unit is 'unit'*/
    rt_int32_t     range_min;    /* minimum range of this sensor's value. unit is 'unit' */
    rt_uint32_t    period_min;   /* Minimum measurement period,unit:ms. zero = not a constant rate */
    rt_uint8_t     fifo_max;                /* Maximum depth of fifo  */
};

Sensor-driven framework to abstract some common configuration options that can be configured is placed  struct rt_sensor_config , the members are as follows:

struct rt_sensor_config
{
    struct rt_sensor_intf        intf;      /* sensor interface config */
    struct rt_device_pin_mode    irq_pin;   /* Interrupt pin, The purpose of this pin is to notification read data */
    rt_uint8_t                   mode;      /* sensor work mode */
    rt_uint8_t                   power;     /* sensor power mode */
    rt_uint16_t                  odr;       /* sensor out data rate */
    rt_int32_t                   range;     /* sensor range of measurement */
};


struct rt_sensor_intf
{
    char                       *dev_name;   /* The name of the communication device */
    rt_uint8_t                  type;       /* Communication interface type */
    void                       *user_data;  /* Private data for the sensor. ex. i2c addr,spi cs,control I/O */
};

Some of the remaining Sensor configuration items is a unique control command, the combined control of the interface ops , to complete the configuration of the sensor. As follows:

#define  RT_SENSOR_CTRL_GET_ID         (0)  /* 读设备ID */
#define  RT_SENSOR_CTRL_GET_INFO       (1)  /* 获取设备信息 */
#define  RT_SENSOR_CTRL_SET_RANGE      (2)  /* 设置传感器测量范围 */
#define  RT_SENSOR_CTRL_SET_ODR        (3)  /* 设置传感器数据输出速率,unit is HZ */
#define  RT_SENSOR_CTRL_SET_MODE       (4)  /* 设置工作模式 */
#define  RT_SENSOR_CTRL_SET_POWER      (5)  /* 设置电源模式 */
#define  RT_SENSOR_CTRL_SELF_TEST      (6)  /* 自检 */

Sensor for storing data, in order to facilitate the parsed data, a type of each predetermined Sensor has its own unique data structure used between these members 共用体in order to reduce the code amount.

/* 3-axis Data Type */
struct sensor_3_axis
{
    rt_int32_t x;
    rt_int32_t y;
    rt_int32_t z;
};
struct rt_sensor_data
{
    rt_uint32_t         timestamp;          /* The timestamp when the data was received */
    rt_uint8_t          type;               /* The sensor type of the data */
    union
    {
        struct sensor_3_axis acce;          /* Accelerometer.       unit: mG          */
        struct sensor_3_axis gyro;          /* Gyroscope.           unit: mdps        */
        struct sensor_3_axis mag;           /* Magnetometer.        unit: mGauss      */
        rt_int32_t           temp;          /* Temperature.         unit: dCelsius    */
        rt_int32_t           humi;          /* Relative humidity.   unit: permillage  */
        rt_int32_t           baro;          /* Pressure.            unit: pascal (Pa) */
        rt_int32_t           light;         /* Light.               unit: lux         */
        rt_int32_t           proximity;     /* Distance.            unit: centimeters */
        rt_int32_t           hr;            /* Heat rate.           unit: HZ          */
        rt_int32_t           tvoc;          /* TVOC.                unit: permillage  */
        rt_int32_t           noise;         /* Noise Loudness.      unit: HZ          */
        rt_uint32_t          step;          /* Step sensor.         unit: 1           */
    } data;
};

Unique ops

OPS (operation function) comprises two function pointers, a role is to obtain sensor data (fetch_data), the other role is to control the sensor by a control command (control).

struct rt_sensor_ops
{
    rt_size_t (*fetch_data)(struct rt_sensor_device *sensor, void *buf, rt_size_t len);
    rt_err_t (*control)(struct rt_sensor_device *sensor, int cmd, void *arg);
};

way to register

Sensor driver framework provides a registration function Sensor, Sensor by passing control blocks, name, and private data flag, it is possible to complete the registration sensor device.

int rt_hw_sensor_register(rt_sensor_t     sensor,                
                          const char      *name,
                          rt_uint32_t     flag,
                          void            *data);

It would appear Sensor-driven framework relying on the framework of standard equipment, as long as the sensor is connected to the drive of the Sensor ops, and by calling the  rt_hw_sensor_register register function Sensor devices can be controlled through the standard device interface of the sensor.

module support

Defined module is to solve the two sensors coupled to the bottom occurs, and some sensors have a function of both the accelerometer gyro function, and they are common to the FIFO in the FIFO mode, only the two types sensor data are simultaneously read out, which shows that they are coupled to the data. To solve this problem, we define the type of module

struct rt_sensor_module
{
    rt_mutex_t            lock;                      /* The module lock */

    rt_sensor_t           sen[RT_SENSOR_MODULE_MAX]; /* The module contains a list of sensors */
    rt_uint8_t            sen_num;                   /* Number of sensors contained in the module */
};

Which contains a pointer device control block coupled to the sensor, this function can be via the read data when the gyroscope, while updating the value of the accelerometer, to solve the problem underlying coupling.

Third, the development of guidelines --- ultrasonic module HC-SR04 A Case Study

The main task is to develop ops docking interfaces Sensor drive frame, and then register for the Sensor device, and then be able to control the behavior of the sensor by driving relevant framework.

framework were given two sensor interfaces ( fetch_data /  control) required to achieve these two interfaces in the drive.

3.1、fetchdata

Action: acquiring sensor data. Interface Prototype:

rt_size_t (*fetch_data)(struct rt_sensor_device *sensor, void *buf, rt_size_t len);

Sensor-driven framework to support the current default polling (POLLING), interrupt (INT), FIFO three operating modes. If the sensor is to develop the support 中断and FIFOoperation mode, the operation mode where the sensor is determined, and then return to the sensor data according to different modes. As follows:

static rt_size_t xxx_acc_fetch_data(struct rt_sensor_device *sensor, void *buf, rt_size_t len)
{
    if (sensor->config.mode == RT_SENSOR_MODE_POLLING)
    {
        return _xxx_acc_polling_get_data(sensor, buf, len);
    }
    else if (sensor->config.mode == RT_SENSOR_MODE_INT)
    {
        return _xxx_acc_int_get_data(sensor, buf, len);
    }
    else if (sensor->config.mode == RT_SENSOR_MODE_FIFO)
    {
        return _xxx_acc_fifo_get_data(sensor, buf, len);
    }
    else
        return 0;
}

Developers should return data to identify the data type for storing data, and then filled with a time stamp data field, as follows:

sensor_data->type = RT_SENSOR_CLASS_ACCE;
sensor_data->data.acce.x = acceleration.x;
sensor_data->data.acce.y = acceleration.y;
sensor_data->data.acce.z = acceleration.z;
sensor_data->timestamp = rt_sensor_get_ts();

HC-SR04 as an example:

static rt_size_t _fetch_data(struct rt_sensor_device *sensor, void *buf, rt_size_t len)
{
    struct rt_sensor_data *data = buf;

    data->type = RT_SENSOR_CLASS_PROXIMITY;
    data->data.proximity = distance;
    data->timestamp = rt_sensor_get_ts();
    return 1;
}

3.2、control

rt_err_t (*control)(struct rt_sensor_device *sensor, int cmd, void *arg);

Control sensors rely on this interface function is realized by performing different incoming command word determining the different operations.

HC-SR04 as an example:

static rt_err_t _control(struct rt_sensor_device *sensor, int cmd, void *args)
{
    rt_err_t result = RT_EOK;

    switch (cmd)
    {
    case RT_SENSOR_CTRL_SET_POWER:
        result = _set_power(sensor, (rt_uint32_t)args & 0xff);
        break;
    default:
        return RT_EOK;
    }
    return result;
}

3.3, the device interface structure ops

But also to achieve a storage device interface ops above structure interface functions:

static struct rt_sensor_ops xxx_ops =
{
    xxx_acc_fetch_data,
    xxx_acc_control
};

Fourth, the device registration

    rt_int8_t result;
    rt_sensor_t sensor_pr = RT_NULL;

    sensor_pr = rt_calloc(1, sizeof(struct rt_sensor_device));
    if (sensor_pr == RT_NULL)
        return RT_NULL;

    sensor_pr->info.type       = RT_SENSOR_CLASS_PROXIMITY;
    sensor_pr->info.model      = "hr_sr04";
    sensor_pr->info.unit       = RT_SENSOR_UNIT_MM;
    sensor_pr->info.intf_type  = RT_SENSOR_INTF_ONEWIRE;
    sensor_pr->info.range_max  = RANG_MAX;
    sensor_pr->info.range_min  = RANG_MIN;
    sensor_pr->info.period_min = 100;

    rt_memcpy(&sensor_pr->config, cfg, sizeof(struct rt_sensor_config));
    sensor_pr->ops = &sensor_ops;
    sensor_pr->irq_handle = sr04_irq_handle;

    result = rt_hw_sensor_register(sensor_pr, name, RT_DEVICE_FLAG_RDWR, RT_NULL);

 

 

Guess you like

Origin blog.csdn.net/m0_37697335/article/details/90680207