使用i2c采集MPU6500的原始加速度和陀螺仪数据
复制之前的 01-pwm 工程目录,重命名为02-i2c,需要修改下述FW bin名称否则烧录有问题
AiPi-Open-Kits\FreeRTOS_study\01-pwm\flash_prog_cfg.ini

同时创建 driver和include目录

CMakelist这里需要按照这样修改,不然会导致编译报错或者链接时报错

i2c_driver.c
#include "i2c_driver.h"
#include "bflb_gpio.h"
#include "bflb_i2c.h"
#include <stdio.h>
static struct bflb_device_s *i2c0; //i2c0外设句柄
bool i2c_init(void)
{
// 1. 配置I2C引脚 (SCL, SDA)
// 2. 初始化I2C控制器,设置时钟频率 (通常400kHz)
// bflb_i2c_init(...);
struct bflb_device_s* gpio;
gpio = bflb_device_get_by_name("gpio");
/* I2C0_SCL */
bflb_gpio_init(gpio, GPIO_PIN_0, GPIO_FUNC_I2C0 | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_1);
/* I2C0_SDA */
bflb_gpio_init(gpio, GPIO_PIN_1, GPIO_FUNC_I2C0 | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_1);
i2c0 = bflb_device_get_by_name("i2c0");
bflb_i2c_init(i2c0, 400000);
printf("[I2C] Init successful.\n");
return true;
}
bool i2c_write_reg(uint8_t devaddr,uint8_t reg,uint8_t reglen,uint8_t *datas,uint16_t datalen)
{
struct bflb_i2c_msg_s msgs[2];
msgs[0].addr = devaddr;
msgs[0].flags = I2C_M_NOSTOP;
msgs[0].buffer = ®
msgs[0].length = reglen;
msgs[1].addr = devaddr;
msgs[1].flags = 0;
msgs[1].buffer = datas;
msgs[1].length = datalen;
if(reglen > 0)
return bflb_i2c_transfer(i2c0, msgs, 2) == 0?0:1;
else
return bflb_i2c_transfer(i2c0, &msgs[1], 1) == 0?0:1;
}
bool i2c_read_reg(uint8_t devaddr,uint8_t reg,uint8_t reglen,uint8_t *datas,uint16_t datalen)
{
struct bflb_i2c_msg_s msgs[2];
msgs[0].addr = devaddr;
msgs[0].flags = I2C_M_NOSTOP;
msgs[0].buffer = ®
msgs[0].length = reglen;
msgs[1].addr = devaddr;
msgs[1].flags = I2C_M_READ;
msgs[1].buffer = datas;
msgs[1].length = datalen;
if(reglen > 0)
return bflb_i2c_transfer(i2c0, msgs, 2) == 0?0:1;
else
return bflb_i2c_transfer(i2c0, &msgs[1], 1) == 0?0:1;
}
i2c_driver.h
#ifndef I2C_DRIVER_H
#define I2C_DRIVER_H
#include <stdint.h>
#include <stdbool.h>
/**
* @brief I2C初始化
* @return true 成功, false 失败
*/
bool i2c_init(void);
/**
* @brief I2C写入寄存器
* @param dev_addr 设备地址 (7-bit)
* @param reg_addr 寄存器地址
* @param data 数据指针
* @param len 数据长度
* @return true 成功, false 失败
*/
bool i2c_write_reg(uint8_t devaddr,uint8_t reg,uint8_t reglen,uint8_t *datas,uint16_t datalen);
/**
* @brief I2C读取寄存器
* @param dev_addr 设备地址 (7-bit)
* @param reg_addr 寄存器地址
* @param data 数据缓冲区
* @param len 数据长度
* @return true 成功, false 失败
*/
bool i2c_read_reg(uint8_t devaddr,uint8_t reg,uint8_t reglen,uint8_t *datas,uint16_t datalen);
#endif /* I2C_DRIVER_H */
mpu6500.c
#include "mpu6500.h"
#include "i2c_driver.h"
#include <stdio.h>
static bool mpu6500_write_byte(uint8_t reg, uint8_t value) {
printf("[MPU6500] mpu6500_write_byte %x\n",reg);
return i2c_write_reg(MPU6500_I2C_ADDR, reg, 1,&value, 1);
}
static bool mpu6500_read_bytes(uint8_t reg, uint8_t *buf, uint16_t len) {
//printf("[MPU6500] mpu6500_read_bytes %x\n",reg);
return i2c_read_reg(MPU6500_I2C_ADDR, reg, 1,buf, len);
}
bool mpu6500_init(void) {
uint8_t who_am_i = 0;
uint8_t i=0;
printf("[MPU6500] mpu6500_init\n");
/*for (i=0;i<256;i++) //当不知道设备地址时可以做扫描动作
{
i2c_read_reg(i, MPU6500_WHO_AM_I, 1,&who_am_i, 1);
if (who_am_i !=0)
{
printf("[MPU6500] I2C addr is %x,ID is %x\n",i,who_am_i);
break;
}
}*/
if (mpu6500_read_bytes(MPU6500_WHO_AM_I, &who_am_i, 1)) {
printf("[MPU6500] I2C Read Failed\n");
return false;
}
printf("[MPU6500] ID: 0x%02X\n", who_am_i);
if (who_am_i != 0x70 && who_am_i != 0x71) { // 6500通常是0x70或0x71
printf("[MPU6500] Wrong ID: 0x%02X\n", who_am_i);
return false;
}
// 2. 唤醒传感器 (清除睡眠位)
mpu6500_write_byte(MPU6500_PWR_MGMT_1, 0x00);
// 3. 配置陀螺仪量程 (+/- 250 dps)
mpu6500_write_byte(MPU6500_GYRO_CONFIG, 0x00);
// 4. 配置加速度计量程 (+/- 2g)
mpu6500_write_byte(MPU6500_ACCEL_CONFIG, 0x00);
printf("[MPU6500] Init Success\n");
return true;
}
bool mpu6500_read_raw(mpu6500_data_t *data) {
uint8_t buf[14];
// 读取加速度(6字节) + 温度(2字节) + 陀螺仪(6字节)
if (mpu6500_read_bytes(MPU6500_ACCEL_XOUT_H, buf, 14)) {
return false;
}
data->ax = (int16_t)(buf[0] << 8 | buf[1]);
data->ay = (int16_t)(buf[2] << 8 | buf[3]);
data->az = (int16_t)(buf[4] << 8 | buf[5]);
int16_t temp_raw = (int16_t)((buf[6] << 8) | buf[7]);
data->temp = ((float)temp_raw / 340.0f) + 36.53f; // 温度公式
data->gx = (int16_t)(buf[8] << 8 | buf[9]);
data->gy = (int16_t)(buf[10] << 8 | buf[11]);
data->gz = (int16_t)(buf[12] << 8 | buf[13]);
return true;
}
mpu6500.h
#ifndef MPU6500_H
#define MPU6500_H
#include <stdint.h>
#include <stdbool.h>
// MPU6500 默认I2C地址
#define MPU6500_I2C_ADDR 0x68
#define MPU6500_WHO_AM_I 0x75
#define MPU6500_PWR_MGMT_1 0x6B
#define MPU6500_GYRO_CONFIG 0x1B
#define MPU6500_ACCEL_CONFIG 0x1C
#define MPU6500_ACCEL_XOUT_H 0x3B
// 数据结构
typedef struct {
int16_t ax, ay, az;
int16_t gx, gy, gz;
float temp;
} mpu6500_data_t;
/**
* @brief 初始化MPU6500
* @return true 成功, false 失败
*/
bool mpu6500_init(void);
/**
* @brief 读取原始数据
* @param data 输出数据结构体指针
* @return true 成功, false 失败
*/
bool mpu6500_read_raw(mpu6500_data_t *data);
#endif /* MPU6500_H */
main.c
#include <stdio.h>
#include <FreeRTOS.h>
#include <task.h>
#include "mpu6500.h"
#include "i2c_driver.h"
// 定义传感器数据任务句柄
TaskHandle_t xMpuTaskHandle = NULL;
/**
* @brief MPU6500数据采集任务
* @param pvParameters 任务参数
*/
void vMpuDataTask(void *pvParameters) {
mpu6500_data_t sensor_data;
TickType_t xLastWakeTime;
const TickType_t xFrequency = pdMS_TO_TICKS(10); // 10ms周期, 100Hz采样率
// 初始化硬件
i2c_init();
if (!mpu6500_init()) {
printf("[ERROR] MPU6500 Init Failed! Task Suspended.\n");
vTaskSuspend(NULL);
}
// 初始化延时基准时间
xLastWakeTime = xTaskGetTickCount();
printf("[INFO] MPU6500 Data Task Started.\n");
for (;;) {
// 严格等间隔调度,避免主循环抖动影响控制算法
vTaskDelayUntil(&xLastWakeTime, xFrequency);
if (mpu6500_read_raw(&sensor_data)) {
// 数据处理:打印或送入滤波算法/姿态解算
printf("Ax: %d, Ay: %d, Az: %d | Gx: %d, Gy: %d, Gz: %d | Temp: %.2f\n",
sensor_data.ax, sensor_data.ay, sensor_data.az,
sensor_data.gx, sensor_data.gy, sensor_data.gz,
sensor_data.temp);
} else {
printf("[WARN] Read Error\n");
}
}
}
/**
* @brief 系统入口函数 (BL616 SDK通常入口为 main)
*/
int main(void) {
board_init();
// 创建MPU6500数据采集任务
// 栈大小根据实际需求调整,优先级设为较高以保证实时性
xTaskCreate(vMpuDataTask, "MpuData", 2048, NULL, 5, &xMpuTaskHandle);
// 启动调度器
vTaskStartScheduler();
// 如果调度器启动失败,会运行到这里
for (;;) {
printf("[ERROR] FreeRTOS Scheduler Failed\n");
}
return 0;
}
串口助手采集的数据
