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.主发送器

  • 首先生成I2Cx(这里x可选择1或者2)通信START条件并打开(ENABLE)并进行检测EV5事件。(EV5事件被触发后自动进行的,不是代码程序控制而产生的)
  • 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发送从机地址,方向为发送(软件读写时从机地址最低位置为0),然后检测EV6事件
  • 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发送寄存器地址,并等待EV8事件
  • 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;
    }

    作者:@遗~

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32硬件I2C读取MPU6050读写配置

    发表回复