SENSOR Devices
Sensor is an important part of the Internet of Things. "Sensor" is to the Internet of Things as "eyes are to humans". Without eyes, humans cannot see the world, and the same is true for the Internet of Things.
With the development of the Internet of Things, a large number of sensors have been developed for developers to choose from, such as accelerometers, magnetometers, gyroscopes, barometers/pressure, and humidometers. These sensors are produced by major semiconductor manufacturers in the world. Although they increase the market's selectivity, they also increase the difficulty of application development. Because different sensor manufacturers and different sensors need to be equipped with their own unique drivers to operate, when developing applications, they need to adapt to different sensors, which naturally increases the difficulty of development. In order to reduce the difficulty of application development and increase the reusability of sensor drivers, we designed sensor devices.
The function of the sensor device is to provide a unified operation interface for the upper layer and improve the reusability of the upper layer code.
Interface: standard device interface (open/close/read/control)
Working mode: Support polling, interrupt and FIFO modes
Power mode: supports four modes: power off, normal, low power consumption, and high power consumption
Click the sensor list to view currently supported sensors.
The application accesses the sensor device through the I/O device management interface provided by RT-Thread. The relevant interface is as follows:
function
describe
rt_device_find()
Find the device and get the device handle according to the sensor device name
rt_device_open()
Open the sensor device
rt_device_read()
Reading Data
rt_device_control()
Controlling sensor devices
rt_device_set_rx_indicate()
Set the receiving callback function
rt_device_close()
Turn off sensor devices
The application obtains the device handle according to the sensor device name, and then can operate the sensor device. The device search function is as follows:
rt_device_t rt_device_find(const char* name);copymistakeCopy Success
parameter
describe
name
Sensor device name
return
——
Device handle
If the corresponding device is found, the corresponding device handle will be returned.
RT_NULL
No corresponding device object was found
The usage examples are as follows:
#define SENSOR_DEVICE_NAME "acce_st" /* 传感器设备名称 */
static rt_device_t sensor_dev; /* 传感器设备句柄 */
/* 根据设备名称查找传感器设备,获取设备句柄 */
sensor_dev = rt_device_find(SENSOR_DEVICE_NAME);copymistakeCopy Success
Through the device handle, the application can open and close the device. When opening the device, it will detect whether the device has been initialized. If it has not been initialized, the initialization interface will be called by default to initialize the device. Open the device through the following function:
rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflags);copymistakeCopy Success
parameter
describe
dev
Device handle
oflags
Device mode flags
return
——
RT_EOK
Device opened successfully
- RT_EBUSY
If the device registration parameter includes the RT_DEVICE_FLAG_STANDALONE parameter, the device will not be allowed to be opened repeatedly.
-RT_EINVAL
Unsupported open parameters
Other error codes
Device open failed
The oflags parameter supports the following parameters:
#define RT_DEVICE_FLAG_RDONLY 0x001 /* 标准设备的只读模式,对应传感器的轮询模式 */
#define RT_DEVICE_FLAG_INT_RX 0x100 /* 中断接收模式 */
#define RT_DEVICE_FLAG_FIFO_RX 0x200 /* FIFO 接收模式 */copymistakeCopy Success
There are three modes for receiving and sending sensor data: interrupt mode, polling mode, and FIFO mode. When using, only one of these three modes can be selected . If the sensor's opening parameter oflags does not specify the interrupt mode or FIFO mode, the polling mode is used by default.
FIFO (First Input First Output) means first in, first out. FIFO transmission mode requires sensor hardware support. Data is stored in the hardware FIFO. Multiple data can be read at one time, which saves CPU resources for other operations. It is very useful in low power mode.
If the sensor is to use FIFO receive mode, oflags takes the value RT_DEVICE_FLAG_FIFO_RX.
An example of using a sensor device in polling mode is as follows:
#define SAMPLE_SENSOR_NAME "acce_st" /* 传感器设备名称 */
int main(void)
{
rt_device_t dev;
struct rt_sensor_data data;
/* 查找传感器设备 */
dev = rt_device_find(SAMPLE_SENSOR_NAME);
/* 以只读及轮询模式打开传感器设备 */
rt_device_open(dev, RT_DEVICE_FLAG_RDONLY);
if (rt_device_read(dev, 0, &data, 1) == 1)
{
rt_kprintf("acce: x:%5d, y:%5d, z:%5d, timestamp:%5d\n", data.data.acce.x, data.data.acce.y, data.data.acce.z, data.timestamp);
}
rt_device_close(dev);
return RT_EOK;
}copymistakeCopy Success
Through the command control word, the application can configure the sensor device through the following functions:
rt_err_t rt_device_control(rt_device_t dev, rt_uint8_t cmd, void* arg);copymistakeCopy Success
parameter
describe
dev
Device handle
cmd
Command control word, see below for details
arg
Control parameters, detailed description see below
return
——
RT_EOK
Function execution successful
-RT_ENOSYS
Execution failed, dev is empty
Other error codes
Execution failed
The cmd currently supports the following command control characters:
#define RT_SENSOR_CTRL_GET_ID /* 读设备ID */
#define RT_SENSOR_CTRL_GET_INFO /* 获取设备信息 */
#define RT_SENSOR_CTRL_SET_RANGE /* 设置传感器测量范围 */
#define RT_SENSOR_CTRL_SET_ODR /* 设置传感器数据输出速率,unit is HZ */
#define RT_SENSOR_CTRL_SET_POWER /* 设置电源模式 */
#define RT_SENSOR_CTRL_SELF_TEST /* 自检 */copymistakeCopy Success
struct rt_sensor_info info;
rt_device_control(dev, RT_SENSOR_CTRL_GET_INFO, &info);
LOG_I("vendor :%d", info.vendor);
LOG_I("model :%s", info.model);
LOG_I("unit :%d", info.unit);
LOG_I("intf_type :%d", info.intf_type);
LOG_I("period_min:%d", info.period_min);copymistakeCopy Success
rt_uint8_t reg = 0xFF;
rt_device_control(dev, RT_SENSOR_CTRL_GET_ID, ®);
LOG_I("device id: 0x%x!", reg);copymistakeCopy Success
The units used when setting the sensor's measurement range are the units provided when the device was registered.
rt_device_control(dev, RT_SENSOR_CTRL_SET_RANGE, (void *)1000);copymistakeCopy Success
Set the output rate to 100HZ and call the following interface.
rt_device_control(dev, RT_SENSOR_CTRL_SET_ODR, (void *)100);copymistakeCopy Success
/* 设置电源模式为掉电模式 */
rt_device_control(dev, RT_SENSOR_CTRL_SET_POWER, (void *)RT_SEN_POWER_DOWN);
/* 设置电源模式为普通模式 */
rt_device_control(dev, RT_SENSOR_CTRL_SET_POWER, (void *)RT_SEN_POWER_NORMAL);
/* 设置电源模式为低功耗模式 */
rt_device_control(dev, RT_SENSOR_CTRL_SET_POWER, (void *)RT_SEN_POWER_LOW);
/* 设置电源模式为高性能模式 */
rt_device_control(dev, RT_SENSOR_CTRL_SET_POWER, (void *)RT_SEN_POWER_HIGH);copymistakeCopy Success
int test_res;
/* 控制设备自检 并把结果返回回来,RT_EOK 自检成功, 其他自检失败 */
rt_device_control(dev, RT_SENSOR_CTRL_SELF_TEST, &test_res);copymistakeCopy Success
The data receiving indication can be set through the following function. When the sensor receives data, it notifies the upper application thread that data has arrived:
rt_err_t rt_device_set_rx_indicate(rt_device_t dev, rt_err_t (*rx_ind)(rt_device_t dev,rt_size_t size));copymistakeCopy Success
parameter
describe
dev
Device handle
rx_ind
Callback function pointer
dev
Device handle (callback function parameter)
size
Buffer data size (callback function parameter)
return
——
RT_EOK
Set up for success
The callback function of this function is provided by the caller. If the sensor is turned on in interrupt receiving mode, when the sensor receives data and generates an interrupt, the callback function will be called, and the data size of the buffer at this time will be placed in the size parameter, and the sensor device handle will be placed in the dev parameter for the caller to obtain.
In general, the receiving callback function can send a semaphore or event to notify the sensor data processing thread that data has arrived. The usage example is as follows:
#define SAMPLE_SENSOR_NAME "acce_st" /* 传感器设备名称 */
static rt_device_t dev; /* 传感器设备句柄 */
static struct rt_semaphore rx_sem; /* 用于接收消息的信号量 */
/* 接收数据回调函数 */
static rt_err_t sensor_input(rt_device_t dev, rt_size_t size)
{
/* 传感器接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */
rt_sem_release(&rx_sem);
return RT_EOK;
}
static int sensor_sample(int argc, char *argv[])
{
dev = rt_device_find(SAMPLE_SENSOR_NAME);
/* 以中断接收及轮询发送模式打开传感器设备 */
rt_device_open(dev, RT_DEVICE_FLAG_INT_RX);
/* 初始化信号量 */
rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_PRIO);
/* 设置接收回调函数 */
rt_device_set_rx_indicate(dev, sensor_input);
}
copymistakeCopy Success
The following function can be called to read the data received by the sensor:
rt_size_t rt_device_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size);copymistakeCopy Success
parameter
describe
dev
Device handle
pos
Read data offset. This parameter is not used by the sensor.
buffer
Buffer pointer. The read data will be saved in the buffer.
size
The number of data read
return
——
>0
Returns the number of data read
0
You need to read the errno of the current thread to determine the error status
The following is an example of using the sensor in interrupt reception mode and in conjunction with the reception callback function:
static rt_device_t dev; /* 传感器设备句柄 */
static struct rt_semaphore rx_sem; /* 用于接收消息的信号量 */
/* 接收数据的线程 */
static void sensor_irq_rx_entry(void *parameter)
{
rt_device_t dev = parameter;
struct rt_sensor_data data;
rt_size_t res;
while (1)
{
rt_sem_take(rx_sem, RT_WAITING_FOREVER);
res = rt_device_read(dev, 0, &data, 1);
if (res == 1)
{
sensor_show_data(dev, &data);
}
}
}
copymistakeCopy Success
The following is an example of using the sensor in FIFO receiving mode and in conjunction with the receiving callback function:
static rt_sem_t sensor_rx_sem = RT_NULL;
rt_err_t rx_cb(rt_device_t dev, rt_size_t size)
{
rt_sem_release(sensor_rx_sem);
return 0;
}
static void sensor_fifo_rx_entry(void *parameter)
{
rt_device_t dev = parameter;
struct rt_sensor_data data;
rt_size_t res, i;
data = rt_malloc(sizeof(struct rt_sensor_data) * 32);
while (1)
{
rt_sem_take(sensor_rx_sem, RT_WAITING_FOREVER);
res = rt_device_read(dev, 0, data, 32);
for (i = 0; i < res; i++)
{
sensor_show_data(dev, &data[i]);
}
}
}
int main(void)
{
static rt_thread_t tid1 = RT_NULL;
rt_device_t dev;
struct rt_sensor_data data;
sensor_rx_sem = rt_sem_create("sen_rx_sem", 0, RT_IPC_FLAG_PRIO);
tid1 = rt_thread_create("sen_rx_thread",
sensor_fifo_rx_entry, dev,
1024,
15, 5);
if (tid1 != RT_NULL)
rt_thread_startup(tid1);
dev = rt_device_find("acce_st");
rt_device_set_rx_indicate(dev, rx_cb);
rt_device_open(dev, RT_SEN_FLAG_FIFO);
return RT_EOK;
}copymistakeCopy Success
When the application completes the sensor operation, it can close the sensor device through the following function:
rt_err_t rt_device_close(rt_device_t dev);copymistakeCopy Success
parameter
describe
dev
Device handle
return
——
RT_EOK
Shut down the device successfully
-RT_ERROR
The device has been completely shut down. You cannot shut down the device again.
Other error codes
Failed to shut down the device
Closing the device interface and opening the device interface must be used in pairs. Each time you open the device, you must close it once. Only in this way can the device be completely closed. Otherwise, the device will still be in an open state.
The specific usage of the sensor device can refer to the following sample code. The main steps of the sample code are as follows:
First look up the sensor settings to get the device handle.
Turn on the sensor in polling mode.
Read the data 5 times continuously and print it out.
Turn off the sensor.
This sample code is not limited to a specific BSP. It can be run by entering a different dev_name according to the sensor device registered in the BSP.
/*
* 程序清单:这是一个 传感器 设备使用例程
* 例程导出了 sensor_sample 命令到控制终端
* 命令调用格式:sensor_sample dev_name
* 命令解释:命令第二个参数是要使用的传感器设备名称
* 程序功能:打开对应的传感器,然后连续读取 5 次数据并打印出来。
*/
#include "sensor.h"
static void sensor_show_data(rt_size_t num, rt_sensor_t sensor, struct rt_sensor_data *sensor_data)
{
switch (sensor->info.type)
{
case RT_SENSOR_CLASS_ACCE:
rt_kprintf("num:%3d, x:%5d, y:%5d, z:%5d, timestamp:%5d\n", num, sensor_data->data.acce.x, sensor_data->data.acce.y, sensor_data->data.acce.z, sensor_data->timestamp);
break;
case RT_SENSOR_CLASS_GYRO:
rt_kprintf("num:%3d, x:%8d, y:%8d, z:%8d, timestamp:%5d\n", num, sensor_data->data.gyro.x, sensor_data->data.gyro.y, sensor_data->data.gyro.z, sensor_data->timestamp);
break;
case RT_SENSOR_CLASS_MAG:
rt_kprintf("num:%3d, x:%5d, y:%5d, z:%5d, timestamp:%5d\n", num, sensor_data->data.mag.x, sensor_data->data.mag.y, sensor_data->data.mag.z, sensor_data->timestamp);
break;
case RT_SENSOR_CLASS_HUMI:
rt_kprintf("num:%3d, humi:%3d.%d%%, timestamp:%5d\n", num, sensor_data->data.humi / 10, sensor_data->data.humi % 10, sensor_data->timestamp);
break;
case RT_SENSOR_CLASS_TEMP:
rt_kprintf("num:%3d, temp:%3d.%dC, timestamp:%5d\n", num, sensor_data->data.temp / 10, sensor_data->data.temp % 10, sensor_data->timestamp);
break;
case RT_SENSOR_CLASS_BARO:
rt_kprintf("num:%3d, press:%5d, timestamp:%5d\n", num, sensor_data->data.baro, sensor_data->timestamp);
break;
case RT_SENSOR_CLASS_STEP:
rt_kprintf("num:%3d, step:%5d, timestamp:%5d\n", num, sensor_data->data.step, sensor_data->timestamp);
break;
default:
break;
}
}
static void sensor_sample(int argc, char **argv)
{
rt_device_t dev = RT_NULL;
struct rt_sensor_data data;
rt_size_t res, i;
/* 查找系统中的传感器设备 */
dev = rt_device_find(argv[1]);
if (dev == RT_NULL)
{
rt_kprintf("Can't find device:%s\n", argv[1]);
return;
}
/* 以轮询模式打开传感器设备 */
if (rt_device_open(dev, RT_DEVICE_FLAG_RDONLY) != RT_EOK)
{
rt_kprintf("open device failed!");
return;
}
for (i = 0; i < 5; i++)
{
/* 从传感器读取一个数据 */
res = rt_device_read(dev, 0, &data, 1);
if (res != 1)
{
rt_kprintf("read data failed!size is %d", res);
}
else
{
sensor_show_data(i, (rt_sensor_t)dev, &data);
}
rt_thread_mdelay(100);
}
/* 关闭传感器设备 */
rt_device_close(dev);
}
MSH_CMD_EXPORT(sensor_sample, sensor device sample);copymistakeCopy Success
Last updated
Was this helpful?