STM32 I2C(四)硬件读写MPU6050

STM32 I2C(四)硬件读写MPU6050

程序思路

  • 第一步,配置I2C2外设,对I2C2外设进行初始化。
    • 开启I2C外设和对应GPIO口的时钟
    • 把I2C外设对应的GPIO口初始化为复用开漏模式
    • 使用结构体,对整个I2C进行配置
    • I2C_Cmd,使能I2C
  • 第二步,控制外设电路,实现指定地址写的时序。
  • 第三步,控制外设电路,实现指定地址读的时序。

程序示例

MPU6050.c

#include "stm32f10x.h"                  // Device header
#include "MPU6050_Reg.h"
#include "Delay.h"
#include "Oled.h"

#define MPU6050_ADDRESS 0xD0

void MPU6050_WaitEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)//防止死循环
{
    uint32_t Timeout;
    Timeout = 10000;
    while(I2C_CheckEvent(I2Cx,I2C_EVENT)!=SUCCESS)
    {
        Timeout--;
        if(Timeout==0)
        {
            break;
        }
    }
}
void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data)//指定地址写 8位从机地址 8位数据
{
    I2C_GenerateSTART(I2C2,ENABLE);//生成起始条件(硬件I2C函数不是阻塞式的函数(没有延时),所以在函数结束之后,我们都要等待相应的标志位,)
    MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);//等待EV5事件(主机模式已选择) 主机模式选择 STM32默认为从机,发送起始条件后变为主机,

    I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter);//发送从机地址 和 读写位
    MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);//等待EV6事件 发送模式已选择
    
    I2C_SendData(I2C2,RegAddress);//发送指定寄存器地址 
    MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTING);//等待EV8事件 字节正在发送
    
    I2C_SendData(I2C2,Data);//发送数据(发送完最后一个字节)
    MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED);//等待EV8_2 字节已经发送完毕
    
    I2C_GenerateSTOP(I2C2,ENABLE);//生成终止条件
}
uint8_t MPU6050_ReadReg(uint8_t RegAddress)//指定地址读
{
    uint8_t Data;
    
    I2C_GenerateSTART(I2C2,ENABLE);//生成起始条件(硬件I2C函数不是阻塞式的函数(没有延时),所以在函数结束之后,我们都要等待相应的标志位,)
    MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);//等待EV5事件(主机模式已选择) 主机模式选择 STM32默认为从机,发送起始条件后变为主机,

    I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter);//发送从机地址 和 读写位 写
    MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);//等待EV6事件 发送模式已选择
    
    I2C_SendData(I2C2,RegAddress);//发送指定寄存器地址 
    MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED);//等待EV8事件 字节发送完成
    
    I2C_GenerateSTART(I2C2,ENABLE);//重复起始条件
    MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);//等待EV5事件(主机模式已选择) 主机模式选择 STM32默认为从机,发送起始条件后变为主机,
    
    I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Receiver);//发送从机地址 和 读写位 读
    MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);//等待EV6事件 接受模式已选择
    
    I2C_AcknowledgeConfig(I2C2,DISABLE);//设置ACK=0 不给应答
    I2C_GenerateSTOP(I2C2,ENABLE);//产生终止条件
    MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED);//等待EV7事件  
    
    Data = I2C_ReceiveData(I2C2);
    
    I2C_AcknowledgeConfig(I2C2,ENABLE);

    return Data;
}
void MPU6050_Init(void)
{
    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2,ENABLE);//开启I2C2的时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//开启GPIOB的时钟
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_OD;//复用开漏输出(将GPIO的控制权交给硬件外设)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    
    GPIO_Init(GPIOB,&GPIO_InitStructure);//初始化GPIOB
    
    
