• 【第六章】STM32 - 软件I2C读取MPU6050


    关联:

    STM32总结超全笔记【秋招自用】icon-default.png?t=N7T8https://blog.csdn.net/Xiaoxuexxxxx/article/details/137509422?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22137509422%22%2C%22source%22%3A%22Xiaoxuexxxxx%22%7D

    【MPU6050】

            MPU6050是一个6轴姿态传感器,由三个陀螺仪和三个加速度传感器组成。可以测量芯片自身X、Y、Z轴的加速度、角速度参数。通过数据融合,可进一步得到姿态角,常应用于平衡车、飞控等。

    【引脚说明】

    SCL时钟线,SDA数据线不必多说。

    【问】XDA和XCL是什么??

    辅助I2C连接其他器件,比如说电磁传感器,成为一个九轴传感器。

    【AD0】地址管脚:连接GND时为0,此时从机地址068。连VCC时为1,从机地址0x69。

    【INT】中断引脚。

    平常MPU6050作为从机,只需要四个引脚VCC、GND、SCL和SDA就够了。

    【软件模拟IIC】

    然后我们再过一遍STM32软件模拟IIC代码:

    1. //I2C写SCL引脚电平
    2. void MyI2C_W_SCL(uint8_t BitValue)
    3. {
    4. GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue);
    5. Delay_us(10);
    6. }
    7. //I2C写SDA引脚电平
    8. void MyI2C_W_SDA(uint8_t BitValue)
    9. {
    10. GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)BitValue); //根据BitValue,设置SDA引脚的电平,BitValue要实现非0即1的特性
    11. Delay_us(10); //延时10us,防止时序频率超过要求
    12. }
    13. //I2C读SDA引脚电平
    14. uint8_t MyI2C_R_SDA(void)
    15. {
    16. uint8_t BitValue;
    17. BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11); //读取SDA电平
    18. Delay_us(10); //延时10us,防止时序频率超过要求
    19. return BitValue; //返回SDA电平
    20. }
    21. //I2C初始化
    22. void MyI2C_Init(void)
    23. {
    24. /*开启时钟*/
    25. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB的时钟
    26. /*GPIO初始化*/
    27. GPIO_InitTypeDef GPIO_InitStructure;
    28. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    29. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
    30. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    31. GPIO_Init(GPIOB, &GPIO_InitStructure); //将PB10和PB11引脚初始化为开漏输出
    32. /*设置默认电平*/
    33. GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11); //设置PB10和PB11引脚初始化后默认为高电平(释放总线状态)
    34. }
    35. //I2C起始
    36. void MyI2C_Start(void)
    37. {
    38. MyI2C_W_SDA(1); //释放SDA,确保SDA为高电平
    39. MyI2C_W_SCL(1); //释放SCL,确保SCL为高电平
    40. MyI2C_W_SDA(0); //在SCL高电平期间,拉低SDA,产生起始信号
    41. MyI2C_W_SCL(0); //起始后把SCL也拉低,即为了占用总线,也为了方便总线时序的拼接
    42. }
    43. //I2C终止
    44. void MyI2C_Stop(void)
    45. {
    46. MyI2C_W_SDA(0); //拉低SDA,确保SDA为低电平
    47. MyI2C_W_SCL(1); //释放SCL,使SCL呈现高电平
    48. MyI2C_W_SDA(1); //在SCL高电平期间,释放SDA,产生终止信号
    49. }
    50. //I2C发送一个字节
    51. void MyI2C_SendByte(uint8_t Byte)
    52. {
    53. uint8_t i;
    54. for (i = 0; i < 8; i ++) //循环8次,主机依次发送数据的每一位
    55. {
    56. MyI2C_W_SDA(Byte & (0x80 >> i)); //使用掩码的方式取出Byte的指定一位数据并写入到SDA线
    57. MyI2C_W_SCL(1); //释放SCL,从机在SCL高电平期间读取SDA
    58. MyI2C_W_SCL(0); //拉低SCL,主机开始发送下一位数据
    59. }
    60. }
    61. //I2C接收一个字节
    62. uint8_t MyI2C_ReceiveByte(void)
    63. {
    64. uint8_t i, Byte = 0x00; //定义接收的数据,并赋初值0x00,此处必须赋初值0x00,后面会用到
    65. MyI2C_W_SDA(1); //接收前,主机先确保释放SDA,避免干扰从机的数据发送
    66. for (i = 0; i < 8; i ++) //循环8次,主机依次接收数据的每一位
    67. {
    68. MyI2C_W_SCL(1); //释放SCL,主机机在SCL高电平期间读取SDA
    69. if (MyI2C_R_SDA() == 1){Byte |= (0x80 >> i);} //读取SDA数据,并存储到Byte变量
    70. //当SDA为1时,置变量指定位为1,当SDA为0时,不做处理,指定位为默认的初值0
    71. MyI2C_W_SCL(0); //拉低SCL,从机在SCL低电平期间写入SDA
    72. }
    73. return Byte; //返回接收到的一个字节数据
    74. }
    75. //I2C发送应答位
    76. void MyI2C_SendAck(uint8_t AckBit)
    77. {
    78. MyI2C_W_SDA(AckBit); //主机把应答位数据放到SDA线
    79. MyI2C_W_SCL(1); //释放SCL,从机在SCL高电平期间,读取应答位
    80. MyI2C_W_SCL(0); //拉低SCL,开始下一个时序模块
    81. }
    82. //I2C接收应答位
    83. uint8_t MyI2C_ReceiveAck(void)
    84. {
    85. uint8_t AckBit; //定义应答位变量
    86. MyI2C_W_SDA(1); //接收前,主机先确保释放SDA,避免干扰从机的数据发送
    87. MyI2C_W_SCL(1); //释放SCL,主机机在SCL高电平期间读取SDA
    88. AckBit = MyI2C_R_SDA(); //将应答位存储到变量里
    89. MyI2C_W_SCL(0); //拉低SCL,开始下一个时序模块
    90. return AckBit; //返回定义应答位变量
    91. }

    【例程12】软件I2C读取MPU6050

    PB10 - SDA

    PB11 - SCL

    【GPIO初始化】

    1. void MyI2C_Init(void)
    2. {
    3. /*开启时钟*/
    4. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB的时钟
    5. /*GPIO初始化*/
    6. GPIO_InitTypeDef GPIO_InitStructure;
    7. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    8. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
    9. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    10. GPIO_Init(GPIOB, &GPIO_InitStructure); //PB10和PB11引脚初始化为开漏输出
    11. GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11); //设置PB10和PB11引脚初始化后默认为高电平(释放总线状态)
    12. }

    【写数据到MPU6050寄存器】

    1. void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
    2. {
    3. MyI2C_Start(); //I2C起始
    4. MyI2C_SendByte(MPU6050_ADDRESS); //发送从机地址,读写位为0,表示即将写入
    5. MyI2C_ReceiveAck(); //接收应答
    6. MyI2C_SendByte(RegAddress); //发送寄存器地址
    7. MyI2C_ReceiveAck(); //接收应答
    8. MyI2C_SendByte(Data); //发送要写入寄存器的数据
    9. MyI2C_ReceiveAck(); //接收应答
    10. MyI2C_Stop(); //I2C终止
    11. }

    【读数据从MPU6050寄存器】

    1. uint8_t MPU6050_ReadReg(uint8_t RegAddress)
    2. {
    3. uint8_t Data;
    4. MyI2C_Start(); //I2C起始
    5. MyI2C_SendByte(MPU6050_ADDRESS); //发送从机地址,读写位为0,表示即将写入
    6. MyI2C_ReceiveAck(); //接收应答
    7. MyI2C_SendByte(RegAddress); //发送寄存器地址
    8. MyI2C_ReceiveAck(); //接收应答
    9. MyI2C_Start(); //I2C重复起始
    10. MyI2C_SendByte(MPU6050_ADDRESS | 0x01); //发送从机地址,读写位为1,表示即将读取
    11. MyI2C_ReceiveAck(); //接收应答
    12. Data = MyI2C_ReceiveByte(); //接收指定寄存器的数据
    13. MyI2C_SendAck(1); //发送应答,给从机非应答,终止从机的数据输出
    14. MyI2C_Stop(); //I2C终止
    15. return Data;
    16. }

    【MPU6050初始化】

    1. #define MPU6050_SMPLRT_DIV 0x19
    2. #define MPU6050_CONFIG 0x1A
    3. #define MPU6050_GYRO_CONFIG 0x1B
    4. #define MPU6050_ACCEL_CONFIG 0x1C
    5. #define MPU6050_ACCEL_XOUT_H 0x3B
    6. #define MPU6050_ACCEL_XOUT_L 0x3C
    7. #define MPU6050_ACCEL_YOUT_H 0x3D
    8. #define MPU6050_ACCEL_YOUT_L 0x3E
    9. #define MPU6050_ACCEL_ZOUT_H 0x3F
    10. #define MPU6050_ACCEL_ZOUT_L 0x40
    11. #define MPU6050_TEMP_OUT_H 0x41
    12. #define MPU6050_TEMP_OUT_L 0x42
    13. #define MPU6050_GYRO_XOUT_H 0x43
    14. #define MPU6050_GYRO_XOUT_L 0x44
    15. #define MPU6050_GYRO_YOUT_H 0x45
    16. #define MPU6050_GYRO_YOUT_L 0x46
    17. #define MPU6050_GYRO_ZOUT_H 0x47
    18. #define MPU6050_GYRO_ZOUT_L 0x48
    19. #define MPU6050_PWR_MGMT_1 0x6B
    20. #define MPU6050_PWR_MGMT_2 0x6C
    21. #define MPU6050_WHO_AM_I 0x75
    22. void MPU6050_Init(void)
    23. {
    24. MyI2C_Init(); //先初始化底层的I2C
    25. /*MPU6050寄存器初始化,需要对照MPU6050手册的寄存器描述配置,此处仅配置了部分重要的寄存器*/
    26. MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01); //电源管理寄存器1,取消睡眠模式,选择时钟源为X轴陀螺仪
    27. MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00); //电源管理寄存器2,保持默认值0,所有轴均不待机
    28. MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09); //采样率分频寄存器,配置采样率
    29. MPU6050_WriteReg(MPU6050_CONFIG, 0x06); //配置寄存器,配置DLPF
    30. MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18); //陀螺仪配置寄存器,选择满量程为±2000°/s
    31. MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18); //加速度计配置寄存器,选择满量程为±16g
    32. }

    【读寄存器获取数据】

    1. void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ,
    2. int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ)
    3. {
    4. uint8_t DataH, DataL; //定义数据高8位和低8位的变量
    5. DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H); //读取加速度计X轴的高8位数据
    6. DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L); //读取加速度计X轴的低8位数据
    7. *AccX = (DataH << 8) | DataL; //数据拼接,通过输出参数返回
    8. DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H); //读取加速度计Y轴的高8位数据
    9. DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L); //读取加速度计Y轴的低8位数据
    10. *AccY = (DataH << 8) | DataL; //数据拼接,通过输出参数返回
    11. DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H); //读取加速度计Z轴的高8位数据
    12. DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L); //读取加速度计Z轴的低8位数据
    13. *AccZ = (DataH << 8) | DataL; //数据拼接,通过输出参数返回
    14. DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H); //读取陀螺仪X轴的高8位数据
    15. DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L); //读取陀螺仪X轴的低8位数据
    16. *GyroX = (DataH << 8) | DataL; //数据拼接,通过输出参数返回
    17. DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H); //读取陀螺仪Y轴的高8位数据
    18. DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L); //读取陀螺仪Y轴的低8位数据
    19. *GyroY = (DataH << 8) | DataL; //数据拼接,通过输出参数返回
    20. DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H); //读取陀螺仪Z轴的高8位数据
    21. DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L); //读取陀螺仪Z轴的低8位数据
    22. *GyroZ = (DataH << 8) | DataL; //数据拼接,通过输出参数返回
    23. }

    【主函数】

    MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ);		//获取MPU6050的数据
    

  • 相关阅读:
    SAM资料
    ARMv7处理器
    JAVA毕设项目软考网络工程师在线练习平台(java+VUE+Mybatis+Maven+Mysql)
    maven的下载、配置
    计算机毕设 大数据工作岗位数据分析与可视化 - python flask
    为什么阿里人能够快速成长?看完他们 Java 架构进化笔记,我秒懂!
    个人主页汇总 | 私信没空看,建议b站
    【仿牛客网笔记】项目进阶,构建安全高效的企业服务——将文件上传至云服务器
    如何制作并运行 jar 程序
    《Android Studio开发实战 从零基础到App上线(第3版)》出版后记
  • 原文地址:https://blog.csdn.net/Xiaoxuexxxxx/article/details/138185714