总体概要MPU9250支持IIC 和是spi 通讯我这里是选择的是spi,因为我后续是需要做姿态解算需要更高的速度spi更合适首先连线按照这个图接好就是啦这一步没有什么问题但是一定要仔细不要接错啦否则后面可能会很麻烦我这里使用到数据中断所以这里INT 也需要接上我这里是接的PB12。SPI通讯底层这里我就不在多讲都是比较基础的可以时候你自己的spi库也可以使用我的我这里直接给出我的代HW_SPI.c#include LLD/PROT/SPI/HW_SPI.h /* -------------------------------------------------------------------------- */ /* 内部工具 */ /* -------------------------------------------------------------------------- */ /** * brief 获取超时计数上限 */ static inline u32_t get_timeout(const MY_HW_SPI *SPI_) { return (SPI_-timeout 0) ? HW_SPI_DEFAULT_TIMEOUT : SPI_-timeout; } /** * brief 等待 TXE发送缓冲区空带超时 */ static HW_SPI_Status wait_txe(MY_HW_SPI *SPI_) { u32_t t get_timeout(SPI_); while (SPI_I2S_GetFlagStatus(SPI_-SPIx, SPI_I2S_FLAG_TXE) ! SET) { if (--t 0) return HW_SPI_ERR_TIMEOUT; } return HW_SPI_OK; } /** * brief 等待 RXNE接收缓冲区非空带超时 */ static HW_SPI_Status wait_rxne(MY_HW_SPI *SPI_) { u32_t t get_timeout(SPI_); while (SPI_I2S_GetFlagStatus(SPI_-SPIx, SPI_I2S_FLAG_RXNE) ! SET) { if (--t 0) return HW_SPI_ERR_TIMEOUT; } return HW_SPI_OK; } /** * brief 等待 BSY总线忙结束用于 Stop 前确保传输完成 */ static HW_SPI_Status wait_not_busy(MY_HW_SPI *SPI_) { u32_t t get_timeout(SPI_); while (SPI_I2S_GetFlagStatus(SPI_-SPIx, SPI_I2S_FLAG_BSY) SET) { if (--t 0) return HW_SPI_ERR_TIMEOUT; } return HW_SPI_OK; } /* -------------------------------------------------------------------------- */ /* SPI 基础操作实现 */ /* -------------------------------------------------------------------------- */ /** * brief 初始化句柄绑定硬件资源与函数指针 */ void HW_SPI_Init(MY_HW_SPI *SPI_, SPI_TypeDef *SPIx, GPIO_TypeDef *NSS_GPIO_X, u16_t NSS_pin) { SPI_-SPIx SPIx; SPI_-NSS_GPIO_X NSS_GPIO_X; SPI_-NSS_pin NSS_pin; SPI_-timeout 0; // 0 使用默认值 HW_SPI_DEFAULT_TIMEOUT SPI_-Init HW_SPI_Init; SPI_-W_NSS HW_SPI_W_NSS; SPI_-Start HW_SPI_Start; SPI_-Stop HW_SPI_Stop; SPI_-SwapByte HW_SPI_SwapByte; SPI_-WriteBuf HW_SPI_WriteBuf; SPI_-ReadBuf HW_SPI_ReadBuf; SPI_-TransferBuf HW_SPI_TransferBuf; } /** * brief 控制片选引脚电平 * param BitValue 0: 拉低选中, 1: 拉高释放 */ void HW_SPI_W_NSS(MY_HW_SPI *SPI_, u8_t BitValue) { GPIO_WriteBit(SPI_-NSS_GPIO_X, SPI_-NSS_pin, (BitAction)BitValue); } /** * brief 开始 SPI 通信NSS 拉低 */ void HW_SPI_Start(MY_HW_SPI *SPI_) { SPI_-W_NSS(SPI_, 0); for(volatile uint8_t i 0; i 10; i) __NOP(); } /** * brief 结束 SPI 通信等待总线空闲后 NSS 拉高 * * 修复说明 * 原代码直接拉高 NSS若此时 SPI 仍在传输最后一个字节 * 提前释放片选会导致从机数据截断。改为先等 BSY0 再拉高。 */ void HW_SPI_Stop(MY_HW_SPI *SPI_) { wait_not_busy(SPI_); // 确保总线传输完成 SPI_-W_NSS(SPI_, 1); } /** * brief 交换一个字节全双工同时发送并接收 * param ByteSend 要发送的字节 * param ByteRecv 接收到的字节指针可为 NULL仅发送时忽略接收值 * return HW_SPI_OK / HW_SPI_ERR_TIMEOUT * * 修复说明 * 原代码 while 循环无超时总线异常时会死锁。 * 改为带超时的 wait_txe / wait_rxne 辅助函数。 */ HW_SPI_Status HW_SPI_SwapByte(MY_HW_SPI *SPI_, u8_t ByteSend, u8_t *ByteRecv) { HW_SPI_Status ret; ret wait_txe(SPI_); if (ret ! HW_SPI_OK) return ret; SPI_I2S_SendData(SPI_-SPIx, ByteSend); ret wait_rxne(SPI_); if (ret ! HW_SPI_OK) return ret; u8_t rx (u8_t)SPI_I2S_ReceiveData(SPI_-SPIx); if (ByteRecv) *ByteRecv rx; return HW_SPI_OK; } /** * brief 连续发送多字节只发不收接收数据丢弃 * param pTx 发送缓冲区 * param len 字节数 */ HW_SPI_Status HW_SPI_WriteBuf(MY_HW_SPI *SPI_, const u8_t *pTx, u16_t len) { if (!pTx || len 0) return HW_SPI_ERR_INVALID_ARG; for (u16_t i 0; i len; i) { HW_SPI_Status ret HW_SPI_SwapByte(SPI_, pTx[i], NULL); if (ret ! HW_SPI_OK) return ret; } return HW_SPI_OK; } /** * brief 连续接收多字节发送 dummy 字节驱动时钟 * param dummy 驱动时钟用的填充字节通常为 0xFF * param pRx 接收缓冲区 * param len 字节数 */ HW_SPI_Status HW_SPI_ReadBuf(MY_HW_SPI *SPI_, u8_t dummy, u8_t *pRx, u16_t len) { if (!pRx || len 0) return HW_SPI_ERR_INVALID_ARG; for (u16_t i 0; i len; i) { HW_SPI_Status ret HW_SPI_SwapByte(SPI_, dummy, pRx[i]); if (ret ! HW_SPI_OK) return ret; } return HW_SPI_OK; } /** * brief 全双工收发pTx 和 pRx 长度相同 * param pTx 发送缓冲区 * param pRx 接收缓冲区 * param len 字节数 */ HW_SPI_Status HW_SPI_TransferBuf(MY_HW_SPI *SPI_, const u8_t *pTx, u8_t *pRx, u16_t len) { if (!pTx || !pRx || len 0) return HW_SPI_ERR_INVALID_ARG; for (u16_t i 0; i len; i) { HW_SPI_Status ret HW_SPI_SwapByte(SPI_, pTx[i], pRx[i]); if (ret ! HW_SPI_OK) return ret; } return HW_SPI_OK; } /* -------------------------------------------------------------------------- */ /* SPI1 具体初始化 */ /* -------------------------------------------------------------------------- */ MY_HW_SPI SPI_1; void SPI_1_Init(void) { /* 开启时钟 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); /* GPIO 初始化 */ GPIO_InitTypeDef GPIO_InitStructure; // PA4 - NSS软件控制推挽输出 GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin GPIO_Pin_4; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); // PA5 - SCK, PA7 - MOSI复用推挽输出 GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin GPIO_Pin_5 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); // PA6 - MISO上拉输入 GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Pin GPIO_Pin_6; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); /* SPI 外设初始化 */ SPI_InitTypeDef SPI_InitStructure; SPI_InitStructure.SPI_Mode SPI_Mode_Master; SPI_InitStructure.SPI_Direction SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_DataSize SPI_DataSize_8b; SPI_InitStructure.SPI_FirstBit SPI_FirstBit_MSB; SPI_InitStructure.SPI_BaudRatePrescaler SPI_BaudRatePrescaler_256; SPI_InitStructure.SPI_CPOL SPI_CPOL_High; // MPU9250: SPI模式3 SPI_InitStructure.SPI_CPHA SPI_CPHA_2Edge; // CPOL1, CPHA1 SPI_InitStructure.SPI_NSS SPI_NSS_Soft; SPI_InitStructure.SPI_CRCPolynomial 7; SPI_Init(SPI1, SPI_InitStructure); SPI_Cmd(SPI1, ENABLE); /* 句柄初始化绑定硬件资源与函数指针 */ HW_SPI_Init(SPI_1, SPI1, SPI_1_NSS_GPIO, SPI_1_NSS); /* NSS 默认拉高释放 */ SPI_1.W_NSS(SPI_1, 1); }HW_SPI.h#ifndef HW_SPI_H #define HW_SPI_H #include stm32f10x.h #include base_c/ALGO/type/type.h // u8_t u16_t u32_t 等类型定义 /* -------------------------------------------------------------------------- */ /* 超时默认值 */ /* -------------------------------------------------------------------------- */ #define HW_SPI_DEFAULT_TIMEOUT 100000U // 循环计数超时上限 /* -------------------------------------------------------------------------- */ /* 错误码与 IIC 保持一致 */ /* -------------------------------------------------------------------------- */ typedef enum { HW_SPI_OK 0, HW_SPI_ERR_TIMEOUT -1, HW_SPI_ERR_INVALID_ARG -2, HW_SPI_ERR_BUSY -3, } HW_SPI_Status; /* -------------------------------------------------------------------------- */ /* MY_HW_SPI 结构体 */ /* -------------------------------------------------------------------------- */ typedef struct MY_HW_SPI MY_HW_SPI; struct MY_HW_SPI { /* 硬件资源 */ SPI_TypeDef *SPIx; // SPI 外设实例 GPIO_TypeDef *NSS_GPIO_X; // NSS 所在 GPIO 端口 u16_t NSS_pin; // NSS 引脚号 u32_t timeout; // 超时计数上限0 使用默认值 /* 操作函数指针 */ void (*Init) (MY_HW_SPI *SPI_, SPI_TypeDef *SPIx, GPIO_TypeDef *NSS_GPIO_X, u16_t NSS_pin); void (*W_NSS) (MY_HW_SPI *SPI_, u8_t BitValue); void (*Start) (MY_HW_SPI *SPI_); void (*Stop) (MY_HW_SPI *SPI_); HW_SPI_Status (*SwapByte)(MY_HW_SPI *SPI_, u8_t ByteSend, u8_t *ByteRecv); HW_SPI_Status (*WriteBuf)(MY_HW_SPI *SPI_, const u8_t *pTx, u16_t len); HW_SPI_Status (*ReadBuf) (MY_HW_SPI *SPI_, u8_t dummy, u8_t *pRx, u16_t len); HW_SPI_Status (*TransferBuf)(MY_HW_SPI *SPI_, const u8_t *pTx, u8_t *pRx, u16_t len); }; /* -------------------------------------------------------------------------- */ /* 函数声明 */ /* -------------------------------------------------------------------------- */ void HW_SPI_Init (MY_HW_SPI *SPI_, SPI_TypeDef *SPIx, GPIO_TypeDef *NSS_GPIO_X, u16_t NSS_pin); void HW_SPI_W_NSS (MY_HW_SPI *SPI_, u8_t BitValue); void HW_SPI_Start (MY_HW_SPI *SPI_); void HW_SPI_Stop (MY_HW_SPI *SPI_); HW_SPI_Status HW_SPI_SwapByte (MY_HW_SPI *SPI_, u8_t ByteSend, u8_t *ByteRecv); HW_SPI_Status HW_SPI_WriteBuf (MY_HW_SPI *SPI_, const u8_t *pTx, u16_t len); HW_SPI_Status HW_SPI_ReadBuf (MY_HW_SPI *SPI_, u8_t dummy, u8_t *pRx, u16_t len); HW_SPI_Status HW_SPI_TransferBuf(MY_HW_SPI *SPI_, const u8_t *pTx, u8_t *pRx, u16_t len); /* -------------------------------------------------------------------------- */ /* SPI1 外部声明 引脚定义 */ /* -------------------------------------------------------------------------- */ extern MY_HW_SPI SPI_1; #define SPI_1_NSS_GPIO GPIOA #define SPI_1_NSS GPIO_Pin_4 void SPI_1_Init(void); #endif /* HW_SPI_H */接下来就是MPU9250的驱动这其实是一个九轴但是我这个是假货所以只有六轴需要外加磁力计而且WHO_AM_I 寄存器的值不是固定 0x71 而是0x70,这里需要注意一下。我也是卡在这里挺久的在淘宝上买东西还是需要谨慎。我只给大家讲讲我的思路具体也是直接看代码主函数就是一个状态机一次完成配置在进去READ 之后需要依靠数据中断来进入状态机在中断中 需要采集十帧数据 才进一次状态机注意需要在这里记录下采样时间进入状态机在记录会有延迟这个时间对于无人机来说是有一些影响的具体的细节直接看源码吧可能会有一些错误这是我第一次写但是我实测是可以准确读取出数据的MPU9250.c#include MPU9250_N.h #include base_c/APP/Debug/Debug.h /* -------------------------------------------------------------------------- */ /* 全局变量 */ /* -------------------------------------------------------------------------- */ bool MPU9250_DataReady_Flag false; uint32_t timestamp_sample 0; static uint8_t samples_count 0; static MPU9250_State _state INIT; #define GYRO_SENS_2000 0.060975 #define ACCEL_SENS_16 0.004788 /* -------------------------------------------------------------------------- */ /* 寄存器配置表 */ /* */ /* 与原 IIC 版本完全相同SPI 只影响底层 RegisterRead/Write 实现 */ /* -------------------------------------------------------------------------- */ static const register_config_t _register_cfg[] { /* 复位后先选时钟源PLL陀螺仪时钟 */ { PWR_MGMT_1, 0x01, 0xFE }, /* 采样率分频SMPLRT_DIV 0 - 采样率 陀螺仪输出率 / (10) 1kHz */ { SMPLRT_DIV, 0x00, 0xFF }, /* DLPF 配置带宽 92Hz陀螺仪延迟 3.9ms */ { CONFIG, 0x02, 0xF8 }, /* 陀螺仪量程±2000 dps */ { GYRO_CONFIG, 0x18, 0xE7 }, /* 加速度计量程±16g */ { ACCEL_CONFIG, 0x18, 0xE7 }, /* 加速度计 DLPF带宽 99Hz */ { ACCEL_CONFIG2, 0x02, 0xF8 }, /* FIFO 使能加速度计 陀螺仪 XYZ 写入 FIFO */ { FIFO_EN, 0x78, 0x87 }, /* USER_CTRL使能 FIFO禁用 I2CSPI 模式下必须禁用 I2C 从机接口 */ { USER_CTRL, (1 6) | (1 4), (1 5) }, /* INT_PIN_CFGINT 引脚高电平有效推挽保持直到读清 */ { INT_PIN_CFG, 0x10, 0xEF }, /* INT_ENABLE数据就绪中断使能 */ { INT_ENABLE, 0x01, 0xFE }, }; #define SIZE_REGISTER_CFG (sizeof(_register_cfg) / sizeof(_register_cfg[0])) /* -------------------------------------------------------------------------- */ /* SPI 底层读写实现 */ /* -------------------------------------------------------------------------- */ /** * brief 写单个寄存器 * param reg 寄存器地址 * param value 写入的值 * * 时序NSS低 - 发送(寄存器地址 | WRITE) - 发送数据 - NSS高 */ void RegisterWrite(Register reg, uint8_t value) { uint8_t tx[2]; tx[0] (uint8_t)reg | MPU9250_SPI_WRITE; // 最高位0写 tx[1] value; SPI_1.Start(SPI_1); SPI_1.WriteBuf(SPI_1, tx, 2); SPI_1.Stop(SPI_1); } /** * brief 读单个寄存器 * param reg 寄存器地址 * return 读到的值 * * 时序NSS低 - 发送(寄存器地址 | READ) - 收1字节 - NSS高 */ uint8_t RegisterRead(Register reg) { uint8_t rx 0; SPI_1.Start(SPI_1); SPI_1.SwapByte(SPI_1, (uint8_t)reg | MPU9250_SPI_READ, NULL); // 发地址 SPI_1.SwapByte(SPI_1, 0xFF, rx); // 收数据 SPI_1.Stop(SPI_1); return rx; } /** * brief 读多个连续寄存器SPI 支持地址自增 * param reg 起始寄存器地址 * param pBuf 接收缓冲区 * param len 字节数 * * 时序NSS低 - 发送(起始地址 | READ) - 连续收 len 字节 - NSS高 */ static void RegisterReadBurst(Register reg, uint8_t *pBuf, uint16_t len) { SPI_1.Start(SPI_1); SPI_1.SwapByte(SPI_1, (uint8_t)reg | MPU9250_SPI_READ, NULL); SPI_1.ReadBuf(SPI_1, 0xFF, pBuf, len); SPI_1.Stop(SPI_1); } /* -------------------------------------------------------------------------- */ /* 寄存器配置工具 */ /* -------------------------------------------------------------------------- */ void RegisterSetAndClearBits(Register reg, uint8_t set_bits, uint8_t clear_bits) { const uint8_t orig_val RegisterRead(reg); uint8_t val (orig_val ~clear_bits) | set_bits; if (val ! orig_val) RegisterWrite(reg, val); } bool RegisterCheck(register_config_t reg_cfg) { bool success true; uint8_t reg_value RegisterRead(reg_cfg.reg); if (reg_cfg.set_bits ((reg_value reg_cfg.set_bits) ! reg_cfg.set_bits)) success false; if (reg_cfg.clear_bits ((reg_cfg.clear_bits reg_value) ! 0)) success false; return success; } /* -------------------------------------------------------------------------- */ /* MPU9250 初始化 */ /* -------------------------------------------------------------------------- */ bool MPU9250_Init(void) { MPU9250_INT_Config(); /* 验证 WHO_AM_I 寄存器MPU9250 固定返回 0x71 */ uint8_t who RegisterRead(WHO_AM_I); if (who ! 0x71 who ! 0x70) { DEBUG(MPU9250 WHO_AM_I check failed: 0x%02X\r\n, who); return false; } DEBUG(MPU9250 detected, WHO_AM_I0x%02X\r\n, who); return true; } bool MPU9250_Config(void) { uint8_t i, j; for (i 0; i SIZE_REGISTER_CFG; i) RegisterSetAndClearBits(_register_cfg[i].reg, _register_cfg[i].set_bits, _register_cfg[i].clear_bits); bool success true; for (j 0; j SIZE_REGISTER_CFG; j) { if (!RegisterCheck(_register_cfg[j])) success false; } return success; } /* -------------------------------------------------------------------------- */ /* 数据处理 */ /* -------------------------------------------------------------------------- */ static inline int16_t combine(uint8_t H, uint8_t L) { return (int16_t)((H 8) | L); } static void ProcessGyro(uint32_t timestamp, const DATA fifo[], uint8_t samples) { GYRO_DATA gyro_data; gyro_data.timestamp timestamp; gyro_data.samples samples; gyro_data.dt FIFO_SAMPLE_DT; for (uint8_t i 0; i samples; i) { int16_t gx combine(fifo[i].GYRO_XOUT_H, fifo[i].GYRO_XOUT_L); int16_t gy combine(fifo[i].GYRO_YOUT_H, fifo[i].GYRO_YOUT_L); int16_t gz combine(fifo[i].GYRO_ZOUT_H, fifo[i].GYRO_ZOUT_L); gyro_data.x[i] gx; gyro_data.y[i] (gy INT16_MIN) ? INT16_MAX : -gy; gyro_data.z[i] (gz INT16_MIN) ? INT16_MAX : -gz; } // 转换为角度 for (uint8_t i 0; i samples; i) { gyro_data.x[i] * GYRO_SENS_2000; gyro_data.y[i] * GYRO_SENS_2000; gyro_data.z[i] * GYRO_SENS_2000; } //DEBUG(gyro_data: %d, %d, %d\r\n, gyro_data.x[0], gyro_data.y[0], gyro_data.z[0]); /* TODO: 将 gyro_data 传递到上层消息队列 / 回调 / 全局缓冲 */ } static bool ProcessAccel(uint32_t timestamp, const DATA fifo[], uint8_t samples) { ACCEL_DATA accel_data; accel_data.timestamp timestamp; accel_data.samples 0; accel_data.dt FIFO_SAMPLE_DT; for (uint8_t i 0; i samples; i) { int16_t ax combine(fifo[i].ACCEL_XOUT_H, fifo[i].ACCEL_XOUT_L); int16_t ay combine(fifo[i].ACCEL_YOUT_H, fifo[i].ACCEL_YOUT_L); int16_t az combine(fifo[i].ACCEL_ZOUT_H, fifo[i].ACCEL_ZOUT_L); accel_data.x[accel_data.samples] ax; accel_data.y[accel_data.samples] (ay INT16_MIN) ? INT16_MAX : -ay; accel_data.z[accel_data.samples] (az INT16_MIN) ? INT16_MAX : -az; accel_data.samples; } for (uint8_t i 0; i accel_data.samples; i) { accel_data.x[i] * ACCEL_SENS_16; accel_data.y[i] * ACCEL_SENS_16; accel_data.z[i] * ACCEL_SENS_16; } DEBUG(accel_data: %d, %d, %d\r\n, accel_data.x[0], accel_data.y[0], accel_data.z[0]); /* TODO: 将 accel_data 传递到上层 */ return true; } /* -------------------------------------------------------------------------- */ /* FIFO 操作 */ /* -------------------------------------------------------------------------- */ static uint16_t FIFOReadCount(void) { uint8_t buf[2] {0}; RegisterReadBurst(FIFO_COUNTH, buf, 2); return combine(buf[0], buf[1]); } static void FIFOReset(void) { /* 先关闭 FIFO 写入再复位 FIFO再重新开启 */ RegisterWrite(FIFO_EN, 0x00); RegisterSetAndClearBits(USER_CTRL, (1 2), (1 6)); // FIFO_RST /* 复位后重新使能 FIFO */ RegisterSetAndClearBits(USER_CTRL, (1 6), (1 2)); RegisterWrite(FIFO_EN, 0x78); } static bool FIFORead(uint32_t timestamp, uint8_t samples) { TransferBuffer buffer; uint16_t transfer_size (uint16_t)(samples * sizeof(DATA)); if (transfer_size FIFO_SIZE) transfer_size FIFO_SIZE; /* * SPI 版本使用 RegisterReadBurst 连续读取 FIFO_R_W 寄存器 * MPU9250 SPI 模式下FIFO_R_W 地址每次读取会自动给出下一字节 * 无需多次发地址。 */ RegisterReadBurst(FIFO_R_W, buffer.raw, transfer_size); ProcessGyro(timestamp, buffer.f, samples); return ProcessAccel(timestamp, buffer.f, samples); } /* -------------------------------------------------------------------------- */ /* 主状态机 */ /* -------------------------------------------------------------------------- */ static void MPU9250_DataReady(void) { switch (_state) { case INIT: if (MPU9250_Init()) _state SETUP; /* Init 失败则停留在 INIT下次再试 */ break; case SETUP: /* 软复位 */ RegisterWrite(PWR_MGMT_1, 1 7); FIFOReset(); /* 等待复位完成约100ms此处简单延时或下次进入再判断 */ _state CONFIGER; DEBUG(MPU9250 reset OK\r\n); break; case CONFIGER: if (MPU9250_Config()) { timestamp_sample millis(); _state READ; DEBUG(MPU9250 config OK\r\n); } break; case READ: { uint32_t now millis(); /* 超过10ms没有新数据 - FIFO 可能溢出复位 */ if (now - timestamp_sample 10) { _state SETUP; break; } uint16_t fifo_count FIFOReadCount(); if (fifo_count FIFO_SIZE) { /* FIFO 溢出直接复位 */ DEBUG(FIFO overflow, reset\r\n); _state SETUP; } else if (fifo_count 0) { /* 暂无数据等待下次中断 */ break; } else { uint8_t samples (uint8_t)(fifo_count / sizeof(DATA)); if (samples 11) { /* 边界情况多了一帧时间戳往前补偿 */ timestamp_sample - FIFO_SAMPLE_DT; samples--; } else if (samples 10) { _state SETUP; break; } if (!FIFORead(timestamp_sample, samples)) { DEBUG(FIFORead failed\r\n); _state SETUP; } } break; } default: _state INIT; break; } } /* -------------------------------------------------------------------------- */ /* 外部调用入口 */ /* -------------------------------------------------------------------------- */ void MPU9250_Run(void) { if (MPU9250_DataReady_Flag || _state INIT || _state SETUP || _state CONFIGER) { //DEBUG(MPU9250_Run state%d\r\n, _state); MPU9250_DataReady_Flag false; MPU9250_DataReady(); } } /* -------------------------------------------------------------------------- */ /* 中断配置 中断服务 */ /* -------------------------------------------------------------------------- */ #define INT_PIN GPIO_Pin_12 #define INT_PORT GPIOB void MPU9250_INT_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); GPIO_InitStructure.GPIO_Pin INT_PIN; GPIO_InitStructure.GPIO_Mode GPIO_Mode_IPD; // 下拉输入 GPIO_Init(INT_PORT, GPIO_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource12); EXTI_InitStructure.EXTI_Line EXTI_Line12; EXTI_InitStructure.EXTI_Mode EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger EXTI_Trigger_Rising; EXTI_InitStructure.EXTI_LineCmd ENABLE; EXTI_Init(EXTI_InitStructure); NVIC_InitStructure.NVIC_IRQChannel EXTI15_10_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority 1; NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; NVIC_Init(NVIC_InitStructure); } void EXTI15_10_IRQHandler(void) { if (EXTI_GetITStatus(EXTI_Line12) ! RESET) { samples_count; if (samples_count 10) { samples_count - 10; MPU9250_DataReady_Flag true; timestamp_sample millis(); } EXTI_ClearITPendingBit(EXTI_Line12); } }MPU9250.h#ifndef MPU9250_SPI_H #define MPU9250_SPI_H #include stm32f10x.h #include base_c/ALGO/type/type.h #include LLD/PROT/SPI/HW_SPI.h /* -------------------------------------------------------------------------- */ /* MPU9250 寄存器地址定义 */ /* -------------------------------------------------------------------------- */ typedef enum { SELF_TEST_X_GYRO 0x00, SELF_TEST_Y_GYRO 0x01, SELF_TEST_Z_GYRO 0x02, SELF_TEST_X_ACCEL 0x0D, SELF_TEST_Y_ACCEL 0x0E, SELF_TEST_Z_ACCEL 0x0F, SMPLRT_DIV 0x19, CONFIG 0x1A, GYRO_CONFIG 0x1B, ACCEL_CONFIG 0x1C, ACCEL_CONFIG2 0x1D, FIFO_EN 0x23, INT_PIN_CFG 0x37, INT_ENABLE 0x38, INT_STATUS 0x3A, ACCEL_XOUT_H 0x3B, ACCEL_XOUT_L 0x3C, ACCEL_YOUT_H 0x3D, ACCEL_YOUT_L 0x3E, ACCEL_ZOUT_H 0x3F, ACCEL_ZOUT_L 0x40, GYRO_XOUT_H 0x43, GYRO_XOUT_L 0x44, GYRO_YOUT_H 0x45, GYRO_YOUT_L 0x46, GYRO_ZOUT_H 0x47, GYRO_ZOUT_L 0x48, USER_CTRL 0x6A, PWR_MGMT_1 0x6B, PWR_MGMT_2 0x6C, FIFO_COUNTH 0x72, FIFO_COUNTL 0x73, FIFO_R_W 0x74, WHO_AM_I 0x75, } Register; /* -------------------------------------------------------------------------- */ /* SPI 读写位定义 */ /* -------------------------------------------------------------------------- */ #define MPU9250_SPI_READ 0x80 // 最高位为1读操作 #define MPU9250_SPI_WRITE 0x00 // 最高位为0写操作 /* -------------------------------------------------------------------------- */ /* FIFO 相关定义 */ /* -------------------------------------------------------------------------- */ #define FIFO_SAMPLE_DT 0.125 // 采样间隔ms由采样率决定 #define FIFO_SIZE 512 // MPU9250 FIFO 最大字节数 /* 一帧 FIFO 数据结构加速度 陀螺仪共12字节 */ typedef struct __attribute__((packed)) { uint8_t ACCEL_XOUT_H; uint8_t ACCEL_XOUT_L; uint8_t ACCEL_YOUT_H; uint8_t ACCEL_YOUT_L; uint8_t ACCEL_ZOUT_H; uint8_t ACCEL_ZOUT_L; uint8_t GYRO_XOUT_H; uint8_t GYRO_XOUT_L; uint8_t GYRO_YOUT_H; uint8_t GYRO_YOUT_L; uint8_t GYRO_ZOUT_H; uint8_t GYRO_ZOUT_L; } DATA; #define FIFO_SAMPLE_SIZE (10 * sizeof(DATA)) // 10帧为一个处理单元 typedef union { DATA f[10]; uint8_t raw[10 * sizeof(DATA)]; } TransferBuffer; /* -------------------------------------------------------------------------- */ /* 输出数据结构 */ /* -------------------------------------------------------------------------- */ typedef struct { uint32_t timestamp; uint8_t samples; uint32_t dt; int16_t x[10]; int16_t y[10]; int16_t z[10]; } GYRO_DATA; typedef struct { uint32_t timestamp; uint8_t samples; uint32_t dt; int16_t x[10]; int16_t y[10]; int16_t z[10]; } ACCEL_DATA; /* -------------------------------------------------------------------------- */ /* 寄存器配置表 */ /* -------------------------------------------------------------------------- */ typedef struct { Register reg; uint8_t set_bits; uint8_t clear_bits; } register_config_t; /* -------------------------------------------------------------------------- */ /* 状态机定义 */ /* -------------------------------------------------------------------------- */ typedef enum { INIT 0, SETUP 1, CONFIGER 2, READ 3 } MPU9250_State; /* -------------------------------------------------------------------------- */ /* 函数声明 */ /* -------------------------------------------------------------------------- */ /* SPI 底层读写 */ void RegisterWrite(Register reg, uint8_t value); uint8_t RegisterRead (Register reg); void RegisterSetAndClearBits(Register reg, uint8_t set_bits, uint8_t clear_bits); bool RegisterCheck(register_config_t reg_cfg); /* 功能接口 */ bool MPU9250_Init (void); bool MPU9250_Config (void); void MPU9250_Run (void); /* 中断配置 */ void MPU9250_INT_Config(void); /* 全局标志 */ extern bool MPU9250_DataReady_Flag; extern uint32_t timestamp_sample; /* 时间戳接口需用户提供 */ extern uint32_t millis(void); #endif /* MPU9250_SPI_H */仅供参考谢谢大家