STM32硬件I2C读取MPU6050读写配置
1.I2C功能框图
由于STM32速度远远高于I2C外设最高速度(400kb/s),所以需要设置等待函数来延时检测,确保上一步任务完成后,方可进行下一步,否则可能造成数据覆盖和错乱。
2.等待延时检测函数
#include "stm32f10x.h" // Device header
#include "MPU6050_Reg.h"
#define MPU6050_ADDRESS 0xD0 //MPU6050的I2C从机地址
/**
* 函 数:MPU6050等待事件
* 参 数:同I2C_CheckEvent
* 返 回 值:无
*/
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) //自减到0后,等待超时
{
/*超时的错误处理代码,可以添加到此处*/
break; //跳出等待,不等了
}
3.主发送器
I2C_GenerateSTART(I2C2, ENABLE); //硬件I2C生成起始条件
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT); //等待EV5
EV5事件解释
– 触发条件:当I2C 总线产生起始条件(S=Start)后,会触发EV5事件。此时,状态寄存器SR1中的“SB”(Start bit,起始位)标志会被置1,表示起始条件已经成功发送到总线上 。
– 清除方式:在检测到SR1寄存器中的“SB = 1”后,软件需要读取SR1寄存器,然后将从机地址写入数据寄存器DR,完成这两个操作后,EV5事件就会被清除。这一过程确保了I2C通信的有序进行,使得主设备可以继续进行后续的从机寻址等操作。
简单来说,EV5事件标志着I2C通信起始条件已发送成功,是主设备向从机发送数据前的关键步骤,通过特定的寄存器操作来清除该事件,从而推进通信流程。
I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Transmitter); //硬件I2C发送从机地址,方向为发送
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); //等待EV6
EV6事件解释
– 触发条件:当主发送器发送完从机地址和读写方向位后,若从机给出响应,此时状态寄存器SR1中的ADDR(Address sent,地址已发送标志)会被置1,触发EV6事件,表示从机地址已成功发送且收到从机响应 。
– 清除方式:需要先读取SR1寄存器以确认ADDR = 1,再读取状态寄存器SR2,完成这两步操作后,EV6事件即被清除。读取SR2是为了获取更多关于当前通信状态的信息,如从机地址的相关细节等。
EV6事件标志着主设备与从机间的地址交互成功,为后续数据传输做好准备,正确清除该事件才能使通信流程顺利进行。
I2C_SendData(I2C2, RegAddress); //硬件I2C发送寄存器地址
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING); //等待EV8
EV8事件解释
– 触发条件:当移位寄存器中的数据传输到总线上,使得数据寄存器DR为空时,状态寄存器SR1中的TxE(Transmit data register empty,发送数据寄存器为空)标志会被置1,触发EV8事件,表明可以向数据寄存器DR写入下一个要发送的数据字节 。
– 清除方式:在检测到SR1寄存器中的TxE = 1后,将下一个要发送的数据写入DR寄存器,即可清除EV8事件。这保证了数据传输的连续性,使主设备能够持续发送数据。
EV8事件确保主发送器及时补充新数据,维持I2C通信中数据的持续发送,是实现稳定数据传输的重要环节。
硬件I2C发送数据,并等待EV8_2事件
I2C_SendData(I2C2, Data); //硬件I2C发送数据
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED); //等待EV8_2
EV8-2事件解释
– 触发条件:当主发送器完成最后一个字节数据的发送,此时状态寄存器SR1中的TxE(发送数据寄存器为空)和BTF(字节传输完成)标志均被置1,触发EV8_2事件。这表明当前字节数据已发送完毕,且数据寄存器为空,同时字节传输也已完成。
– 清除方式:EV8_2事件中,TxE和BTF标志由硬件在产生停止条件(P=Stop)时自动清除。该事件出现后,意味着主发送器即将结束此次数据传输任务,可根据需要发送停止条件来终止I2C通信。
EV8_2事件标志着主发送器数据发送接近尾声,是I2C通信结束前的关键状态指示 。
I2C生成终止条件
I2C_GenerateSTOP(I2C2, ENABLE); //硬件I2C生成终止条件
总结
/**
* 函 数:MPU6050写寄存器
* 参 数:RegAddress 寄存器地址,范围:参考MPU6050手册的寄存器描述
* 参 数:Data 要写入寄存器的数据,范围:0x00~0xFF
* 返 回 值:无
*/
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{
I2C_GenerateSTART(I2C2, ENABLE); //硬件I2C生成起始条件
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT); //等待EV5
I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Transmitter); //硬件I2C发送从机地址,方向为发送
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); //等待EV6
I2C_SendData(I2C2, RegAddress); //硬件I2C发送寄存器地址
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING); //等待EV8
I2C_SendData(I2C2, Data); //硬件I2C发送数据
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED); //等待EV8_2
I2C_GenerateSTOP(I2C2, ENABLE); //硬件I2C生成终止条件
}
4.主接收器
1.前几步与前边重复不再解释
I2C_GenerateSTART(I2C2, ENABLE); //硬件I2C生成起始条件
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT); //等待EV5
I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Transmitter); //硬件I2C发送从机地址,方向为发送
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); //等待EV6
I2C_SendData(I2C2, RegAddress); //硬件I2C发送寄存器地址
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED); //等待EV8_2
2.这里需要重复发送起始条件,方向为接收方向,直接调用相关函数(软件读I2C时需要从机地址末尾置1)
I2C_GenerateSTART(I2C2, ENABLE); //硬件I2C生成重复起始条件
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT); //等待EV5
I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Receiver); //硬件I2C发送从机地址,方向为接收
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED); //等待EV6
3.在接收最后一个字节之前提前将应答失能,提前申请停止条件。
I2C_AcknowledgeConfig(I2C2, DISABLE); //在接收最后一个字节之前提前将应答失能
I2C_GenerateSTOP(I2C2, ENABLE); //在接收最后一个字节之前提前申请停止条件
4.等待EV7事件,并且接收数据寄存器
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED); //等待EV7
Data = I2C_ReceiveData(I2C2); //接收数据寄存器
EV7事件解释
– 触发条件:当从机向主接收器发送数据,主接收器的接收数据寄存器DR接收到数据后,状态寄存器SR1中的RxNE(Receive data register not empty,接收数据寄存器非空)标志会被置1,此时触发EV7事件,表示主接收器已成功接收到一个字节的数据。
– 清除方式:检测到SR1寄存器中的RxNE = 1后,通过读取DR寄存器,将其中接收到的数据读出,即可清除EV7事件。这样能使主接收器准备好接收下一个字节的数据,保证数据接收的连续性。
EV7事件是主接收器获取从机发送数据的关键状态指示,正确处理该事件能确保I2C通信中数据接收的顺利进行。
EV7-1事件解释
– 触发条件:当主接收器在I2C通信中接收到最后一个字节的数据后,且此时从机发送了应答信号,同时状态寄存器SR1中的RxNE(接收数据寄存器非空)标志依然为1,且BTF(字节传输完成)标志也被置1时,就会触发EV7_1事件。这表明主接收器已经成功接收完所有数据,并且从机也完成了应答操作。
– 清除方式:通常在检测到SR1寄存器中的RxNE = 1和BTF = 1后,通过读取数据寄存器DR来获取接收到的最后一个字节数据,之后再根据具体的I2C通信配置和需求,可能需要设置相关寄存器位来产生停止条件(如果通信结束)等操作,以清除EV7_1事件相关标志位,使I2C模块准备好进行下一次通信或进入待机等其他状态。
5.将应答恢复为使能,为了不影响后续可能产生的读取多字节操作
I2C_AcknowledgeConfig(I2C2, ENABLE);
return Data;
总结
/**
* 函 数:MPU6050读寄存器
* 参 数:RegAddress 寄存器地址,范围:参考MPU6050手册的寄存器描述
* 返 回 值:读取寄存器的数据,范围:0x00~0xFF
*/
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{
uint8_t Data;
I2C_GenerateSTART(I2C2, ENABLE); //硬件I2C生成起始条件
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT); //等待EV5
I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Transmitter); //硬件I2C发送从机地址,方向为发送
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); //等待EV6
I2C_SendData(I2C2, RegAddress); //硬件I2C发送寄存器地址
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED); //等待EV8_2
I2C_GenerateSTART(I2C2, ENABLE); //硬件I2C生成重复起始条件
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT); //等待EV5
I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Receiver); //硬件I2C发送从机地址,方向为接收
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED); //等待EV6
I2C_AcknowledgeConfig(I2C2, DISABLE); //在接收最后一个字节之前提前将应答失能
I2C_GenerateSTOP(I2C2, ENABLE); //在接收最后一个字节之前提前申请停止条件
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED); //等待EV7
Data = I2C_ReceiveData(I2C2); //接收数据寄存器
I2C_AcknowledgeConfig(I2C2, ENABLE); //将应答恢复为使能,为了不影响后续可能产生的读取多字节操作
return Data;
}
作者:@遗~