Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
RT-Thread
Sensor_传感器框架
学习笔记
RT-Thread 入门学习笔记:熟悉传感器sensor组件的使用
发布于 2022-01-23 09:52:25 浏览:2793
订阅该版
[tocm] [RT-Thread 入门学习笔记 - 目录](https://club.rt-thread.org/ask/article/3420.html) ## 前言 - RT-Thread有个sensor组件(框架),这个组件是用于把一些物理传感器注册成一个sensor device设备,从而方便上层应用对传感器的数据读取与控制。 - 当然sensor框架开启后,还是需要实例化,并编写应用软件,对传感器进行操作 - 这里不使用具体的【物理传感器】,使用【虚拟传感器】,让sensor先工作起来,熟悉传感器在RT-Thread的使用方法 ## sensor 组件介绍 - 可以直接参考RT-Thread 官方的文档:[sensor 设备](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/sensor/sensor?id=sensor-%e8%ae%be%e5%a4%87) - sensor组件把sensor 抽象成一个设备进行管理,对上层提供标准的rt_device API,从而实现了应用于驱动的解耦。 - 上层应用可以通过一个sensor device的名字,就可以读写传感器,方便实现对传感器的操作。 - 这种分层的设计,看上去相对代码【臃肿】些,实际使用后发现降低了使用各类传感器的难度。 ## 虚拟传感器设备 - 与Linux中的**一切皆文件**的思想类似,RT-Thread使用设备框架进行抽象,也就是设备与文件有某种相似性。 - RT-Thread的rt_device,只是一个框架,采用设计与实现分离的设计,我们就可以注册一些【虚拟设备】,实现平台无关性。 -虚拟设备,也就是底层实现什么都不干,或者说底层实现不依赖具体的【物理外设】,如不依赖具体的串口等这样的外设,不依赖具体的引脚配置等。 - RT-Thread 有个【虚拟传感器】的软件包:`vsensor`,就实现了一些虚拟传感器。 - 使用【虚拟传感器】的好处就是前期可以模拟真实传感器,让上层应用先设计。等底层适配好后,切换起来方便。为真实的传感器驱动设计提供参考模板。 ## 验证平台 - 测试平台:STM32L475 Panora 开发板 - 开启sensor 组件: ![2022-01-23_092812.png](https://oss-club.rt-thread.org/uploads/20220123/1ff8ae8414df4eca65efd95b61fe713d.png) ![2022-01-23_092903.png](https://oss-club.rt-thread.org/uploads/20220123/13f6edd2b7996cf33087ba7a410a394f.png) ![2022-01-23_092929.png](https://oss-club.rt-thread.org/uploads/20220123/653204810d2be2147e9fee0ddc9383c4.png) - vsensor 软件包地址:[https://github.com/RT-Thread-packages/vsensor.git](https://github.com/RT-Thread-packages/vsensor.git) - 我使用gitee做了一个备份地址:[https://gitee.com/zhangsz0516/vsensor](https://gitee.com/zhangsz0516/vsensor) - 这里支持多个虚拟传感器,各个虚拟传感器是独立的,我这里抽出一个加速度传感器来进行验证 ```c #include
#ifdef PKG_USING_VIRTUAL_SENSOR_ACCE #include "sensor.h" #include
#define DBG_TAG "v_acce" #ifdef PKG_USING_VIRTUAL_SENSOR_DBG #define DBG_LVL DBG_LOG #else #define DBG_LVL DBG_INFO #endif #include
enum SENS_ACCE_ID { SENS_ACCE_01 = 0, //Accelerometer SENS_ACCE_MAX, }; #define SENS_BUS_NAME "sens_bus" #define SENS_ACCE_01_SENSOR_ID (RT_SENSOR_CLASS_ACCE + 0x10) struct sens_acce { char* dev_name; rt_uint8_t sens_id; }; static struct sens_acce sens_acce_tbl[SENS_ACCE_MAX] = { {V_SENS_ACCE_DEV_NAME, 0x00 }, /* Accelerometer */ }; static struct rt_sensor_info acce_info_tbl[SENS_ACCE_MAX] = { {RT_SENSOR_CLASS_ACCE, RT_SENSOR_VENDOR_BOSCH, RT_NULL, RT_SENSOR_UNIT_MG, RT_SENSOR_INTF_SPI, 2048, -2048, 1 }, }; static rt_uint8_t sensor_get_id(rt_uint8_t sens_index) { rt_uint8_t chip_id = 0x00; switch (sens_index) { case SENS_ACCE_01: chip_id = SENS_ACCE_01_SENSOR_ID; break; default: break; } return chip_id; } static int sensor_init(rt_uint8_t index) { sens_acce_tbl[index].sens_id = sensor_get_id(index); return RT_EOK; } static void* acce_sensor_create(struct rt_sensor_intf* intf, rt_uint8_t index) { if (sensor_init(index) != RT_EOK) { LOG_E("%s:error!", __func__); } return 0; } static rt_err_t acce_sensor_set_odr(rt_sensor_t sensor, rt_uint16_t odr) { LOG_D("%s:odr=%d", __func__, odr); return RT_EOK; } static rt_err_t acce_sensor_set_range(rt_sensor_t sensor, rt_uint16_t range) { LOG_D("%s:range=%d", __func__, range); return RT_EOK; } static rt_err_t acce_sensor_set_power(rt_sensor_t sensor, rt_uint8_t power) { rt_int8_t rslt = 0; LOG_D("%s:power=%d", __func__, power); return rslt; } static rt_size_t acce_sensor_fetch_data(struct rt_sensor_device* sensor, void* buf, rt_size_t size) { struct rt_sensor_data* data = buf; rt_int16_t max_range = 0; if (size < 1) { LOG_E("%s:read size err! size=%d", __func__, size); return 0; } if (buf == RT_NULL) { LOG_E("%s:read buf is NULL!", __func__); return 0; } max_range = acce_info_tbl[SENS_ACCE_01].range_max - acce_info_tbl[SENS_ACCE_01].range_min; for (int i = 0; i < size; i++) { data->type = RT_SENSOR_CLASS_ACCE; data->data.acce.x = rand() % max_range + acce_info_tbl[SENS_ACCE_01].range_min; data->data.acce.y = rand() % max_range + acce_info_tbl[SENS_ACCE_01].range_min; data->data.acce.z = rand() % max_range + acce_info_tbl[SENS_ACCE_01].range_min; data->timestamp = rt_sensor_get_ts(); LOG_D("%s:%d,%d,%d", __func__, data->data.acce.x, data->data.acce.y, data->data.acce.z); data++; } return size; } static rt_err_t acce_sensor_control(struct rt_sensor_device* sensor, int cmd, void* args) { rt_err_t result = RT_EOK; switch (cmd) { case RT_SENSOR_CTRL_GET_ID: *(rt_uint8_t*)args = sens_acce_tbl[SENS_ACCE_01].sens_id; break; case RT_SENSOR_CTRL_SET_ODR: result = acce_sensor_set_odr(sensor, (rt_uint32_t)args & 0xffff); break; case RT_SENSOR_CTRL_SET_RANGE: result = acce_sensor_set_range(sensor, (rt_uint32_t)args); break; case RT_SENSOR_CTRL_SET_POWER: result = acce_sensor_set_power(sensor, (rt_uint32_t)args & 0xff); break; case RT_SENSOR_CTRL_SELF_TEST: /* TODO */ result = -RT_EINVAL; break; default: return -RT_EINVAL; } return result; } static struct rt_sensor_ops sensor_ops[] = { {acce_sensor_fetch_data, acce_sensor_control}, }; int rt_vd_sens_acce_init(void) { rt_int8_t result; rt_uint8_t index = 0; rt_sensor_t sensor_dat = RT_NULL; struct rt_sensor_config cfg; cfg.intf.dev_name = SENS_BUS_NAME; cfg.intf.user_data = RT_NULL; cfg.irq_pin.pin = RT_PIN_NONE; for (index = 0; index < SENS_ACCE_MAX; index++) { acce_sensor_create(&cfg.intf, index); sensor_dat = rt_calloc(1, sizeof(struct rt_sensor_device)); if (sensor_dat == RT_NULL) { LOG_E("%s:rt_calloc err!", __func__); return -RT_ERROR; } sensor_dat->info.type = acce_info_tbl[index].type; sensor_dat->info.vendor = acce_info_tbl[index].vendor; sensor_dat->info.model = acce_info_tbl[index].model; sensor_dat->info.unit = acce_info_tbl[index].unit; sensor_dat->info.intf_type = acce_info_tbl[index].intf_type; sensor_dat->info.range_max = acce_info_tbl[index].range_max; sensor_dat->info.range_min = acce_info_tbl[index].range_min; sensor_dat->info.period_min = acce_info_tbl[index].period_min; rt_memcpy(&sensor_dat->config, &cfg, sizeof(struct rt_sensor_config)); sensor_dat->ops = &sensor_ops[index]; result = rt_hw_sensor_register(sensor_dat, sens_acce_tbl[index].dev_name, RT_DEVICE_FLAG_RDWR, RT_NULL); if (result != RT_EOK) { LOG_E("%s:device register err code: %d", __func__, result); rt_free(sensor_dat); return -RT_ERROR; } } return RT_EOK; } INIT_DEVICE_EXPORT(rt_vd_sens_acce_init); #endif ``` - 可以根据`vsensor`的软件包,简单更改名称,就可以产生一个新的传感器,通过底层适配,物理传感器就可以工作起来了 ## 调试方法 - 编译下载 ```c \ | / - RT - Thread Operating System / | \ 4.1.0 build Jan 23 2022 08:31:27 2006 - 2021 Copyright by rt-thread team [I/sensor] rt_sensor[acce_accelerometer] init success /* 配置的虚拟传感器初始化 */ [I/sensor] rt_sensor[temp_temperature] init success [I/sensor] rt_sensor[baro_barometer] init success [I/sensor] rt_sensor[gyro_gyroscope] init success [I/sensor] rt_sensor[humi_humidity] init success ``` - 这次先使用sensor组件自带的MSH 串口命令进行 sensor操作,实际操作需要编写应用代码 ```c msh >sensor sensor [OPTION] [PARAM] probe
Probe sensor by given name info Get sensor info sr
Set range to var sm
Set work mode to var sp
Set power mode to var sodr
Set output date rate to var read [num] Read [num] times sensor num default 5 msh >list_device device type ref count -------- -------------------- ---------- humi_hum Sensor Device 0 /* 虚拟传感器设备 */ gyro_gyr Sensor Device 0 /* 虚拟传感器设备 */ baro_bar Sensor Device 0 /* 虚拟传感器设备 */ temp_tem Sensor Device 0 /* 虚拟传感器设备 */ acce_acc Sensor Device 0 /* 虚拟传感器设备 */ uart2 Character Device 0 uart1 Character Device 2 pin Miscellaneous Device 0 msh >sensor probe acce_acc [D/v_acce] acce_sensor_set_power:power=2 [I/sensor.cmd] device id: 0x11! msh >sensor read 5 [D/v_acce] acce_sensor_fetch_data:-1872,-1589,841 [I/sensor.cmd] num: 0, x:-1872, y:-1589, z: 841 mg, timestamp:338658 [D/v_acce] acce_sensor_fetch_data:104,1287,-1211 [I/sensor.cmd] num: 1, x: 104, y: 1287, z:-1211 mg, timestamp:338770 [D/v_acce] acce_sensor_fetch_data:968,1919,-1261 [I/sensor.cmd] num: 2, x: 968, y: 1919, z:-1261 mg, timestamp:338882 [D/v_acce] acce_sensor_fetch_data:1988,-1940,-213 [I/sensor.cmd] num: 3, x: 1988, y:-1940, z: -213 mg, timestamp:338994 [D/v_acce] acce_sensor_fetch_data:954,1633,357 [I/sensor.cmd] num: 4, x: 954, y: 1633, z: 357 mg, timestamp:339106 msh > ``` - 初步验证【虚拟的传感器】工作了,真实的【物理传感器】,使用起来,也是这个思路 ## 小结 - 主要熟悉下传感器sensor 在RT-Thread 中的一种使用方式 - 通过了解虚拟设备,深入了解 Device框架的使用,平台无关的抽象设计思想 - 方便为对接真实【物理传感器】提供方法与模板
4
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
张世争
学以致用
文章
131
回答
802
被采纳
173
关注TA
发私信
相关文章
1
RT-THREAD在STM32H747平台上移植lwip
2
正点原子miniSTM32开发板读写sdcard
3
反馈rtt串口驱动对低功耗串口lpuart1不兼容的问题
4
Keil MDK 移植 RT-Thread Nano
5
RT1061/1052 带 RTT + LWIP和LPSPI,有什么坑要注意吗?
6
RT thread HID 如何收发数据
7
求一份基于RTT系统封装好的STM32F1系列的FLASH操作程序
8
RT-Thread修改项目名称之后不能下载
9
rt-studio编译c++
10
有木有移植rt-thread(nano)到riscv 32位MCU上
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
at_device
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
a1012112796
13
个答案
2
次被采纳
张世争
9
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
本月文章贡献
程序员阿伟
7
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
3
次点赞
ThinkCode
1
篇文章
1
次点赞
Betrayer
1
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部