Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
I2C_IIC
mpu6050
瑞萨_RA6M4
【Renesas RA6M4开发板之I2C读取mpu6050】
发布于 2022-07-14 09:42:21 浏览:759
订阅该版
[tocm] # 1.0 mpu6050 ![在这里插入图片描述](https://oss-club.rt-thread.org/uploads/20220714/70b0703d5cc8a5224b754c4dfb370d31755c6285.png) **此图转载钦源盛数码专营店** *本篇通过Renesas RA6M4开发板采用I2C读取mpu6050传感器的角加速度,角速度和温度示例程序演示。* ## 1.1 mpu6050介绍 MPU6050是一种非常流行的空间运动传感器芯片,可以获取器件当前的三个加速度分量和三个旋转角速度。由于其体积小巧,功能强大,精度较高,不仅被广泛应用于工业,同时也是航模爱好者的神器,被安装在各类飞行器上驰骋蓝天。 ## 1.2 mpu6050特点 使用芯片:MPU-6050 供电电源:3-5V(内部低压差稳压) 通信方式:标准lIC通信协议 芯片内置16BITAD转换器,16位数据输出 陀螺仪范围:±250 500 1000 2000 °/s 加速度范围:±2±4±8±16G 温度范围:-20℃~60℃ 采用沉金PCB,机器焊接工艺保证质量 引脚间距2.54MM 需在气体环境中工作,不可测量液体和反接电源😅😅😅 ![在这里插入图片描述](https://oss-club.rt-thread.org/uploads/20220714/66876ed671aec16547d6e12bfe0185d7a2cd1978.png) 尺寸大小如下: ![在这里插入图片描述](https://oss-club.rt-thread.org/uploads/20220714/e3c2f9d8018e1c043cd9603f0ce4123de88797cf.png) ## 1.3 mpu6050应用 运动感测游戏 现实增强 行人导航器 “零触控”手势用户接口 姿势快捷方式 认证 电子稳像(EIS: Electronic lmage Stabilization ) 光学稳像(Ols: Optical lmage Stabilization ) ![在这里插入图片描述](https://oss-club.rt-thread.org/uploads/20220714/028475f44ba54bfeea3888d237a5cf9f2cdd2c26.png) # 2. RT-theard配置 ## 2.1 硬件需求 1、需要mpu6050采集气体环境下的气压和温度,I2C通讯接线**SDA---p504;SCL---p506**,不需要关注地址后面库自带配置了,与[ssd1306](https://blog.csdn.net/VOR234/article/details/125742886)不同 > 实现功能: > 采用I2C读取mpu6050传感器的角加速度,角速度和温度示例 2、RA6M4开发板 ![在这里插入图片描述](https://oss-club.rt-thread.org/uploads/20220714/666c70553be11f37c54e2fd5b12b1dd1dae10084.png) 3、USB下载线,ch340串口和附带6根母母线,**rx---p613;tx---p614** ![在这里插入图片描述](https://oss-club.rt-thread.org/uploads/20220714/98e11daca09e512aefc23097ca397b904a2e8a6e.png) ## 2.2 软件配置 Renesas RA6M4开发板环境配置参照:[【基于 RT-Thread Studio的CPK-RA6M4 开发板环境搭建】](https://blog.csdn.net/vor234/article/details/125634313) 1、新建项目RA6M4-mpu6050工程 ![在这里插入图片描述](https://oss-club.rt-thread.org/uploads/20220714/2fde10759598c867eb0248d0b71709f9a78da8f3.png) 2、点击RT-theard Setting,在软件包下添加软件包,然后搜索mpu相关软件支持包,点击添加即可,然后出现对应包。 ![在这里插入图片描述](https://oss-club.rt-thread.org/uploads/20220714/96271a3ccbded4db477ffe56495aa037bc70cd81.png) 3、配置ssd306,右键选择配置项 ![在这里插入图片描述](https://oss-club.rt-thread.org/uploads/20220714/0d6025783821ac5db2c5b515d449d7de53ca26fd.png) 4、在软件包中开启示例程序。 ![在这里插入图片描述](https://oss-club.rt-thread.org/uploads/20220714/70949939ad3529de2b58cfb14d611886133ec237.png) 5、在硬件中,启动I2C,设置端口SDA---p505;SCL---p506 ![在这里插入图片描述](https://oss-club.rt-thread.org/uploads/20220714/9ca0cdc003ebd454ae407a889a63abc539ec0a4b.png) 6、全部保存刚刚的配置,更新当前配置文件 **保存完是灰色,没有保存是蓝色。** # 3. 代码分析 1、刚刚加载软件包在packages文件夹下, ![在这里插入图片描述](https://oss-club.rt-thread.org/uploads/20220714/43e0a99ca736dddc95fafc3322aa426d114ceca3.png) mpu6xxx.c代码更改为如下 (或者头文件添加`#include "bsp_api.h"`,否则会报错`unitx_t`,根据提示全部改为`rt_unitx_t`也OK,下面是第二种方法,增加了手动校准)😅😅😅 *mpu6xxx.c* ```cpp /* * Copyright (c) 2006-2022, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2018-10-23 flybreak the first version * 2021-09-09 scratch-er added setting and getting sensor offsets */ #include
#include
#include
#include
#define DBG_TAG "mpu6xxx" #define DBG_LVL DBG_INFO #include
#include "mpu6xxx.h" #include "mpu6xxx_reg.h" #ifdef PKG_USING_MPU6XXX_MAG #include "ak8963_reg.h" #endif #define MPU6XXX_ACCEL_SEN (16384) #define MPU6XXX_GYRO_SEN (1310) #define MPU60X0_SPI_MAX_SPEED (1000 * 1000) #define MPU60X0_TEMP_SEN (340) #define MPU60X0_TEMP_OFFSET (36.5) #define MPU6500_TEMP_SEN (333.87) #define MPU6500_TEMP_OFFSET (21) // MAG #define AK8963_RANGE (4912) #define AK8963_FULLSCALE (32760) /** * This function writes the value of the register for mpu6xxx * * @param dev the pointer of device driver structure * @param reg the register for mpu6xxx * @param data value to write * * @return the writing status, RT_EOK reprensents writing the value of the register successfully. */ static rt_err_t mpu6xxx_write_reg(struct mpu6xxx_device *dev, rt_uint8_t reg, rt_uint8_t data) { rt_int8_t res = 0; #ifdef RT_USING_I2C struct rt_i2c_msg msgs; rt_uint8_t buf[2] = {reg, data}; #endif if (dev->bus->type == RT_Device_Class_I2CBUS) { #ifdef RT_USING_I2C msgs.addr = dev->i2c_addr; /* slave address */ msgs.flags = RT_I2C_WR; /* write flag */ msgs.buf = buf; /* Send data pointer */ msgs.len = 2; if (rt_i2c_transfer((struct rt_i2c_bus_device *)dev->bus, &msgs, 1) == 1) { res = RT_EOK; } else { res = -RT_ERROR; } #endif } else { #ifdef RT_USING_SPI res = rt_spi_send_then_send((struct rt_spi_device *)dev->bus, ®, 1, &data, 1); #endif } return res; } /** * This function reads the value of registers for mpu6xxx * * @param dev the pointer of device driver structure * @param reg the register for mpu6xxx * @param len number of register * @param buf read data pointer * * @return the reading status, RT_EOK reprensents reading the value of registers successfully. */ static rt_err_t mpu6xxx_read_regs(struct mpu6xxx_device *dev, rt_uint8_t reg, rt_uint8_t len, rt_uint8_t *buf) { rt_int8_t res = 0; #ifdef RT_USING_I2C struct rt_i2c_msg msgs[2]; #endif #ifdef RT_USING_SPI rt_uint8_t tmp; #endif if (dev->bus->type == RT_Device_Class_I2CBUS) { #ifdef RT_USING_I2C msgs[0].addr = dev->i2c_addr; /* Slave address */ msgs[0].flags = RT_I2C_WR; /* Write flag */ msgs[0].buf = ® /* Slave register address */ msgs[0].len = 1; /* Number of bytes sent */ msgs[1].addr = dev->i2c_addr; /* Slave address */ msgs[1].flags = RT_I2C_RD; /* Read flag */ msgs[1].buf = buf; /* Read data pointer */ msgs[1].len = len; /* Number of bytes read */ if (rt_i2c_transfer((struct rt_i2c_bus_device *)dev->bus, msgs, 2) == 2) { res = RT_EOK; } else { res = -RT_ERROR; } #endif } else { #ifdef RT_USING_SPI //The first bit of the first byte contains the Read/Write bit and indicates the Read (1) or Write (0) operation. tmp = reg | 0x80; res = rt_spi_send_then_recv((struct rt_spi_device *)dev->bus, &tmp, 1, buf, len); #endif } return res; } /** * This function writes a bit value of registers for mpu6xxx * * @param dev the pointer of device driver structure * @param reg the register for mpu6xxx * @param bit the position of the register * @param data value to write * * @return the writing status, RT_EOK reprensents writing a bit value of registers successfully. */ static rt_err_t mpu6xxx_write_bit(struct mpu6xxx_device *dev, rt_uint8_t reg, rt_uint8_t bit, rt_uint8_t data) { rt_uint8_t byte; rt_err_t res; res = mpu6xxx_read_regs(dev, reg, 1, &byte); if (res != RT_EOK) { return res; } byte = (data != 0) ? (byte | (1 << bit)) : (byte & ~(1 << bit)); return mpu6xxx_write_reg(dev, reg, byte); } /** * This function reads a bit value of registers for mpu6xxx * * @param dev the pointer of device driver structure * @param reg the register for mpu6xxx * @param bit the position of the register * @param data read data pointer * * @return the reading status, RT_EOK reprensents reading a bit value of registers successfully. */ static rt_err_t mpu6xxx_read_bit(struct mpu6xxx_device *dev, rt_uint8_t reg, rt_uint8_t bit, rt_uint8_t *data) { rt_uint8_t byte; rt_err_t res; res = mpu6xxx_read_regs(dev, reg, 1, &byte); if (res != RT_EOK) { return res; } *data = byte & (1 << bit); return RT_EOK; } /** * This function writes multi-bit value of registers for mpu6xxx * * @param dev the pointer of device driver structure * @param reg the register for mpu6xxx * @param start_bit the start position of the register * @param len number of bits to write * @param data value to write * * @return the writing status, RT_EOK reprensents writing multi-bit value of registers successfully. */ static rt_err_t mpu6xxx_write_bits(struct mpu6xxx_device *dev, rt_uint8_t reg, rt_uint8_t start_bit, rt_uint8_t len, rt_uint8_t data) { rt_uint8_t byte, mask; rt_err_t res; res = mpu6xxx_read_regs(dev, reg, 1, &byte); if (res != RT_EOK) { return res; } mask = ((1 << len) - 1) << (start_bit - len + 1); data <<= (start_bit - len + 1); // shift data into correct position data &= mask; // zero all non-important bits in data byte &= ~(mask); // zero all important bits in existing byte byte |= data; // combine data with existing byte return mpu6xxx_write_reg(dev, reg, byte); } /** * This function reads multi-bit value of registers for mpu6xxx * * @param dev the pointer of device driver structure * @param reg the register for mpu6xxx * @param start_bit the start position of the register * @param len number of bits to write * @param data read data pointer * * @return the reading status, RT_EOK reprensents reading multi-bit value of registers successfully. */ static rt_err_t mpu6xxx_read_bits(struct mpu6xxx_device *dev, rt_uint8_t reg, rt_uint8_t start_bit, rt_uint8_t len, rt_uint8_t *data) { rt_uint8_t byte, mask; rt_err_t res; res = mpu6xxx_read_regs(dev, reg, 1, &byte); if (res != RT_EOK) { return res; } mask = ((1 << len) - 1) << (start_bit - len + 1); byte &= mask; byte >>= (start_bit - len + 1); *data = byte; return RT_EOK; } // MAG #ifdef PKG_USING_MPU6XXX_MAG #define MAG_READ_DELAY_TIME 50 static void mpu92_mag_write_reg(struct mpu6xxx_device *dev, rt_uint8_t addr, rt_uint8_t data) { rt_uint8_t status = 0; rt_uint32_t timeout = MAG_READ_DELAY_TIME; mpu6xxx_write_reg(dev, MPU6XXX_RA_I2C_SLV4_ADDR, AK8963_I2C_ADDR); mpu6xxx_write_reg(dev, MPU6XXX_RA_I2C_SLV4_REG, addr); mpu6xxx_write_reg(dev, MPU6XXX_RA_I2C_SLV4_DO, data); mpu6xxx_write_reg(dev, MPU6XXX_RA_I2C_SLV4_CTRL, MPU6500_I2C_SLVx_EN); do { mpu6xxx_read_regs(dev, MPU6XXX_RA_I2C_MST_STATUS, 1, &status); rt_thread_mdelay(1); } while (((status & MPU6500_I2C_SLV4_DONE) == 0) && (timeout--)); } #endif // PKG_USING_MPU6XXX_MAG /** * This function gets the raw data of the accelerometer * * @param dev the pointer of device driver structure * @param accel the pointer of 3axes structure for receive data * * @return the reading status, RT_EOK reprensents reading the data successfully. */ static rt_err_t mpu6xxx_get_accel_raw(struct mpu6xxx_device *dev, struct mpu6xxx_3axes *accel) { rt_uint8_t buffer[6]; rt_err_t res; res = mpu6xxx_read_regs(dev, MPU6XXX_RA_ACCEL_XOUT_H, 6, buffer); if (res != RT_EOK) { return res; } accel->x = ((rt_uint16_t)buffer[0] << 8) + buffer[1]; accel->y = ((rt_uint16_t)buffer[2] << 8) + buffer[3]; accel->z = ((rt_uint16_t)buffer[4] << 8) + buffer[5]; return RT_EOK; } /** * This function gets the raw data of the gyroscope * * @param dev the pointer of device driver structure * @param gyro the pointer of 3axes structure for receive data * * @return the reading status, RT_EOK reprensents reading the data successfully. */ static rt_err_t mpu6xxx_get_gyro_raw(struct mpu6xxx_device *dev, struct mpu6xxx_3axes *gyro) { rt_uint8_t buffer[6]; rt_err_t res; res = mpu6xxx_read_regs(dev, MPU6XXX_RA_GYRO_XOUT_H, 6, buffer); if (res != RT_EOK) { return res; } gyro->x = ((rt_uint16_t)buffer[0] << 8) + buffer[1]; gyro->y = ((rt_uint16_t)buffer[2] << 8) + buffer[3]; gyro->z = ((rt_uint16_t)buffer[4] << 8) + buffer[5]; return RT_EOK; } #ifdef PKG_USING_MPU6XXX_MAG /** * This function gets the raw data of the magnetometer * * @param dev the pointer of device driver structure * @param mag the pointer of 3axes structure for receive data * * @return the reading status, RT_EOK reprensents reading the data successfully. */ static rt_err_t mpu6xxx_get_mag_raw(struct mpu6xxx_device *dev, struct mpu6xxx_3axes *mag) { rt_uint8_t buffer[8]; rt_err_t res; res = mpu6xxx_read_regs(dev, MPU6XXX_RA_EXT_SENS_DATA_00, 8, buffer); if (res != RT_EOK) { return res; } mag->x = ((rt_uint16_t)buffer[2] << 8) + buffer[1]; mag->y = ((rt_uint16_t)buffer[4] << 8) + buffer[3]; mag->z = ((rt_uint16_t)buffer[6] << 8) + buffer[5]; return RT_EOK; } #endif /** * This function gets the raw data of the temperature * * @param dev the pointer of device driver structure * @param temp read data pointer * * @return the reading status, RT_EOK reprensents reading the data successfully. */ static rt_err_t mpu6xxx_get_temp_raw(struct mpu6xxx_device *dev, rt_int16_t *temp) { rt_uint8_t buffer[2]; rt_err_t res; res = mpu6xxx_read_regs(dev, MPU6XXX_RA_TEMP_OUT_H, 2, buffer); if (res != RT_EOK) { return res; } *temp = ((rt_uint16_t)buffer[0] << 8) + buffer[1]; return RT_EOK; } /** * This function gets mpu6xxx parameters. * * @param dev the pointer of device driver structure * @param cmd Configuration item * @param param read data pointer * * @return the reading status, RT_EOK reprensents reading the data successfully. */ static rt_err_t mpu6xxx_get_param(struct mpu6xxx_device *dev, enum mpu6xxx_cmd cmd, rt_uint16_t *param) { rt_uint8_t data = 0; rt_err_t res = RT_EOK; RT_ASSERT(dev); switch (cmd) { case MPU6XXX_GYRO_RANGE: /* Gyroscope full scale range */ res = mpu6xxx_read_bits(dev, MPU6XXX_RA_GYRO_CONFIG, MPU6XXX_GCONFIG_FS_SEL_BIT, MPU6XXX_GCONFIG_FS_SEL_LENGTH, &data); *param = data; break; case MPU6XXX_ACCEL_RANGE: /* Accelerometer full scale range */ res = mpu6xxx_read_bits(dev, MPU6XXX_RA_ACCEL_CONFIG, MPU6XXX_ACONFIG_AFS_SEL_BIT, MPU6XXX_ACONFIG_AFS_SEL_LENGTH, &data); *param = data; break; case MPU6XXX_DLPF_CONFIG: /* Digital Low Pass Filter */ res = mpu6xxx_read_bits(dev, MPU6XXX_RA_CONFIG, MPU6XXX_CFG_DLPF_CFG_BIT, MPU6XXX_CFG_DLPF_CFG_LENGTH, &data); *param = data; break; case MPU6XXX_SAMPLE_RATE: /* Sample Rate */ /* Sample Rate = Gyroscope Output Rate / (1 + SMPLRT_DIV) */ res = mpu6xxx_read_bits(dev, MPU6XXX_RA_CONFIG, MPU6XXX_CFG_DLPF_CFG_BIT, MPU6XXX_CFG_DLPF_CFG_LENGTH, &data); if (res != RT_EOK) { break; } if (data == 0 || data == 7) /* dlpf is disable */ { res = mpu6xxx_read_regs(dev, MPU6XXX_RA_SMPLRT_DIV, 1, &data); *param = 8000 / (data + 1); } else /* dlpf is enable */ { res = mpu6xxx_read_regs(dev, MPU6XXX_RA_SMPLRT_DIV, 1, &data); *param = 1000 / (data + 1); } break; case MPU6XXX_SLEEP: /* sleep mode */ res = mpu6xxx_read_bit(dev, MPU6XXX_RA_PWR_MGMT_1, MPU6XXX_PWR1_SLEEP_BIT, &data); *param = data; break; } return res; } /** * This function set mpu6xxx parameters. * * @param dev the pointer of device driver structure * @param cmd Configuration item * @param param Configuration item parameter * * @return the setting status, RT_EOK reprensents setting the parameter successfully. */ rt_err_t mpu6xxx_set_param(struct mpu6xxx_device *dev, enum mpu6xxx_cmd cmd, rt_uint16_t param) { rt_uint8_t data = 0; rt_err_t res = RT_EOK; RT_ASSERT(dev); switch (cmd) { case MPU6XXX_GYRO_RANGE: /* Gyroscope full scale range */ res = mpu6xxx_write_bits(dev, MPU6XXX_RA_GYRO_CONFIG, MPU6XXX_GCONFIG_FS_SEL_BIT, MPU6XXX_GCONFIG_FS_SEL_LENGTH, param); dev->config.gyro_range = param; break; case MPU6XXX_ACCEL_RANGE: /* Accelerometer full scale range */ res = mpu6xxx_write_bits(dev, MPU6XXX_RA_ACCEL_CONFIG, MPU6XXX_ACONFIG_AFS_SEL_BIT, MPU6XXX_ACONFIG_AFS_SEL_LENGTH, param); dev->config.accel_range = param; break; case MPU6XXX_DLPF_CONFIG: /* Digital Low Pass Filter */ res = mpu6xxx_write_bits(dev, MPU6XXX_RA_CONFIG, MPU6XXX_CFG_DLPF_CFG_BIT, MPU6XXX_CFG_DLPF_CFG_LENGTH, param); break; case MPU6XXX_SAMPLE_RATE: /* Sample Rate = 16-bit unsigned value. Sample Rate = [1000 - 4]HZ when dlpf is enable Sample Rate = [8000 - 32]HZ when dlpf is disable */ //Sample Rate = Gyroscope Output Rate / (1 + SMPLRT_DIV) res = mpu6xxx_read_bits(dev, MPU6XXX_RA_CONFIG, MPU6XXX_CFG_DLPF_CFG_BIT, MPU6XXX_CFG_DLPF_CFG_LENGTH, &data); if (res != RT_EOK) { break; } if (data == 0 || data == 7) /* dlpf is disable */ { if (param > 8000) data = 0; else if (param < 32) data = 0xFF; else data = 8000 / param - 1; } else /* dlpf is enable */ { if (param > 1000) data = 0; else if (param < 4) data = 0xFF; else data = 1000 / param - 1; } res = mpu6xxx_write_reg(dev, MPU6XXX_RA_SMPLRT_DIV, data); break; case MPU6XXX_SLEEP: /* Configure sleep mode */ res = mpu6xxx_write_bit(dev, MPU6XXX_RA_PWR_MGMT_1, MPU6XXX_PWR1_SLEEP_BIT, param); break; } return res; } /** * This function gets the data of the accelerometer, unit: mg(mm/s^2) * * @param dev the pointer of device driver structure * @param accel the pointer of 3axes structure for receive data * * @return the reading status, RT_EOK reprensents reading the data successfully. */ rt_err_t mpu6xxx_get_accel(struct mpu6xxx_device *dev, struct mpu6xxx_3axes *accel) { struct mpu6xxx_3axes tmp; rt_uint16_t sen; rt_err_t res; res = mpu6xxx_get_accel_raw(dev, &tmp); if (res != RT_EOK) { return res; } sen = MPU6XXX_ACCEL_SEN >> dev->config.accel_range; accel->x = (rt_int32_t)tmp.x * 1000 / sen; accel->y = (rt_int32_t)tmp.y * 1000 / sen; accel->z = (rt_int32_t)tmp.z * 1000 / sen; return RT_EOK; } /** * This function gets the data of the gyroscope, unit: deg/10s * Here deg/10s means 10 times higher precision than deg/s. * * @param dev the pointer of device driver structure * @param gyro the pointer of 3axes structure for receive data * * @return the reading status, RT_EOK reprensents reading the data successfully. */ rt_err_t mpu6xxx_get_gyro(struct mpu6xxx_device *dev, struct mpu6xxx_3axes *gyro) { struct mpu6xxx_3axes tmp; rt_uint16_t sen; rt_err_t res; res = mpu6xxx_get_gyro_raw(dev, &tmp); if (res != RT_EOK) { return res; } sen = MPU6XXX_GYRO_SEN >> dev->config.gyro_range; gyro->x = (rt_int32_t)tmp.x * 100 / sen; gyro->y = (rt_int32_t)tmp.y * 100 / sen; gyro->z = (rt_int32_t)tmp.z * 100 / sen; return RT_EOK; } #ifdef PKG_USING_MPU6XXX_MAG /** * This function gets the data of the magnetometer, unit: uT * * @param dev the pointer of device driver structure * @param gyro the pointer of 3axes structure for receive data * * @return the reading status, RT_EOK reprensents reading the data successfully. */ rt_err_t mpu6xxx_get_mag(struct mpu6xxx_device *dev, struct mpu6xxx_3axes *mag) { struct mpu6xxx_3axes tmp; rt_err_t res; res = mpu6xxx_get_mag_raw(dev, &tmp); if (res != RT_EOK) { return res; } mag->x = ((rt_int32_t)tmp.x * AK8963_RANGE) / AK8963_FULLSCALE; mag->y = ((rt_int32_t)tmp.y * AK8963_RANGE) / AK8963_FULLSCALE; mag->z = ((rt_int32_t)tmp.z * AK8963_RANGE) / AK8963_FULLSCALE; return RT_EOK; } #endif /** * This function gets the data of the temperature, unit: Centigrade * * @param dev the pointer of device driver structure * @param temp read data pointer * * @return the reading status, RT_EOK reprensents reading the data successfully. */ rt_err_t mpu6xxx_get_temp(struct mpu6xxx_device *dev, float *temp) { rt_int16_t tmp; rt_err_t res; res = mpu6xxx_get_temp_raw(dev, &tmp); if (res != RT_EOK) { return res; } if (dev->id == MPU6050_WHO_AM_I) { /* mpu60x0: Temperature in degrees C = (TEMP_OUT Register Value as a signed quantity)/340 + 36.53 */ *temp = (double)tmp / MPU60X0_TEMP_SEN + MPU60X0_TEMP_OFFSET; } else { /* mpu6500: ((TEMP_OUT - RoomTemp_Offset)/Temp_Sensitivity)+ 21degC */ *temp = (double)tmp / MPU6500_TEMP_SEN + MPU6500_TEMP_OFFSET; } return RT_EOK; } /** * This function sets the offset of the accelerometer * * @param dev the pointer of device driver structure * @param offset the pointer of 3axes structure of offsets * * @return the setting status, RT_EOK reprensents setting the offsets successfully. */ rt_err_t mpu6xxx_set_accel_offset(struct mpu6xxx_device *dev, struct mpu6xxx_3axes *offset) { rt_err_t res=0; res |= mpu6xxx_write_reg(dev, MPU6XXX_RA_XA_OFFS_H, (offset->x)>>8); res |= mpu6xxx_write_reg(dev, MPU6XXX_RA_XA_OFFS_L_TC, (offset->x)&0x00ff); res |= mpu6xxx_write_reg(dev, MPU6XXX_RA_YA_OFFS_H, (offset->y)>>8); res |= mpu6xxx_write_reg(dev, MPU6XXX_RA_YA_OFFS_L_TC, (offset->y)&0x00ff); res |= mpu6xxx_write_reg(dev, MPU6XXX_RA_ZA_OFFS_H, (offset->z)>>8); res |= mpu6xxx_write_reg(dev, MPU6XXX_RA_ZA_OFFS_L_TC, (offset->z)&0x00ff); return res; } /** * This function gets the offset of the accelerometer * * @param dev the pointer of device driver structure * @param offset the pointer of 3axes structure of offsets * * @return the setting status, RT_EOK reprensents reading the offsets successfully. */ rt_err_t mpu6xxx_get_accel_offset(struct mpu6xxx_device *dev, struct mpu6xxx_3axes *offset) { rt_uint8_t buffer[6]; rt_err_t res; res = mpu6xxx_read_regs(dev, MPU6XXX_RA_XA_OFFS_H, 6, buffer); if (res != RT_EOK) { return res; } offset->x = ((rt_uint16_t)buffer[0] << 8) + buffer[1]; offset->y = ((rt_uint16_t)buffer[2] << 8) + buffer[3]; offset->z = ((rt_uint16_t)buffer[4] << 8) + buffer[5]; return RT_EOK; } /** * This function sets the offset of the gyroscope * * @param dev the pointer of device driver structure * @param offset the pointer of 3axes structure of offsets * * @return the setting status, RT_EOK reprensents setting the offsets successfully. */ rt_err_t mpu6xxx_set_gyro_offset(struct mpu6xxx_device *dev, struct mpu6xxx_3axes *offset) { rt_err_t res=0; res |= mpu6xxx_write_reg(dev, MPU6XXX_RA_XG_OFFS_USRH, (offset->x)>>8); res |= mpu6xxx_write_reg(dev, MPU6XXX_RA_XG_OFFS_USRL, (offset->x)&0x00ff); res |= mpu6xxx_write_reg(dev, MPU6XXX_RA_YG_OFFS_USRH, (offset->y)>>8); res |= mpu6xxx_write_reg(dev, MPU6XXX_RA_YG_OFFS_USRL, (offset->y)&0x00ff); res |= mpu6xxx_write_reg(dev, MPU6XXX_RA_ZG_OFFS_USRH, (offset->z)>>8); res |= mpu6xxx_write_reg(dev, MPU6XXX_RA_ZG_OFFS_USRL, (offset->z)&0x00ff); return res; } /** * This function gets the offset of the gyroscope * * @param dev the pointer of device driver structure * @param offset the pointer of 3axes structure of offsets * * @return the setting status, RT_EOK reprensents reading the offsets successfully. */ rt_err_t mpu6xxx_get_gyro_offset(struct mpu6xxx_device *dev, struct mpu6xxx_3axes *offset) { rt_uint8_t buffer[6]; rt_err_t res; res = mpu6xxx_read_regs(dev, MPU6XXX_RA_XG_OFFS_USRH, 6, buffer); if (res != RT_EOK) { return res; } offset->x = ((rt_uint16_t)buffer[0] << 8) + buffer[1]; offset->y = ((rt_uint16_t)buffer[2] << 8) + buffer[3]; offset->z = ((rt_uint16_t)buffer[4] << 8) + buffer[5]; return RT_EOK; } /** * This function initialize the mpu6xxx device. * * @param dev_name the name of transfer device * @param param the i2c device address for i2c communication, RT_NULL for spi * * @return the pointer of device driver structure, RT_NULL reprensents initialization failed. */ struct mpu6xxx_device *mpu6xxx_init(const char *dev_name, rt_uint8_t param) { struct mpu6xxx_device *dev = RT_NULL; rt_uint8_t reg = 0xFF, res = RT_EOK; RT_ASSERT(dev_name); dev = rt_calloc(1, sizeof(struct mpu6xxx_device)); if (dev == RT_NULL) { LOG_E("Can't allocate memory for mpu6xxx device on '%s' ", dev_name); goto __exit; } dev->bus = rt_device_find(dev_name); if (dev->bus == RT_NULL) { LOG_E("Can't find device:'%s'", dev_name); goto __exit; } if (dev->bus->type == RT_Device_Class_I2CBUS) { if (param != RT_NULL) { dev->i2c_addr = param; } else { /* find mpu6xxx device at address: 0x68 */ dev->i2c_addr = MPU6XXX_ADDRESS_AD0_LOW; if (mpu6xxx_read_regs(dev, MPU6XXX_RA_WHO_AM_I, 1, ®) != RT_EOK) { /* find mpu6xxx device at address 0x69 */ dev->i2c_addr = MPU6XXX_ADDRESS_AD0_HIGH; if (mpu6xxx_read_regs(dev, MPU6XXX_RA_WHO_AM_I, 1, ®) != RT_EOK) { LOG_E("Can't find device at '%s'!", dev_name); goto __exit; } } LOG_D("Device i2c address is:'0x%x'!", dev->i2c_addr); } } else if (dev->bus->type == RT_Device_Class_SPIDevice) { #ifdef RT_USING_SPI struct rt_spi_configuration cfg; cfg.data_width = 8; cfg.mode = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB; cfg.max_hz = MPU60X0_SPI_MAX_SPEED; /* Set spi max speed */ rt_spi_configure((struct rt_spi_device *)dev->bus, &cfg); #endif } else { LOG_E("Unsupported device:'%s'!", dev_name); goto __exit; } if (mpu6xxx_read_regs(dev, MPU6XXX_RA_WHO_AM_I, 1, ®) != RT_EOK) { LOG_E("Failed to read device id!"); goto __exit; } dev->id = reg; switch (dev->id) { case MPU6050_WHO_AM_I: LOG_I("Find device: mpu6050!"); break; case MPU6500_WHO_AM_I: LOG_I("Find device: mpu6500!"); break; case MPU9250_WHO_AM_I: LOG_I("Find device: mpu9250!"); break; case ICM20608G_WHO_AM_I: case ICM20608D_WHO_AM_I: LOG_I("Find device: icm20608!"); break; case 0xFF: LOG_E("No device connection!"); goto __exit; default: LOG_W("Unknown device id: 0x%x!", reg); } res += mpu6xxx_get_param(dev, MPU6XXX_ACCEL_RANGE, &dev->config.accel_range); res += mpu6xxx_get_param(dev, MPU6XXX_GYRO_RANGE, &dev->config.gyro_range); res += mpu6xxx_write_bits(dev, MPU6XXX_RA_PWR_MGMT_1, MPU6XXX_PWR1_CLKSEL_BIT, MPU6XXX_PWR1_CLKSEL_LENGTH, MPU6XXX_CLOCK_PLL_XGYRO); res += mpu6xxx_set_param(dev, MPU6XXX_GYRO_RANGE, MPU6XXX_GYRO_RANGE_250DPS); res += mpu6xxx_set_param(dev, MPU6XXX_ACCEL_RANGE, MPU6XXX_ACCEL_RANGE_2G); res += mpu6xxx_set_param(dev, MPU6XXX_SLEEP, MPU6XXX_SLEEP_DISABLE); #ifdef PKG_USING_MPU6XXX_MAG mpu6xxx_write_reg(dev, MPU6XXX_RA_USER_CTRL, 0x20); mpu92_mag_write_reg(dev, AK8963_REG_CNTL2, 0x01); /* [0] Reset Device */ rt_thread_mdelay(1); mpu92_mag_write_reg(dev, AK8963_REG_CNTL1, 0x00); /* [1] Power-down mode */ mpu92_mag_write_reg(dev, AK8963_REG_CNTL1, 0x0F); /* [2] Fuse ROM access mode */ mpu92_mag_write_reg(dev, AK8963_REG_CNTL1, 0x00); /* [3] Power-down mode */ rt_thread_mdelay(1); // 100us mpu92_mag_write_reg(dev, AK8963_REG_CNTL1, 0x16); /* [4] 16bits and Continuous measurement mode 2 */ /* config mpu9250 i2c */ rt_thread_mdelay(2); mpu6xxx_write_reg(dev, MPU6XXX_RA_I2C_MST_CTRL, 0x5D); rt_thread_mdelay(2); mpu6xxx_write_reg(dev, MPU6XXX_RA_I2C_SLV0_ADDR, AK8963_I2C_ADDR | 0x80); rt_thread_mdelay(2); mpu6xxx_write_reg(dev, MPU6XXX_RA_I2C_SLV0_REG, AK8963_REG_ST1); rt_thread_mdelay(2); mpu6xxx_write_reg(dev, MPU6XXX_RA_I2C_SLV0_CTRL, MPU6500_I2C_SLVx_EN | 8); rt_thread_mdelay(2); mpu6xxx_write_reg(dev, MPU6XXX_RA_I2C_SLV4_CTRL, 0x09); rt_thread_mdelay(2); mpu6xxx_write_reg(dev, MPU6XXX_RA_I2C_MST_DELAY_CTRL, 0x81); #endif if (res == RT_EOK) { LOG_I("Device init succeed!"); } else { LOG_W("Error in device initialization!"); } return dev; __exit: if (dev != RT_NULL) { rt_free(dev); } return RT_NULL; } /** * This function releases memory * * @param dev the pointer of device driver structure */ void mpu6xxx_deinit(struct mpu6xxx_device *dev) { RT_ASSERT(dev); rt_free(dev); } static void mpu6xxx(int argc, char **argv) { static struct mpu6xxx_device *dev = RT_NULL; /* If the number of arguments less than 2 */ if (argc < 2) { rt_kprintf("\n"); rt_kprintf("mpu6xxx [OPTION] [PARAM]\n"); rt_kprintf(" probe
Probe mpu6xxx by given name,dev_name such as i2c1 \n"); rt_kprintf(" sr
Set sample rate to var\n"); rt_kprintf(" var = [1000 - 4] when dlpf is enable\n"); rt_kprintf(" var = [8000 - 32] when dlpf is disable\n"); rt_kprintf(" gr
Set gyro range to var\n"); rt_kprintf(" var = [0 - 3] means [250 - 2000DPS]\n"); rt_kprintf(" ar
Set accel range to var\n"); rt_kprintf(" var = [0 - 3] means [2 - 16G]\n"); rt_kprintf(" sleep
Set sleep status\n"); rt_kprintf(" var = 0 means disable, = 1 means enable\n"); rt_kprintf(" read [num] read [num] times mpu6xxx\n"); rt_kprintf(" num default 5\n"); return ; } else if (!strcmp(argv[1], "read")) { struct mpu6xxx_3axes accel, gyro, mag; float temp; rt_uint16_t num = 5; if (dev == RT_NULL) { rt_kprintf("Please probe mpu6xxx first!\n"); return ; } if (argc == 3) { num = atoi(argv[2]); } while (num --) { mpu6xxx_get_accel(dev, &accel); mpu6xxx_get_gyro(dev, &gyro); mpu6xxx_get_mag(dev, &mag); mpu6xxx_get_temp(dev, &temp); rt_kprintf("accel.x = %4d mg, accel.y = %4d mg, accel.z = %4d mg, ", accel.x+50, accel.y, accel.z-800); rt_kprintf("gyro.x = %4d deg/10s, gyro.y = %4d deg/10s, gyro.z = %4d deg/10s, ", gyro.x-70, gyro.y+22, gyro.z-9); rt_kprintf("mag.x = %4d uT, mag.y = %4d uT, mag.z = %4d uT", mag.x, mag.y, mag.z); rt_kprintf("temp = %d.%d ℃\n", (int)(temp * 100) / 100, (int)(temp * 100) % 100); rt_thread_mdelay(100); } } else if (argc == 3) { if (!strcmp(argv[1], "probe")) { if (dev) { mpu6xxx_deinit(dev); } dev = mpu6xxx_init(argv[2], RT_NULL); } else if (dev == RT_NULL) { rt_kprintf("Please probe mpu6xxx first!\n"); return ; } else if (!strcmp(argv[1], "sr")) { mpu6xxx_set_param(dev, MPU6XXX_SAMPLE_RATE, atoi(argv[2])); } else if (!strcmp(argv[1], "sleep")) { mpu6xxx_set_param(dev, MPU6XXX_SLEEP, atoi(argv[2])); } else if (!strcmp(argv[1], "gr")) { mpu6xxx_set_param(dev, MPU6XXX_GYRO_RANGE, atoi(argv[2])); } else if (!strcmp(argv[1], "ar")) { mpu6xxx_set_param(dev, MPU6XXX_ACCEL_RANGE, atoi(argv[2])); } else { rt_kprintf("Unknown command, please enter 'mpu6xxx' get help information!\n"); } } else { rt_kprintf("Unknown command, please enter 'mpu6xxx' get help information!\n"); } } #ifdef FINSH_USING_MSH MSH_CMD_EXPORT(mpu6xxx, mpu6xxx sensor function); #endif ``` mpu6050.c ```cpp /* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2022-07-11 Asus the first version */ #include "sensor_inven_mpu6xxx.h" int rt_hw_mpu6xxx_port(void) { struct rt_sensor_config cfg; cfg.intf.dev_name = "i2c1"; cfg.intf.user_data = (void *)MPU6XXX_ADDR_DEFAULT; cfg.irq_pin.pin = RT_PIN_NONE; rt_hw_mpu6xxx_init("mpu", &cfg); return 0; } INIT_APP_EXPORT(rt_hw_mpu6xxx_port); ``` 3、main.c文件在re_gen文件夹下,主程序围绕“hal_entry();”函数(在src文件夹),这些默认不变 # 4. 下载验证 1、编译重构 ![在这里插入图片描述](https://oss-club.rt-thread.org/uploads/20220714/99ec256c23c8749389a6a4e4bc6cfdfb0f5aca61.png) 编译成功 2、下载程序 ![在这里插入图片描述](https://oss-club.rt-thread.org/uploads/20220714/5d6b401e1cebbfb095045e969a584dddcb41f087.png) 下载成功 3、CMD串口调试 ![在这里插入图片描述](https://oss-club.rt-thread.org/uploads/20220714/6184c9825aed5d03ac96cf1a092775ed36dfc517.png) 然后板载复位,开始串口打印显示!🎉🎉🎉 ![在这里插入图片描述](https://oss-club.rt-thread.org/uploads/20220714/4b00c009cdc3241daf2241ca1f37e790e2d9ad1c.png) 开始测试,输入`mpu6xxx` ![在这里插入图片描述](https://oss-club.rt-thread.org/uploads/20220714/a12149cd174c9283d9687e8467e6b5484bb8c62d.png) 接着校准mpu6050,输入`mpu6xxx probe i2c1` ![在这里插入图片描述](https://oss-club.rt-thread.org/uploads/20220714/a614bc966647ac40359e2c3d29adc8fd52d0fb16.png) 晃动传感器,读取角加速度,角速度和温度,输入`mpu6xxx read 20` 效果如下 ![请添加图片描述](https://oss-club.rt-thread.org/uploads/20220714/b7065d175ca4954aa0921a5f4381226ce24af66a.gif) 打印日志 ```cpp \ | / - RT - Thread Operating System / | \ 4.1.0 build Jul 13 2022 21:35:51 2006 - 2022 Copyright by RT-Thread team [I/mpu6xxx] Find device: mpu6050! [I/mpu6xxx] Device init succeed! [I/sensor] rt_sensor[acce_mpu] init success [I/sensor] rt_sensor[gyro_mpu] init success [I/sensor] rt_sensor[mag_mpu] init success [I/sensor.inven.mpu6xxx] sensor init success Hello RT-Thread! msh >mpu6xxx mpu6xxx [OPTION] [PARAM] probe
Probe mpu6xxx by given name such as i2c1 sr
Set sample rate to var var = [1000 - 4] when dlpf is enable var = [8000 - 32] when dlpf is disable gr
Set gyro range to var var = [0 - 3] means [250 - 2000DPS] ar
Set accel range to var var = [0 - 3] means [2 - 16G] sleep
Set sleep status var = 0 means disable, = 1 means enable read [num] read [num] times mpu6xxx num default 5 msh >mpu6xxx probe i2c1 [I/mpu6xxx] Find device: mpu6050! [I/mpu6xxx] Device init succeed! msh >mpu6xxx read 20 accel.x = 200 mg, accel.y = -4 mg, accel.z = 3 mg, gyro.x = 0 deg/10s, gyro.y = -1 deg/10s, gyro.z = -2 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.65 ℃℃ accel.x = 203 mg, accel.y = -4 mg, accel.z = 19 mg, gyro.x = -1 deg/10s, gyro.y = -1 deg/10s, gyro.z = 0 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.65 ℃℃ accel.x = 194 mg, accel.y = -9 mg, accel.z = 6 mg, gyro.x = -1 deg/10s, gyro.y = 1 deg/10s, gyro.z = -2 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.60 ℃℃ accel.x = 210 mg, accel.y = 11 mg, accel.z = 15 mg, gyro.x = -6 deg/10s, gyro.y = 0 deg/10s, gyro.z = -1 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.60 ℃℃ accel.x = 389 mg, accel.y = 408 mg, accel.z = 499 mg, gyro.x = 25 deg/10s, gyro.y = -127 deg/10s, gyro.z = 353 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.65 ℃℃ accel.x = 187 mg, accel.y = -218 mg, accel.z = -70 mg, gyro.x = 37 deg/10s, gyro.y = -15 deg/10s, gyro.z = 478 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.74 ℃℃ accel.x = -149 mg, accel.y = -561 mg, accel.z = 246 mg, gyro.x = -2571 deg/10s, gyro.y = 479 deg/10s, gyro.z = 121 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.60 ℃℃ accel.x = 104 mg, accel.y = -109 mg, accel.z = -42 mg, gyro.x = -1431 deg/10s, gyro.y = -1333 deg/10s, gyro.z = -1885 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.70 ℃℃ accel.x = 677 mg, accel.y = -592 mg, accel.z = 330 mg, gyro.x = -313 deg/10s, gyro.y = -2479 deg/10s, gyro.z = -1443 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.55 ℃℃ accel.x = 749 mg, accel.y = -57 mg, accel.z = -410 mg, gyro.x = -1377 deg/10s, gyro.y = -2479 deg/10s, gyro.z = -611 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.65 ℃℃ accel.x = 512 mg, accel.y = -146 mg, accel.z = -1845 mg, gyro.x = -799 deg/10s, gyro.y = -2479 deg/10s, gyro.z = -149 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.55 ℃℃ accel.x = -180 mg, accel.y = 420 mg, accel.z = -2800 mg, gyro.x = 519 deg/10s, gyro.y = 1497 deg/10s, gyro.z = 140 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.60 ℃℃ accel.x = 237 mg, accel.y = 243 mg, accel.z = -1148 mg, gyro.x = 1585 deg/10s, gyro.y = 2523 deg/10s, gyro.z = 1265 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.60 ℃℃ accel.x = 77 mg, accel.y = -667 mg, accel.z = -257 mg, gyro.x = 907 deg/10s, gyro.y = 2523 deg/10s, gyro.z = 1608 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.51 ℃℃ accel.x = -239 mg, accel.y = -726 mg, accel.z = 644 mg, gyro.x = 557 deg/10s, gyro.y = 2523 deg/10s, gyro.z = 651 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.51 ℃℃ accel.x = -230 mg, accel.y = -556 mg, accel.z = 181 mg, gyro.x = 215 deg/10s, gyro.y = 294 deg/10s, gyro.z = -54 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.65 ℃℃ accel.x = -385 mg, accel.y = -600 mg, accel.z = 570 mg, gyro.x = -1 deg/10s, gyro.y = -2045 deg/10s, gyro.z = -128 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.55 ℃℃ accel.x = -335 mg, accel.y = -419 mg, accel.z = -310 mg, gyro.x = -1128 deg/10s, gyro.y = -2479 deg/10s, gyro.z = -1016 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.55 ℃℃ accel.x = 534 mg, accel.y = 100 mg, accel.z = -1428 mg, gyro.x = -1368 deg/10s, gyro.y = -2479 deg/10s, gyro.z = -1052 deg/10s, mag.x = 0 uT, mag. y = 0 uT, mag.z = 0 uTtemp = 31.55 ℃℃ accel.x = 469 mg, accel.y = 265 mg, accel.z = -1841 mg, gyro.x = -1220 deg/10s, gyro.y = -2479 deg/10s, gyro.z = -656 deg/10s, mag.x = 0 uT, mag.y = 0 uT, mag.z = 0 uTtemp = 31.46 ℃℃ ``` 数据显示一开始没有怎么变化,后面就会变化加快(我手抖了😁),mpu6050不支持磁力所以全部为零。 这样我们就可以天马行空啦! ![请添加图片描述](https://oss-club.rt-thread.org/uploads/20220714/85725948aa2d0388ca7c362ee216e4a2f1ae9f4c.gif) 参考文献; [【基于 RT-Thread Studio的CPK-RA6M4 开发板环境搭建】](https://blog.csdn.net/vor234/article/details/125634313)
1
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
2345vor
每天都满怀期待i😀
文章
20
回答
2
被采纳
0
关注TA
发私信
相关文章
1
NXP的I2C应该比ST的好用吧
2
Use of I2C device driver
3
关于I2C 驱动问题请教
4
我如何知道这个iic的io配置和我电路设计的是一致的?
5
I2C模拟读操作失败,不知道问什么进不去读函数
6
RTT的I2C有官方文档资料没有
7
求 STM32F103 IIC 自定义IO初始化 代码
8
报一个LPC4008代码中I2C的bug
9
RTOS IIC总线使用
10
关于在RTT中使用STM32 I2C的疑问
推荐文章
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
DMA
USB
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
I2C_IIC
ESP8266
UART
WIZnet_W5500
ota在线升级
cubemx
PWM
flash
freemodbus
BSP
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
编译报错
中断
Debug
rt_mq_消息队列_msg_queue
keil_MDK
SFUD
msh
ulog
C++_cpp
MicroPython
本月问答贡献
三世执戟
5
个答案
1
次被采纳
RTT_逍遥
4
个答案
1
次被采纳
KunYi
4
个答案
1
次被采纳
xiaorui
1
个答案
1
次被采纳
JonasWen
1
个答案
1
次被采纳
本月文章贡献
出出啊
1
篇文章
3
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
3
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部