STM32CubeMX教程19 I2C - MPU6050驱动
1、准备材料
STM32CubeMX软件(Version 6.10.0)
keil µVision5 IDE(MDK-Arm)
逻辑分析仪nanoDLA
2、实验目标
使用STM32CubeMX软件配置STM32F407开发板的I2C1与MPU6050芯片通信,读取MPU6050的三轴加速度和陀螺仪数据并通过串口打印出来
3、实验流程
3.0、前提知识
本实验重点是理解I2C通信协议,而STM32CubeMX的配置则相对简单,这里不会过于详细全面的介绍I2C通信协议,但是会对所有需要知道的知识做介绍
在我们的开发板上有一颗三轴加速度计和陀螺仪传感器MPU6050,单片机通过I2C1的PB8和PB9两个引脚与MPU6050进行通信,MPU6050还有一个中断引脚,这里为3D_INT引脚,但是本实验仅仅轮询读取加速度计和陀螺仪的数据,并没有用到该引脚中断功能,我们使用的开发板上的MPU6050芯片硬件原理图如下图所示

I2C通信仅需要时钟线SCLK和数据线SDA两根线就可以让主机与挂载在I2C上的从机进行通信和数据交换,一个I2C理论上最多可挂载127个设备(从机地址用7位二进制表示)
为了让主机准确的与众多从机中的一个进行通信,每个从机都会有一个地址,I2C通信时会在通信数据中先发送从机地址,然后对应地址的从机才会响应
而且I2C通信使用的时钟线SCLK和数据线SDA两根线必须要做上拉设置,因为I2C的两个引脚被配置为开漏输出,因此无法输出高电平,I2C总线连线图如下图所示 (注释1)

MPU6050的从机地址由芯片上的AD0引脚确定,当AD0引脚接地时,从机地址为0X68;
当AD0引脚接VCC时,从机地址为0X69;
根据上面MPU6050芯片硬件原理图可知此时MPU6050的从机地址为0X68
根据MPU6050 datasheet 9.3 I2C Communications Protocol 小节可知 (注释2),主机要通过I2C写入/读取MPU6050某一个寄存器一字节的数据,其通信步骤序列应该如下图所示


我们以读取内部寄存器单个字节数据为例做详细介绍,首先确定通信的目的为主机Master从从机Slave内部某个寄存器internal register中读取一个字节数据,以下为详细通信步骤
- 主机时钟线SCLK和数据线SDA两根线产生起始信号(当 SCL 线是高电平时 SDA 线从高电平向低电平切换)
- 接下来时钟线SCLK的8个时钟节拍中,由数据线SDA发送一字节8位的数据,其中高7位为从机的地址,最后一位为0(1表示读操作,0表示写操作)
- 接下来1个时钟节拍,从机应该产生应答信号ACK
- 接下来8个时钟节拍,主机发送一字节8位的数据,该数据为要读取的从机内部寄存器地址
- 接下来1个时钟节拍,从机应该产生应答信号ACK
- 主机重新产生一个起始信号
- 接下来8个时钟节拍,重新发送一字节8位的数据,其中高7位为从机的地址,最后一位为1,表示这次要读
- 接下来1个时钟节拍,从机应该产生应答信号ACK
- 接下来8个时钟节拍,主机读取一字节8位数据
- 接下来1个时钟节拍,主机应该产生应答信号NACK
- 主机时钟线SCLK和数据线SDA两根线产生停止信号(当 SCL 线是高电平时 SDA 线由低电平向高电平切换)
接下来我们用逻辑分析仪捕获下主机使用I2C1读取MPU6050寄存器WHO_AM_I(0X75)时,时钟线SCLK和数据线SDA的逻辑电平变化,如下图所示,从图上可知I2C读取读取MPU6050内部寄存器的时序与上面我们所描述的一致


用逻辑分析仪捕获主机使用I2C1向MPU6050寄存器PWR_MGMT_1(0X6B)写入一字节0X00数据时,时钟线SCLK和数据线SDA的逻辑电平变化,如下图所示


为什么上图中从机地址从0X68变为0XD0了?
HAL库中的I2C写入函数HAL_I2C_Mem_Write()和读取函数HAL_I2C_Mem_Read()对传入从机地址DevAddress参数做了要求,该地址必须将数据手册中提到的地址左移才可以调用该接口
0X68(0110 1000)向左移动直到遇到1即为0XD0(1101 0000),在I2C通信中使用上述两个API,从机地址传入0XD0表示对从机地址为0X68的从机进行写操作,传入0XD1表示对从机地址为0X68的从机进行读操作
如下图为HAL库HAL_I2C_Mem_Read()函数说明