//    MyI2C_Init();  
    
    I2C_InitTypeDef I2C_InitStruct;
    I2C_InitStruct.I2C_Ack =I2C_Ack_Enable ;//ACK应答位配置
    I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit ;//指定STM32作为从机,可以相应几位的地址,响应7位或10位
    I2C_InitStruct.I2C_ClockSpeed = 100000;//SCL的时钟频率 50KHZ
    I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_16_9;//时钟占空比 2:1 低电平事件和高电平事件是2:1的比例关系
    I2C_InitStruct.I2C_Mode =I2C_Mode_I2C ;//I2C的模式
    I2C_InitStruct.I2C_OwnAddress1 = 0x00 ;//自身地址
    I2C_Init(I2C2,&I2C_InitStruct);

    
    I2C_Cmd(I2C2,ENABLE);
    
    
    //初始化配置
    MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x01);//电源管理寄存器1 解除睡眠 选择陀螺仪时钟
    MPU6050_WriteReg(MPU6050_PWR_MGMT_2,0x00);//电源管理寄存器2 6个轴均不待机
    MPU6050_WriteReg(MPU6050_SMPLRT_DIV,0x09);//采样率分频 采样分频为10
    MPU6050_WriteReg(MPU6050_CONFIG,0x06);//配置寄存器 滤波参数最大
    MPU6050_WriteReg(MPU6050_GYRO_CONFIG,0x18);//陀螺仪配置寄存器 选择最大量程
    MPU6050_WriteReg(MPU6050_ACCEL_CONFIG,0x18);//加速度计配置寄存器 选择最大量程
    //配置完之后,MPU6050内部就在连续不断地进行数据转换了,输出的数据就存放在数据寄存器中

}
uint8_t MPU6050_GetID(void)
{
    return MPU6050_ReadReg(MPU6050_WHO_AM_I);    
}
void MPU6050_GetData(int16_t * AccX,int16_t * AccY,int16_t * AccZ,//获取数据寄存器
                     int16_t * GyroX,int16_t * GyroY,int16_t * GyroZ)//通过指针,把主函数变量的地址传递到子函数来。子函数中,通过传递过来的地址,操作主函数的变量,这样,子函数结束后,主函数变量的值,就是子函数想要返回的值
{
    uint16_t DataH,DataL;
    //可以用I2C读取多个字节优化
    DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);//高8位数据
    DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);//低8位数据
    *AccX = (DataH<<8) | DataL;//高8位左移8位再或上低8位,得到加速度计X轴的16位数据,再把读到的数据通过指针返回回去
    //这个16位数据是一个用补码表示的有符号数
    
    DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);
    DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);
    *AccY = (DataH<<8) | DataL;
    
    DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);
    DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);
    *AccZ = (DataH<<8) | DataL;
    
    DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);
    DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);
    *GyroX = (DataH<<8) | DataL;
    
    DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);
    DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);
    *GyroY = (DataH<<8) | DataL;
    
    DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);
    DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);
    *GyroZ = (DataH<<8) | DataL;
}

MPU6050.h

#ifndef __MPU6050_H
#define __MPU6050_H

void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data);
uint8_t MPU6050_ReadReg(uint8_t RegAddress);
void MPU6050_Init(void);
void MPU6050_GetData(int16_t * AccX,int16_t * AccY,int16_t * AccZ,
                     int16_t * GyroX,int16_t * GyroY,int16_t * GyroZ);
uint8_t MPU6050_GetID(void);

#endif

mian.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MPU6050.h"
#include "MPU6050_Reg.h"

uint8_t ID;
int16_t AX,AY,AZ,GX,GY,GZ;

int main(void)
{
    OLED_Init();
    OLED_ShowString(1,1,"ID");
    
    MPU6050_Init();
    
    ID=MPU6050_GetID();
    OLED_ShowHexNum(1,4,ID,2);//获取ID号  
 
    while(1)
    {
      MPU6050_GetData(&AX,&AY,&AZ,&GX,&GY,&GZ);//获取加速度计和陀螺仪测量值
      OLED_ShowSignedNum(2,1,AX,5);
      OLED_ShowSignedNum(3,1,AY,5);
      OLED_ShowSignedNum(4,1,AZ,5);
      OLED_ShowSignedNum(2,8,GX,5);
      OLED_ShowSignedNum(3,8,GY,5);
      OLED_ShowSignedNum(4,8,GZ,5);
    }
}

问题待解决

用STM32 I2C 硬件读写MPU6050,出现读取ID和指定地址读寄存器的值均为0xD1,但第二天,莫名其妙就正常了。

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YRr YRr

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值