Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
设备驱动
基于 RT-Thread 的 RoboMaster 电控框架(二)
发布于 2023-09-18 20:50:53 浏览:546
订阅该版
[tocm] # 基于 RT-Thread 的 RoboMaster 电控框架(二) *由于 RT-Thread 稳定高效的内核,丰富的文档教程,积极活跃的社区氛围,以及设备驱动框架、Kconfig、Scons、日志系统、海量的软件包......很难不选择 RT-Thread 进行项目开发。但也正是因为这些优点的覆盖面较广,很多初学者会觉得无从下手,但只要步入 RT-Thread 的大门,你就发现她的美好。这系列文档将作为本人基于 RT-Thread 开发 RoboMaster 电控框架的记录与分享,希望能帮助到更多初识 RT-Thread 的小伙伴,也欢迎大家交流分享,指正不足,共同进步。* ## 背景 使用的开发板为大疆的 RoboMaster-C 型开发板,基础工程为 rt-thread>bsp>stm32f407-robomaster-c ## ist8310磁力计模块开发 ist8310 为 robomaster-c 开发板上集成的三轴磁力计,使用 I2C 通讯,驱动主要参考 [Firmament Autopilot Embedded System](https://github.com/Firmament-Autopilot/FMT-Firmware) 该飞控开源项目中的驱动程序在此基础上进行调整。 ### 添加 I2C 读写 API 首先将飞控程序中针对 RT-Thread 的 I2C 设备驱动封装的 I2C 读写函数借鉴过来: ```c rt_err_t i2c_read_reg(struct rt_i2c_bus_device *bus, uint16_t slave_addr, uint8_t reg, uint8_t* buffer) { rt_size_t ret; struct rt_i2c_msg msgs[2]; msgs[0].addr = slave_addr; msgs[0].flags = RT_I2C_WR | bus->flags; msgs[0].buf = ® msgs[0].len = 1; msgs[1].addr = slave_addr; msgs[1].flags = RT_I2C_RD | bus->flags; msgs[1].buf = buffer; msgs[1].len = 1; ret = rt_i2c_transfer(bus, msgs, 2); return ret == 2 ? RT_EOK : RT_ERROR; } rt_err_t i2c_write_reg(struct rt_i2c_bus_device *bus, uint16_t slave_addr, uint8_t reg, uint8_t val) { rt_size_t ret; rt_uint8_t buffer[2]; struct rt_i2c_msg msgs; buffer[0] = reg; buffer[1] = val; msgs.addr = slave_addr; msgs.flags = RT_I2C_WR | bus->flags; msgs.buf = buffer; msgs.len = 2; ret = rt_i2c_transfer(bus, &msgs, 1); return ret == 1 ? RT_EOK : RT_ERROR; } rt_err_t i2c_read_regs(struct rt_i2c_bus_device *bus, uint16_t slave_addr, uint8_t reg, uint8_t* buffer, uint16_t count) { rt_size_t ret; struct rt_i2c_msg msgs[2]; msgs[0].addr = slave_addr; msgs[0].flags = RT_I2C_WR | bus->flags; msgs[0].buf = ® msgs[0].len = 1; msgs[1].addr = slave_addr; msgs[1].flags = RT_I2C_RD | bus->flags; msgs[1].buf = buffer; msgs[1].len = count; ret = rt_i2c_transfer(bus, msgs, 2); return ret == 2 ? RT_EOK : RT_ERROR; } rt_err_t i2c_write_regs(struct rt_i2c_bus_device *bus, uint16_t slave_addr, uint8_t reg, uint8_t* vals, uint16_t count) { rt_size_t ret; struct rt_i2c_msg msgs[2]; msgs[0].addr = slave_addr; msgs[0].flags = RT_I2C_WR | bus->flags; msgs[0].buf = ® msgs[0].len = 1; msgs[1].addr = slave_addr; msgs[1].flags = RT_I2C_WR | bus->flags; msgs[1].buf = vals; msgs[1].len = count; ret = rt_i2c_transfer(bus, msgs, 2); return ret == 2 ? RT_EOK : RT_ERROR; } ``` BSP 中 STM32 I2C 设备驱动使用的是软件 I2C,于是进入到 menuconfig 中对 I2C 引脚进行配置: ``` /* Notice: PA8 --> 8; PC9 --> 41 */ #define BSP_I2C1_SCL_PIN 8 #define BSP_I2C1_SDA_PIN 41 ``` ### IST8310 驱动 主要就是先对 IST8310 进行初始化,设置相关采样参数,之后就可以读取磁力计的信息了 ```c static rt_err_t mag_raw_measure(int16_t mag[3]) { uint8_t buffer[6]; i2c_read_regs(i2c_bus, IST8310_ADDRESS, REG_DATA_OUT_X_L, buffer, sizeof(buffer)); /* swap the data */ mag[0] = ((int16_t)buffer[1] << 8) | (int16_t)buffer[0]; mag[1] = ((int16_t)buffer[3] << 8) | (int16_t)buffer[2]; mag[2] = ((int16_t)buffer[5] << 8) | (int16_t)buffer[4]; /* start next measurement */ // i2c_write_reg(i2c_bus, IST8310_ADDRESS, REG_CTRL1, CTRL1_ODR_SINGLE)); return RT_EOK; } static rt_err_t mag_measure(float mag[3]) { int16_t raw[3]; mag_raw_measure(raw); mag[0] = _range_scale * raw[0]; mag[1] = _range_scale * raw[1]; mag[2] = _range_scale * raw[2]; ist8310_rotate_to_frd(mag); if (ist8310_user_calibrate != RT_NULL) { /* do user defined calibration */ ist8310_user_calibrate(mag); } return RT_EOK; } ``` 其中 i`st8310_user_calibrate` 和 `ist8310_rotate_to_frd` 为预留的虚函数,用户可根据校准及转化需求,自行定义实现。 ```c __attribute__((weak)) void ist8310_user_calibrate(float data[3]); /* Re-implement this function to define customized rotation */ __attribute__((weak)) void ist8310_rotate_to_frd(float* data); ``` ### 抽象设备 为提高程序的模块化,选用不同传感器时的灵活性,将 ist8310 抽象为 mag 一类设备,抽象出 mag_init 和 mag_read 两个操作方法。 ```c struct mag_ops{ rt_err_t (*mag_init)(const char* i2c_bus_name); rt_err_t (*mag_read)(float data[3]); }; ``` 项目选用不同的磁力计传感器时,对接这两个接口即可,以 ist8310 为例: ```c /** * @brief 调用此函数初始化 ist8310 * * @param i2c_bus_name ist8310 所挂载的总线名称 * * @return RT_EOK */ static rt_err_t drv_ist8310_init(const char* i2c_bus_name); /** * @brief 调用此函数读取 ist8310 数据 * * @param data[3] 存储读取数据的数组 * * @return 读取成功 RT_EOK ; 读取失败 -RT_ERROR */ static rt_err_t ist8310_read(float data[3]); struct mag_ops mag = { .mag_init = drv_ist8310_init, .mag_read = ist8310_read, }; ``` 应用层需要使用磁力计时,调用 mag_ops 中的操作方法即可: ```c static float read_data[3]; mag.mag_init("i2c1"); // 初始化 mag 设备 mag.mag_read(read_data); // 将设备数据读取到 read_data 中 ``` 到此就可以方便的使用磁力计模块啦 仓库地址放这里了 [HNU_RM_SHARK_C ](https://github.com/Z8MAN8/HNU_RM_SHARK_C) ,觉得不错可以点个 Star ! 感谢阿木实验室开源的基于 RT-Thread 的飞控程序! ## 存在问题及优化方向 1. 目前为了提高性能,mag设备的注册对接形式是比较简陋的。 1. 后续考虑能不能也优化为,read,write,control 等形式。
0
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
螺丝松掉的人
这家伙很懒,什么也没写!
文章
42
回答
0
被采纳
0
关注TA
发私信
相关文章
1
让成员函数能作为rt_device中的回调函数
2
关于设备配置时延时的处理
3
rt_device_set_rx_indicate设置的回调如何传递参数?
4
关于 输入捕获 驱动的
5
关于设备驱动的迷茫与疑惑
6
关于rtthread中各种驱动的问题
7
drv_hwtimer 和hwtimer关系是啥?
8
RTT有没有接口文档,可以用于写一些自己创建的设备的这些文档?
9
i2c设备驱动为什么没有速率设置
10
UART设备中断接收及轮询发送
推荐文章
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
UART
WIZnet_W5500
ota在线升级
PWM
cubemx
flash
freemodbus
BSP
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
rt_mq_消息队列_msg_queue
SFUD
msh
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1444
个答案
290
次被采纳
张世争
812
个答案
177
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
2
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
2
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部