上面提到,当启用I2C之后,其I2C_SCL和I2C_SDA两个引脚被配置为了复用功能开漏输出,而开漏输出无法输出高电平,因此I2C_SCL和I2C_SDA两个引脚需要外部上拉,一般的开发板都会考虑到这一点,在设计原理图的时候将使用的I2C两根线给外部上拉到3.3V,如果你使用的是自己设计的板子,请务必记住I2C需要上拉
细心的同学可能又发现了,你上面给出的MPU6050硬件原理图I2C两根线并没有外部上拉呀?
虽然MPU6050硬件原理图I2C两根线没有上拉,但是在开发板的其他I2C通信的芯片上进行了外部上拉,如下图所示

3.1、CubeMX相关配置
3.1.0、工程基本配置
打开STM32CubeMX软件,单击ACCESS TO MCU SELECTOR选择开发板MCU(选择你使用开发板的主控MCU型号),选中MCU型号后单击页面右上角Start Project开始工程,具体如下图所示


开始工程之后在配置主页面System Core/RCC中配置HSE/LSE晶振,在System Core/SYS中配置Debug模式,具体如下图所示


详细工程建立内容读者可以阅读“STM32CubeMX教程1 工程建立”
3.1.1、时钟树配置
系统时钟使用8MHz外部高速时钟HSE,HCLK、PCLK1和PCLK2均设置为STM32F407能达到的最高时钟频率,具体如下图所示

3.1.2、外设参数配置
实验需要通过串口来输出与MPU6050进行I2C通信读取的陀螺仪和加速度计数据,因此外设需要初始化USART1和I2C1
单击Pinout & Configuration页面左边Connectivity/USART1选项,然后按照“STM32CubeMX教程9 USART/UART 异步通信”实验中将USART1配置为异步通信模式,无需开启中断,如下图所示

在Pinout & Configuration页面右边芯片引脚预览Pinout view中找到与开发板上MPU6050芯片连接的I2C的两个通信引脚PB8和PB9,左边单击将其分别配置为I2C1_SCL和I2C1_SDA
然后单击Connectivity/I2C1选项,在其模式中选择I2C,在下方Master Features中将 I2C Speed Mode 根据用户需求选择快速模式(400kkHz)或者标准模式(100kHz),这两种模式仅仅影响通信速率,对于本实验两个模式均可随意选择
其他参数保持默认即可,具体配置如下图所示

3.1.3、外设中断配置
本实验无需启用中断,如果需要启用I2C1的中断,请单击System Core/NVIC,然后根据需求勾选I2C1的事件或错误中断,并选择合适的中断优先级即可,具体配置如下图所示

3.2、生成代码
3.2.0、配置Project Manager页面
单击进入Project Manager页面,在左边Project分栏中修改工程名称、工程目录和工具链,然后在Code Generator中勾选“Gnerate peripheral initialization as a pair of ‘c/h’ files per peripheral”,最后单击页面右上角GENERATE CODE生成工程,具体如下图所示


详细Project Manager配置内容读者可以阅读“STM32CubeMX教程1 工程建立”实验3.4.3小节
3.2.1、外设初始化调用流程
还是一模一样的流程,与该系列教程所有的外设初始化一致
在生成的工程代码主函数中新增了MX_I2C1_Init()函数,在该函数中实现了对I2C1的模式及参数配置
在MX_I2C1_Init()函数中调用了HAL_I2C_Init()函数使用配置的参数对I2C1进行了初始化
在HAL_I2C_Init()函数中又调用了HAL_I2C_MspInit()函数对I2C1引脚复用设置,I2C1时钟使能,如果开启了中断该函数中还会有中断相关设置及使能
如下图所示为I2C1初始化调用流程

3.2.2、外设中断调用流程
本实验无需中断,因此未启动任何I2C1的中断
3.2.3、添加其他必要代码
需要添加MPU6050的驱动文件,文件中至少应该包括
- MPU6050初始化函数
- MPU6050获取三轴加速度计原始数据函数
- MPU6050获取三轴陀螺仪原始数据函数
注意本实验只使用而不会介绍MPU6050具体驱动文件的原理,具体源代码如下所示 (注释3)
mpu6050.c文件
1 |
|
mpu6050.h文件
1 |
|
在keil中添加.c/.h文件步骤如下图所示


然后将源代码复制到新建的.c/.h文件中,最后将.c文件添加到工程即可,如下图所示

在主函数中初始化MPU6050,主循环中获取原始的三轴加速度数据和三轴陀螺仪数据,并通过串口打印信息

源代码如下
1 |
|
4、常用函数
1 |
|
5、烧录验证
烧录程序,上电后开启串口,可以看到源源不断的输出当前MPU6050三轴加速度数据和三轴陀螺仪数据,移动开发板会发现数据有规律改变,如下图所示为串口输出的数据

6、注释详解
注释1:图片来源 I2C通信协议介绍 - 知乎
注释2:MPU6050 Datasheet https://invensense.tdk.com/wp-content/uploads/2015/02/MPU-6000-Datasheet1.pdf
注释3:MPU6050驱动库参考 https://github.com/leech001/MPU6050