十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

STM32学习24--I2C-2

STM32学习24--I2C-2 一、MPU6050简介1、MOU6050是一个6轴姿态传感器可以测量芯片自身X、Y、Z轴的加速度、角速度参数通过数据融合可进一步得到姿态角欧拉角常用于平衡车、飞行器等需要检测自身姿态的场景。2、3轴加速度计Accelerometer测量X、Y、Z轴的加速度3轴陀螺仪传感器Gyroscope测量X、Y、Z轴的角速度3、16位ADC采集传感器的模拟信号量化范围-32768~327674、加速度即满量程选择±2、±4、±8、±165、陀螺仪满量程选择±250、±500、±1000、±2000°/sec6、可配置的数字低通滤波7、可配置的时钟源8、可配置的采样分频二、硬件与引脚1、VCC3.3V模块板载LDO可以接5V芯片内核只能3.3V。2、GND必须与STM32共地否则数据乱跳3、SDA、SCLI2C通信引脚最高400KHz4、XCL、XDA主机I2C通信引脚是扩展功能用常外接磁力计、气压计将外接的数据读取到MPU6050里面通过DMP数据融合和姿态解算也可将气压计直接接SCL、SDA上。5、AD0地址选择AD0接地→I2C 7位地址0x680x1101000AD0接VCC→I2C 7位地址0x69 (0x1101001)6、INT中断输出。三、常用关键寄存器1、WHO_AM_I 0x75只读读出应为0x68读不到则I2C不通2、PWR_MGMT_1 0x6B电源管理1上电默认0x40位名称说明7DEVICE_RESET写1硬件复位芯片硬件自动清0复位后芯片进入睡眠6SLEEP1睡眠模式0正常工作必须清零5CYCLE循环低功耗模式睡眠--唤醒间歇采集加速度关闭陀螺仪。4RESERVED保留3TEMP_DIS1-关闭片内温度传感器0-开启2-0CKLSEL时钟源选择CKLSEL推荐0-内部8M RC精度差不推荐长期使用1PLLX-Gyro时钟源最常用2PLL Y-Gyro3PLL Z-Gyro标准唤醒配置0x01--退出睡眠使用X陀螺PLL时钟稳定打开建议不要写0x003、PWR_MGMT_2 0x6C电源管理2bit[5-0]分别控制AX、AY、AZGXGYGZ写0开启该轴写1关闭该轴上电默认全部是0六轴全开全部传感器开启注这不是休眠是单轴关闭休眠是0x6B的bit64、SMPLRT_DIV 0x19 采样率分频寄存器陀螺仪输出数据率陀螺仪内部输出速率/(1SMPRT_DIV)DLPF_CFG≠7陀螺基础速率1000Hz(ADC)DLPF_CFG0或7陀螺基础速率8000HzADC示例如下SMPRT_DIV7→1000/(17) 125Hz平衡车、倒立摆最常用而加速度ADC固定1kHz不受SMPRT_DIV的限制。5、CONFIG 0x1A 配置寄存器DLPFDigital Low Pass Filter硬件数字低通滤波bit[2-0] DLPF_CFG硬件数字低通滤波直接决定滤波、延迟。[7-3]FSYNC外部同步输入不用必须写0Frame Synchronization帧同步[2-0]DLPF_CFG数字低通滤波配置示例写0x06即DLPF_CFG6带宽5Hz强抑制振动噪声但延迟大适合平衡车高速项目选3或4DLPF是硬件模拟之后数字滤波优先用硬件DLPF不能全靠软件滤波。加速度计带宽好陀螺带宽不是严格相等是2套独立的数字滤波器硬件。DLPF带宽 VS SMPLRT_DIV(0x19)输出采样频率DLPF_CFG硬件滤波器截止带宽抗混叠、过滤噪声发送在ADC之后输出寄存器之前。SMPLRT_DIV输出分频决定MCU读到数据的输出频率ODR只改变输出多少Hz给MCU不改变滤波器截止频率。经验设计原则硬件DLPF带宽必须小于ODR/2否则发发送信号混叠。比如ODR125HzODR/262.5那么DLPF_CFG只能选421Hz、510Hz、65Hz不能选0/1/2/3。6、GYRO_CONFIG 0x1B 陀螺仪配置寄存器[7-5]是陀螺仪X、Y、Z的自检位[4-3]是FS_SEL陀螺仪满量程选择[2-0]保留为0示例0x18FS_SEL3±2000°/s最大量程分辨率最低适合高速旋转。普通平衡小车推荐0x08±500°/s。7、ACCEL_CONFIG 0x1C 加速度计配置寄存器[7-5]是加速度计X、Y、Z的自检位[4-3]是AFS_SEL加速度计量程选择[2-0]写0示例0x18AFS_SEL3±16g量程越大分辨率越低。静止、倾角检测选±2g冲击、剧烈运动选±8g。8、数据寄存器组只读0x3B开始连续14个字节全部为16位二进制补码高字节在前低字节在后。读取后必须存入int16_t有符号16位整型不能用uint16_t直接运算。示例0x3B-0x3CACCEL_XOUT_H/LX加速度以此类推……0x41-0x42 TEMP_OUT_H/L片内温度原始值温度计算公式int16_t Temp_raw; float Temp_c Temp_raw/340.0f36.53f;这是芯片硅片内部温度不是环境温度32-38℃属于正常不能当环境温度计。示例0x43-0x44ACCEL_XOUT_H/LX陀螺仪角速度以此类推……四、代码部分1、MPU6050.c文件#include stm32f10x.h #include I2C.h #include MPU6050Req.h #include MPU6050.h #define MPU6050_ADDRESS 0xD0 void MPU6050_WriteReq(uint8_t ReqAddress,uint8_t Data) { MyI2C_Start(); MyI2C_SendByte(MPU6050_ADDRESS); MyI2C_ReceiveACK(); MyI2C_SendByte(ReqAddress); MyI2C_ReceiveACK(); MyI2C_SendByte(Data); MyI2C_ReceiveACK(); MyI2C_Stop(); } uint8_t MPU6050_ReadReq(uint8_t RegAddress) { uint8_t Data; MyI2C_Start(); MyI2C_SendByte(MPU6050_ADDRESS); MyI2C_ReceiveACK(); MyI2C_SendByte(RegAddress); MyI2C_ReceiveACK(); MyI2C_Start(); MyI2C_SendByte(MPU6050_ADDRESS|0x01); MyI2C_ReceiveACK(); Data MyI2C_ReceiveByte(); MyI2C_SendACK(1); MyI2C_Stop(); return Data; } void MPU6050_Init() { MyI2C_Init(); MPU6050_WriteReq(MPU6050_PWR_MGMT_1,0x01); MPU6050_WriteReq(MPU6050_PWR_MGMT_2,0x00); MPU6050_WriteReq(MPU6050_SMPLRT_DIV,0x09); MPU6050_WriteReq(MPU6050_CONFIG,0x06); MPU6050_WriteReq(MPU6050_GYRO_CONFIG,0x18); MPU6050_WriteReq(MPU6050_ACCEL_CONFIG,0x18); Delay_ms(100); } uint8_t GetID() { return MPU6050_ReadReq(MPU6050_WHO_AM_I); } void MPU6050_GetData(MPU6050_StructureData* SensorValue) { uint8_t DataH,DataL; DataH MPU6050_ReadReq(MPU6050_ACCEL_XOUT_H); DataL MPU6050_ReadReq(MPU6050_ACCEL_XOUT_L); SensorValue-AccX (int16_t)DataH8| DataL; DataH MPU6050_ReadReq(MPU6050_ACCEL_YOUT_H); DataL MPU6050_ReadReq(MPU6050_ACCEL_YOUT_L); SensorValue-AccY (int16_t)DataH8| DataL; DataH MPU6050_ReadReq(MPU6050_ACCEL_ZOUT_H); DataL MPU6050_ReadReq(MPU6050_ACCEL_ZOUT_L); SensorValue-AccZ (int16_t)DataH8| DataL; }2、MPU6050.h文件#ifndef __MPU6050_H #define __MPU6050_H #include Delay.h void MPU6050_WriteReq(uint8_t ReqAddress,uint8_t Data); uint8_t MPU6050_ReadReq(uint8_t RegAddress); void MPU6050_Init(); uint8_t GetID(); typedef struct { int16_t AccX; int16_t AccY; int16_t AccZ; int16_t GroX; int16_t GroY; int16_t GroZ; }MPU6050_StructureData; void MPU6050_GetData(MPU6050_StructureData* SensorValue); #endif3、MPU6050寄存器文件#ifndef __MPU6050REQ_H #define __MPU6050REQ_H #define MPU6050_SMPLRT_DIV 0x19 //采样分频 #define MPU6050_CONFIG 0x1A //配置低通滤波 #define MPU6050_GYRO_CONFIG 0x1B //陀螺仪配置 #define MPU6050_ACCEL_CONFIG 0x1C //加速度计配置 #define MPU6050_ACCEL_XOUT_H 0x3B //加速度计X轴高位 #define MPU6050_ACCEL_XOUT_L 0x3C //加速度计X轴低位以此类推…… #define MPU6050_ACCEL_YOUT_H 0x3D #define MPU6050_ACCEL_YOUT_L 0x3E #define MPU6050_ACCEL_ZOUT_H 0x3F #define MPU6050_ACCEL_ZOUT_L 0x40 #define MPU6050_TEMP_OUT_H 0x41 //片内温度 #define MPU6050_TEMP_OUT_L 0x42 #define MPU6050_GYRO_XOUT_H 0x43 #define MPU6050_GYRO_XOUT_L 0x44 #define MPU6050_GYRO_YOUT_H 0x45 #define MPU6050_GYRO_YOUT_L 0x46 #define MPU6050_GYRO_ZOUT_H 0x47 #define MPU6050_GYRO_ZOUT_L 0x48 #define MPU6050_PWR_MGMT_1 0x6B //电源管理1配置睡眠模式和时钟源选择 #define MPU6050_PWR_MGMT_2 0x6C //电源管理2配置X、Y、Z睡眠与否 #define MPU6050_WHO_AM_I 0x75 #endif4、main函数#include stm32f10x.h #include Delay.h #include OLED.h #include MPU6050.h uint8_t ID; MPU6050_StructureData Sensor_Value; int main() { OLED_Init(); MPU6050_Init(); ID GetID(); Test TestValue(); OLED_ShowHexNum(1,1,ID,2); OLED_ShowHexNum(1,4,Test,2); while(1) { MPU6050_GetData(Sensor_Value); OLED_ShowSignedNum(2,1,Sensor_Value.AccX,5); OLED_ShowSignedNum(3,1,Sensor_Value.AccY,5); OLED_ShowSignedNum(4,1,Sensor_Value.AccZ,5); Delay_ms(100); } }练习2连续读1、I2C底层修改#include stm32f10x.h // Device header #include Delay.h void MyI2C_W_SCL(uint8_t BitValue) { GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction)BitValue); Delay_us(5); } void MyI2C_W_SDA(uint8_t BitValue) { GPIO_WriteBit(GPIOB,GPIO_Pin_11,(BitAction)BitValue); Delay_us(5); } uint8_t MyI2C_R_SDA() { uint8_t BitValue; BitValue GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11); Delay_us(5); return BitValue; } void MyI2C_Init() { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_OD; GPIO_InitStructure.GPIO_PinGPIO_Pin_10|GPIO_Pin_11 ; GPIO_InitStructure.GPIO_SpeedGPIO_Speed_50MHz ; GPIO_Init(GPIOB,GPIO_InitStructure); GPIO_SetBits(GPIOB,GPIO_Pin_10 |GPIO_Pin_11); } void MyI2C_Start() { MyI2C_W_SDA(1); MyI2C_W_SCL(1); MyI2C_W_SDA(0); MyI2C_W_SCL(0); } void MyI2C_Stop() { MyI2C_W_SCL(0); MyI2C_W_SDA(0); MyI2C_W_SCL(1); MyI2C_W_SDA(1); } void MyI2C_SendByte(uint8_t Byte) { for(uint8_t i0;i8;i) { MyI2C_W_SDA(Byte(0x80i)); MyI2C_W_SCL(1); MyI2C_W_SCL(0); } } uint8_t MyI2C_ReceiveByte() { uint8_t Byte0x00; uint8_t i0; MyI2C_W_SDA(1); for(i0;i8;i) { MyI2C_W_SCL(1); if(MyI2C_R_SDA()1) { Byte|(0x80i); } // MyI2C_W_SCL(1); MyI2C_W_SCL(0); } return Byte; } void MyI2C_SendACK(uint8_t ACKBit) { MyI2C_W_SDA(ACKBit); MyI2C_W_SCL(1); MyI2C_W_SCL(0); } uint8_t MyI2C_ReceiveACK() { uint8_t ACKBit ; MyI2C_W_SDA(1); MyI2C_W_SCL(1); ACKBit MyI2C_R_SDA(); MyI2C_W_SCL(0); return ACKBit; } //连续读 void MyI2C_ReadMulti(uint8_t Addr,uint8_t Reg,uint8_t*Buff,uint8_t Lenth) { MyI2C_Start(); MyI2C_SendByte(Addr); MyI2C_ReceiveACK(); MyI2C_SendByte(Reg); MyI2C_ReceiveACK(); MyI2C_Start(); MyI2C_SendByte(Addr |0x01); MyI2C_ReceiveACK(); for(uint8_t i0;iLenth;i) { Buff[i] MyI2C_ReceiveByte(); if(i Lenth-1) { MyI2C_SendACK(1); } else { MyI2C_SendACK(0); } } MyI2C_Stop(); }2、MPU6050.c文件#include stm32f10x.h #include I2C.h #include MPU6050Req.h #include MPU6050.h #define MPU6050_ADDRESS 0xD0 void MPU6050_WriteReq(uint8_t ReqAddress,uint8_t Data) { MyI2C_Start(); MyI2C_SendByte(MPU6050_ADDRESS); MyI2C_ReceiveACK(); MyI2C_SendByte(ReqAddress); MyI2C_ReceiveACK(); MyI2C_SendByte(Data); MyI2C_ReceiveACK(); MyI2C_Stop(); } uint8_t MPU6050_ReadReq(uint8_t RegAddress) { uint8_t Data; MyI2C_Start(); MyI2C_SendByte(MPU6050_ADDRESS); MyI2C_ReceiveACK(); MyI2C_SendByte(RegAddress); MyI2C_ReceiveACK(); MyI2C_Start(); MyI2C_SendByte(MPU6050_ADDRESS|0x01); MyI2C_ReceiveACK(); Data MyI2C_ReceiveByte(); MyI2C_SendACK(1); MyI2C_Stop(); return Data; } void MPU6050_Init() { MyI2C_Init(); MPU6050_WriteReq(MPU6050_PWR_MGMT_1,0x01); MPU6050_WriteReq(MPU6050_PWR_MGMT_2,0x00); MPU6050_WriteReq(MPU6050_SMPLRT_DIV,0x09); MPU6050_WriteReq(MPU6050_CONFIG,0x06); MPU6050_WriteReq(MPU6050_GYRO_CONFIG,0x18); MPU6050_WriteReq(MPU6050_ACCEL_CONFIG,0x18); Delay_ms(100); } uint8_t GetID() { return MPU6050_ReadReq(MPU6050_WHO_AM_I); } uint8_t TestValue() { return MPU6050_ReadReq(MPU6050_PWR_MGMT_1); } void MPU6050_GetData(MPU6050_StructureData* SensorValue) { uint8_t Buff[14]; MyI2C_ReadMulti(MPU6050_ADDRESS,MPU6050_ACCEL_XOUT_H,Buff,14); SensorValue-AccX (int16_t)Buff[0]8 |Buff[1]; SensorValue-AccY (int16_t)Buff[2]8 |Buff[3]; SensorValue-AccZ (int16_t)Buff[4]8 |Buff[5]; SensorValue-GroX(int16_t)Buff[8]8 |Buff[9]; SensorValue-GroY (int16_t)Buff[10]8 |Buff[11]; SensorValue-GroZ (int16_t)Buff[12]8 |Buff[13]; }3、main函数#include stm32f10x.h #include Delay.h #include OLED.h #include MPU6050.h uint8_t ID; int16_t AccX,AccY,AccZ,GroX,GroY,GroZ; MPU6050_StructureData Sensor_Value; int main() { OLED_Init(); MPU6050_Init(); ID GetID(); Test TestValue(); OLED_ShowHexNum(1,1,ID,2); while(1) { MPU6050_GetData(Sensor_Value); OLED_ShowSignedNum(2,1,Sensor_Value.AccX,5); OLED_ShowSignedNum(3,1,Sensor_Value.AccY,5); OLED_ShowSignedNum(4,1,Sensor_Value.AccZ,5); OLED_ShowSignedNum(2,8,Sensor_Value.GroX,5); OLED_ShowSignedNum(3,8,Sensor_Value.GroY,5); OLED_ShowSignedNum(4,8,Sensor_Value.GroZ,5); Delay_ms(100); } }结果量程配置±16g平放时AccZ≈2048AccX、AccY在0附近小范围跳动。陀螺仪静止全部接近0手动转动模块正负值来回变化。本文完
返回列表