Sensor(传感器)是物联网重要的一部分,“Sensor 之于物联网”就相当于“眼睛之于人类”。人类如果没有了眼睛就看不到这大千的花花世界,对于物联网来说也是一样。已经有大量的 Sensor 被开发出来供开发者选择了,如:加速度计(Accelerometer)、磁力计(Magnetometer)、陀螺仪(Gyroscope)、气压计(Barometer/pressure)、湿度计(Humidometer)等。
传感器介绍
LTR303 传感器
LTR303 是一款数字环境光传感器,通过 I²C 或 SPI 接口与外部设备进行通信,具有低功耗、高精度等特点,能够适应多种复杂的光照环境。
LTR303 内部集成了光电二极管,能够感知环境中的可见光与红外光。通过光电转换原理,将光信号转化为电信号,再经过内部的 ADC(模拟数字转换器)将模拟电信号转换为数字信号,从而实现对环境光照强度的精确测量,测量范围可达 0.01 - 88,000 lux。
作用:根据环境光强度自动调节屏幕亮度,在保证显示效果的同时降低设备功耗,提升用户体验。
MMC56X3 传感器
MMC56X3 是一系列磁传感器,采用先进的霍尔效应技术,通过 I²C 接口与主控芯片通信,具有高灵敏度、低噪声、宽工作电压范围等优势。
利用霍尔效应原理,当有磁场作用于传感器时,传感器内部的霍尔元件会产生霍尔电压,该电压与磁场强度成正比。通过对霍尔电压的精确测量和处理,MMC56X3 能够检测环境中的磁场强度和方向 。
LSM6DS 传感器
LSM6DS 是一款高性能的 6 轴惯性测量单元(IMU),集成了三轴加速度计和三轴陀螺仪,支持 I²C 和 SPI 通信接口,具有低功耗、高动态范围、高精度等特点。
加速度测量:三轴加速度计能够测量设备在三个正交方向(X、Y、Z 轴)上的加速度,通过检测内部质量块在加速度作用下产生的惯性力,将其转化为电信号,经过处理后输出加速度数据,测量范围通常可设置为 ±2g、±4g、±8g 或 ±16g
角速度测量:三轴陀螺仪用于测量设备绕三个正交轴的旋转角速度,利用科里奥利力原理,当设备旋转时,内部的振动结构会受到科里奥利力的作用,产生相应的电信号,经过处理后得到角速度数据,测量范围一般有 ±125°/s、±250°/s、±500°/s、±1000°/s 和 ±2000°/s 等多种可选 。
供电介绍
在使用 Sensor 传感器时,需先开启供电。这是因为当传感器处于休眠状态或其他非工作场景时,关闭其供电能够更有效地降低功耗。如下图所示:
在传感器的应用场景中,PA_38 与 PA_30 这两个供电引脚必须被同步激活。这一操作具有不可替代性,因为它们分别控制着传感器的电源系统。若其中任一引脚未被激活,将直接导致传感器因供电不足而无法启动,从而无法通讯。
硬件连接
我们查看一下立创黄山派的原理图,发现各传感器都是使用PA_39_I2C3_SDA 与PA_40_I2C3_SLC进行数据的接收与发送,外设总线使用的是I2C3。
程序讲解
GPIO初始
初始化供电IO与I2C通信的引脚PA_39和PA_40设置为上拉模式
static void board_io_init(void)
{
HAL_PIN_Set(PAD_PA40, I2C3_SCL, PIN_PULLUP, 1);
HAL_PIN_Set(PAD_PA39, I2C3_SDA, PIN_PULLUP, 1);
rt_base_t vsys = GET_PIN(1,38);
rt_pin_mode(vsys, PIN_MODE_OUTPUT);
rt_pin_write(vsys, PIN_HIGH);
rt_base_t pin_id = GET_PIN(1,30);
rt_pin_mode(pin_id, PIN_MODE_OUTPUT);
rt_pin_write(pin_id, PIN_HIGH);
rt_thread_mdelay(50);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
初始化传感器
想要初始化传感器,我们需要一个初始化函数,在工程中我们有如下代码:
static void sensors_init(struct rt_sensor_config *cfg)
{
cfg->intf.dev_name = "i2c3";
rt_hw_ltr303_init("ltr303", cfg);
rt_hw_mmc56x3_init("mmc56x3", cfg);
cfg->intf.user_data = (void *)LSM6DSL_ADDR_DEFAULT;
cfg->irq_pin.pin = RT_PIN_NONE;
rt_hw_lsm6dsl_init("lsm6d", cfg);
}
2
3
4
5
6
7
8
9
10
打开与配置传感器
static void open_and_config_devices(rt_device_t *ltr303_dev, rt_device_t *mmc56x3_dev,
rt_device_t *lsm6d_dev, rt_device_t *lsm6d_gyro_dev, rt_device_t *lsm6d_step_dev)
{
*ltr303_dev = rt_device_find("li_ltr303");
if (*ltr303_dev == RT_NULL)
rt_kprintf("Can't find device:%s\n", "ltr303");
else {
rt_err_t ret = rt_device_open(*ltr303_dev, RT_DEVICE_FLAG_RDONLY);
if (ret != RT_EOK)
rt_kprintf("open device failed! err: %d\n", ret);
rt_device_control(*ltr303_dev, RT_SENSOR_CTRL_SET_POWER, (void *)RT_SENSOR_POWER_NORMAL);
}
*mmc56x3_dev = rt_device_find("mag_mmc56x3");
if (*mmc56x3_dev == RT_NULL)
rt_kprintf("Can't find device:%s\n", "mmc56x3");
else {
rt_err_t ret = rt_device_open(*mmc56x3_dev, RT_DEVICE_FLAG_RDONLY);
if (ret != RT_EOK)
rt_kprintf("open device failed! err: %d\n", ret);
}
*lsm6d_dev = rt_device_find("acce_lsm");
*lsm6d_gyro_dev = rt_device_find("gyro_lsm");
*lsm6d_step_dev = rt_device_find("step_lsm");
if (*lsm6d_dev == RT_NULL || *lsm6d_gyro_dev == RT_NULL || *lsm6d_step_dev == RT_NULL)
rt_kprintf("Can't find device:%s\n", "lsm6d");
else {
rt_err_t ret = rt_device_open(*lsm6d_dev, RT_DEVICE_FLAG_RDONLY);
ret += rt_device_open(*lsm6d_gyro_dev, RT_DEVICE_FLAG_RDONLY);
ret += rt_device_open(*lsm6d_step_dev, RT_DEVICE_FLAG_RDONLY);
if (ret != RT_EOK)
rt_kprintf("open device failed! err: %d\n", ret);
rt_device_control(*lsm6d_dev, RT_SENSOR_CTRL_SET_ODR, (void *)1660);
rt_device_control(*lsm6d_gyro_dev, RT_SENSOR_CTRL_SET_ODR, (void *)1660);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
- 查找传感器应用程序根据传感器设备名称获取设备句柄,进而可以操作传感器设备,查找设备函数如:*ltr303_dev = rt_device_find("li_ltr303");
- 打开传感器通过设备句柄,应用程序可以打开和关闭设备,打开设备时,会检测设备是否已经初始化,没有初始化则会默认调用初始化接口初始化设备。通过如下函数打开设备rt_err_t ret = rt_device_open(*lsm6d_dev, RT_DEVICE_FLAG_RDONLY);
- 设备模式标志参数支持下列参数:
#define RT_DEVICE_FLAG_RDONLY 0x001 /* 标准设备的只读模式,对应传感器的轮询模式 */
#define RT_DEVICE_FLAG_INT_RX 0x100 /* 中断接收模式 */
#define RT_DEVICE_FLAG_FIFO_RX 0x200 /* FIFO 接收模式 */
2
3
传感器数据接收和发送数据的模式分为 3 种:中断模式、轮询模式、FIFO 模式。在使用的时候,这 3 种模式只能选其一, 在这使用以只读及轮询模式打开传感器设备如:rt_err_t ret = rt_device_open(*ltr303_dev, RT_DEVICE_FLAG_RDONLY);
- 控制传感器设备通过命令控制字,应用程序可以对传感器设备进行配置,通过如下函数完成:rt*device_control(_ltr303_dev, RT_SENSOR_CTRL_SET_POWER, (void *)RT_SENSOR_POWER_NORMAL); 命令控制字目前支持以下几种命令控制字
#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 /* 自检 */
2
3
4
5
6
传感器数据采集与打印
读取数据可调用读取传感器接收到的数据函数如:res = rt_device_read(ltr303_dev, 0, <r303, 1);,以循环的模式读取当前数据并打印出来。
static void sensors_loop(rt_device_t ltr303_dev, rt_device_t mmc56x3_dev,
rt_device_t lsm6d_dev, rt_device_t lsm6d_gyro_dev, rt_device_t lsm6d_step_dev)
{
struct rt_sensor_data ltr303, mmc56x3, lsm6d_acce, lsm6d_gyro, lsm6d_step;
rt_size_t res;
res = rt_device_read(ltr303_dev, 0, <r303, 1);
if (res != 1)
rt_kprintf("read data failed!size is %d\n", res);
else
rt_kprintf("light: %d lux\n", ltr303.data.light);
res = rt_device_read(mmc56x3_dev, 0, &mmc56x3, 1);
if (res != 1)
rt_kprintf("read data failed!size is %d\n", res);
else
rt_kprintf("mag, x: %d, y: %d, z: %d\n", mmc56x3.data.mag.x, mmc56x3.data.mag.y, mmc56x3.data.mag.z);
res = rt_device_read(lsm6d_dev, 0, &lsm6d_acce, 1);
if (res != 1)
rt_kprintf("read data failed!size is %d\n", res);
else
rt_kprintf("acce, x: %d, y: %d, z: %d\n", lsm6d_acce.data.acce.x, lsm6d_acce.data.acce.y, lsm6d_acce.data.acce.z);
res = rt_device_read(lsm6d_gyro_dev, 0, &lsm6d_gyro, 1);
if (res != 1)
rt_kprintf("read data failed!size is %d\n", res);
else
rt_kprintf("gyro, x: %d, y: %d, z: %d\n", lsm6d_gyro.data.gyro.x, lsm6d_gyro.data.gyro.y, lsm6d_gyro.data.gyro.z);
res = rt_device_read(lsm6d_step_dev, 0, &lsm6d_step, 1);
if (res != 1)
rt_kprintf("read data failed!size is %d\n", res);
else
rt_kprintf("lsm6d step, step: %d\n", lsm6d_step.data.step);
rt_thread_mdelay(100);
rt_kprintf("\n");
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
程序编写
#include "rtthread.h"
#include "bf0_hal.h"
#include "drv_io.h"
#include "stdio.h"
#include "string.h"
#include "drv_gpio.h"
#include "sensor_liteon_ltr303.h"
#include "sensor_memsic_mmc56x3.h"
#include "st_lsm6dsl_sensor_v1.h"
/**
* @brief Main program
* @param None
* @retval 0 if success, otherwise failure number
*/
// 初始化硬件IO
static void board_io_init(void)
{
HAL_PIN_Set(PAD_PA40, I2C3_SCL, PIN_PULLUP, 1);
HAL_PIN_Set(PAD_PA39, I2C3_SDA, PIN_PULLUP, 1);
rt_base_t vsys = GET_PIN(1,38);
rt_pin_mode(vsys, PIN_MODE_OUTPUT);
rt_pin_write(vsys, PIN_HIGH);
rt_base_t pin_id = GET_PIN(1,30);
rt_pin_mode(pin_id, PIN_MODE_OUTPUT);
rt_pin_write(pin_id, PIN_HIGH);
rt_thread_mdelay(50);
}
// 初始化所有传感器
static void sensors_init(struct rt_sensor_config *cfg)
{
cfg->intf.dev_name = "i2c3";
rt_hw_ltr303_init("ltr303", cfg);
rt_hw_mmc56x3_init("mmc56x3", cfg);
cfg->intf.user_data = (void *)LSM6DSL_ADDR_DEFAULT;
cfg->irq_pin.pin = RT_PIN_NONE;
rt_hw_lsm6dsl_init("lsm6d", cfg);
}
// 打开并配置传感器设备
static void open_and_config_devices(rt_device_t *ltr303_dev, rt_device_t *mmc56x3_dev,
rt_device_t *lsm6d_dev, rt_device_t *lsm6d_gyro_dev, rt_device_t *lsm6d_step_dev)
{
*ltr303_dev = rt_device_find("li_ltr303");
if (*ltr303_dev == RT_NULL)
rt_kprintf("Can't find device:%s\n", "ltr303");
else {
rt_err_t ret = rt_device_open(*ltr303_dev, RT_DEVICE_FLAG_RDONLY);
if (ret != RT_EOK)
rt_kprintf("open device failed! err: %d\n", ret);
rt_device_control(*ltr303_dev, RT_SENSOR_CTRL_SET_POWER, (void *)RT_SENSOR_POWER_NORMAL);
}
*mmc56x3_dev = rt_device_find("mag_mmc56x3");
if (*mmc56x3_dev == RT_NULL)
rt_kprintf("Can't find device:%s\n", "mmc56x3");
else {
rt_err_t ret = rt_device_open(*mmc56x3_dev, RT_DEVICE_FLAG_RDONLY);
if (ret != RT_EOK)
rt_kprintf("open device failed! err: %d\n", ret);
}
*lsm6d_dev = rt_device_find("acce_lsm");
*lsm6d_gyro_dev = rt_device_find("gyro_lsm");
*lsm6d_step_dev = rt_device_find("step_lsm");
if (*lsm6d_dev == RT_NULL || *lsm6d_gyro_dev == RT_NULL || *lsm6d_step_dev == RT_NULL)
rt_kprintf("Can't find device:%s\n", "lsm6d");
else {
rt_err_t ret = rt_device_open(*lsm6d_dev, RT_DEVICE_FLAG_RDONLY);
ret += rt_device_open(*lsm6d_gyro_dev, RT_DEVICE_FLAG_RDONLY);
ret += rt_device_open(*lsm6d_step_dev, RT_DEVICE_FLAG_RDONLY);
if (ret != RT_EOK)
rt_kprintf("open device failed! err: %d\n", ret);
rt_device_control(*lsm6d_dev, RT_SENSOR_CTRL_SET_ODR, (void *)1660);
rt_device_control(*lsm6d_gyro_dev, RT_SENSOR_CTRL_SET_ODR, (void *)1660);
}
}
// 传感器数据采集与打印
static void sensors_loop(rt_device_t ltr303_dev, rt_device_t mmc56x3_dev,
rt_device_t lsm6d_dev, rt_device_t lsm6d_gyro_dev, rt_device_t lsm6d_step_dev)
{
struct rt_sensor_data ltr303, mmc56x3, lsm6d_acce, lsm6d_gyro, lsm6d_step;
rt_size_t res;
res = rt_device_read(ltr303_dev, 0, <r303, 1);
if (res != 1)
rt_kprintf("read data failed!size is %d\n", res);
else
rt_kprintf("light: %d lux\n", ltr303.data.light);
res = rt_device_read(mmc56x3_dev, 0, &mmc56x3, 1);
if (res != 1)
rt_kprintf("read data failed!size is %d\n", res);
else
rt_kprintf("mag, x: %d, y: %d, z: %d\n", mmc56x3.data.mag.x, mmc56x3.data.mag.y, mmc56x3.data.mag.z);
res = rt_device_read(lsm6d_dev, 0, &lsm6d_acce, 1);
if (res != 1)
rt_kprintf("read data failed!size is %d\n", res);
else
rt_kprintf("acce, x: %d, y: %d, z: %d\n", lsm6d_acce.data.acce.x, lsm6d_acce.data.acce.y, lsm6d_acce.data.acce.z);
res = rt_device_read(lsm6d_gyro_dev, 0, &lsm6d_gyro, 1);
if (res != 1)
rt_kprintf("read data failed!size is %d\n", res);
else
rt_kprintf("gyro, x: %d, y: %d, z: %d\n", lsm6d_gyro.data.gyro.x, lsm6d_gyro.data.gyro.y, lsm6d_gyro.data.gyro.z);
res = rt_device_read(lsm6d_step_dev, 0, &lsm6d_step, 1);
if (res != 1)
rt_kprintf("read data failed!size is %d\n", res);
else
rt_kprintf("lsm6d step, step: %d\n", lsm6d_step.data.step);
rt_thread_mdelay(100);
rt_kprintf("\n");
}
// 主函数
int main(void)
{
rt_kprintf("Hello world!\n");
board_io_init();
struct rt_sensor_config cfg;
sensors_init(&cfg);
rt_device_t ltr303_dev, mmc56x3_dev, lsm6d_dev, lsm6d_gyro_dev, lsm6d_step_dev;
open_and_config_devices(<r303_dev, &mmc56x3_dev, &lsm6d_dev, &lsm6d_gyro_dev, &lsm6d_step_dev);
while (1)
{
sensors_loop(ltr303_dev, mmc56x3_dev, lsm6d_dev, lsm6d_gyro_dev, lsm6d_step_dev);
}
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
sensor配置流程
在menuconfig中打开相应传感器和I2C3
scons --board=sf32lb52-lchspi-ulp --menuconfig
然后编译下载即可。