STM32笔记——模拟I2C与MPU6050通信

目录

一、I2C时序

1.1 指定地址写数据

1.2 指定地址读数据

二、MPU6050简介

2.1 MPU6050的参数

2.2 MPU6050的硬件电路

2.3 MPU6050框图


一、I2C时序

        在学习51单片机时,已经接触过I2C基本时序了,简单回顾一下。

I2C的基本时序有:

  • 起始信号、停止信号;
  • 接收一个字节、发送一个字节;
  • 接收应答、发送应答。

程序如下:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
/*
      *函数名      :MyI2C_W_SCL(uint8_t Bitvalue)
      *函数功能    :主机操作SCL线
      *输入        :Bitvalue:高电平还是低电平,范围0或1
      *输出        :无
*/
void MyI2C_W_SCL(uint8_t Bitvalue)
{
	GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction)Bitvalue);
	Delay_us(10);
}
/*
      *函数名      :MyI2C_R_SDA(void)
      *函数功能    :读取SDA线上的数据
      *输入        :无
      *输出        :bit:高电平还是低电平,范围0或1
*/
uint8_t MyI2C_R_SDA(void)
{
	uint8_t bit=0;
	bit=GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11);
	Delay_us(10);
	return bit;
}
/*
      *函数名      :MyI2C_W_SDA(uint8_t Bitvalue)
      *函数功能    :写数据到SDA线上
      *输入        :Bitvalue:高电平还是低电平,范围0或1
      *输出        :无
*/
void MyI2C_W_SDA(uint8_t Bitvalue)
{
	GPIO_WriteBit(GPIOB,GPIO_Pin_11,(BitAction)Bitvalue);
	Delay_us(10);
}
/*
      *函数名      :MyI2C_Init(void)
      *函数功能    :I2C初始化
      *输入        :无
      *输出        :无
*/
void MyI2C_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;//开漏输出模式
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11;
 	GPIO_Init(GPIOB, &GPIO_InitStructure);
}
/*
      *函数名      :MyI2C_Start(void)
      *函数功能    :I2C起始信号
      *输入        :无
      *输出        :无
*/
void MyI2C_Start(void)
{
	MyI2C_W_SDA(1);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(0);//保证每个时序单元操作完后,SCL为低电平
}
/*
      *函数名      :MyI2C_Stop(void)
      *函数功能    :I2C停止信号
      *输入        :无
      *输出        :无
*/
void MyI2C_Stop(void)
{
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(1);
}
/*
      *函数名      :MyI2C_WriteByte(uint8_t Byte)
      *函数功能    :主机写入一个字节数据
      *输入        :Byte:写入的数据   范围:0x00~0xff
      *输出        :无
*/
void MyI2C_WriteByte(uint8_t Byte)
{
	uint8_t i=0;
	for(i=0;i<8;i++)
	{
		MyI2C_W_SDA(Byte&(0x80)>>i);
		MyI2C_W_SCL(1);
		MyI2C_W_SCL(0);
	}	
}
/*
      *函数名      :MyI2C_ReadByte(void)
      *函数功能    :主机读取一个字节数据
      *输入        :无
      *输出        :Byte:读出的数据   范围:0x00~0xff
*/
uint8_t MyI2C_ReadByte(void)
{
	uint8_t i,Byte=0;
	MyI2C_W_SDA(1);//释放总线
	for(i=0;i<8;i++)
	{	
		MyI2C_W_SCL(1);
		if(MyI2C_R_SDA()==1){Byte|=0x80>>i;}
		MyI2C_W_SCL(0);
	}
	return	Byte;
}
/*
      *函数名      :MyI2C_SeedAck(uint8_t Ack)
      *函数功能    :主机发送应答
      *输入        :Ack:应答信号   可以是:0(应答)或1(非应答)
      *输出        :无
*/
void MyI2C_SeedAck(uint8_t Ack)
{
	MyI2C_W_SDA(Ack);
	MyI2C_W_SCL(1);
	MyI2C_W_SCL(0);
}
/*
      *函数名      :MyI2C_ReciveAck(void)
      *函数功能    :主机接收应答
      *输入        :无
      *输出        :Ack:应答信号   可以是:0(应答)或1(非应答)
*/
uint8_t MyI2C_ReciveAck(void)
{
	uint8_t Ack=0;
	MyI2C_W_SDA(1);
	MyI2C_W_SCL(1);
	Ack=MyI2C_R_SDA();
	MyI2C_W_SCL(0);
	return Ack;
}

1.1 指定地址写数据

  •  指定地址写: 对于指定设备(Slave Address),在指定地址(Reg Address)下,写入指定数据(Data)。

1.2 指定地址读数据

  • 指定地址读:对于指定设备(Slave Address),在指定地址(Reg Address)下,读取从机数据(Data)
  • 可以读取连续地址中的数据。

二、MPU6050简介

  • MPU6050是一个6轴姿态传感器,可以测量芯片自身X、Y、Z轴的加速度、角速度参数,通过数据融合,可进一步得到姿态角,常应用于平衡车、飞行器等需要检测自身姿态的场景
  • 3轴加速度计(Accelerometer):测量X、Y、Z轴的加速度
  • 3轴陀螺仪传感器(Gyroscope):测量X、Y、Z轴的角速度

2.1 MPU6050的参数

  • 16位ADC采集传感器的模拟信号,量化范围:-32768~32767
  • 加速度计满量程选择:±2、±4、±8、±16(g)
  • 陀螺仪满量程选择: ±250、±500、±1000、±2000(°/sec)
  • 可配置的数字低通滤波器
  • 可配置的时钟源
  • 可配置的采样分频 I2C从机地址:1101000(AD0=0)    1101001(AD0=1)

2.2 MPU6050的硬件电路

  • VCC、GND:电源
  • SCL、 SDA :I2C通信引脚
  • XCL、XDA:主机I2C通信引脚
  • AD0:从机地址最低位,可配置从机地址
  • INT:中断信号输出

2.3 MPU6050框图

  • 在使用MPU6050前要先初始化,包括:解除sleep状态、取消各个轴的待机、分频、低通滤波配置、加速度计配置、陀螺仪配置。这些都是通过写入寄存器数据来实现的。
  • MPU6050内置了AD转换器,自动将测量的模拟量转换成数字量,存放在对应的寄存器中,只需要对各个寄存器进行读操作,就可以把数据读取出来。

程序如下:

#include "stm32f10x.h"                  // Device header
#include "I2C.h"
#include "MPU6050_Reg.h"
#define MPU6050_address  0xD0

/*
      *函数名      :MPU6050_WriteReg(uint8_t regaddress,uint8_t Data)
      *函数功能    :指定寄存器地址,往MPU6050的寄存器中写入数据
      *输入        :regaddress:寄存器的地址  @ref MPU6050_Reg.h
					 Data	:写入的数据
      *输出        :无
*/
void MPU6050_WriteReg(uint8_t regaddress,uint8_t Data)
{
	MyI2C_Start();
	MyI2C_WriteByte(MPU6050_address);
	MyI2C_ReciveAck();
	MyI2C_WriteByte(regaddress);
	MyI2C_ReciveAck();
	MyI2C_WriteByte(Data);
	MyI2C_ReciveAck();
	MyI2C_Stop();
}
/*
      *函数名      :MPU6050_Init(void)
      *函数功能    :MPU6050初始化
      *输入        :无
      *输出        :无
*/
void MPU6050_Init(void)
{
	MyI2C_Init();
	MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x01);
	MPU6050_WriteReg(MPU6050_PWR_MGMT_2,0x00);
	MPU6050_WriteReg(MPU6050_SMPLRT_DIV,0x09);
	MPU6050_WriteReg(MPU6050_CONFIG,0x06);
	MPU6050_WriteReg(MPU6050_GYRO_CONFIG,0x18);
	MPU6050_WriteReg(MPU6050_ACCEL_CONFIG,0x18);
}
/*
      *函数名      :MPU6050_ReadReg(uint8_t regaddress)
      *函数功能    :指定寄存器地址,读取MPU6050寄存器中的数据
      *输入        :regaddress:寄存器的地址    @ref MPU6050_Reg.h
      *输出        :Data:读取的数据
*/
uint8_t MPU6050_ReadReg(uint8_t regaddress)
{
	uint8_t Data=0;
	MyI2C_Start();
	MyI2C_WriteByte(MPU6050_address);
	MyI2C_ReciveAck();
	MyI2C_WriteByte(regaddress);
	MyI2C_ReciveAck();
	MyI2C_Start();
	MyI2C_WriteByte(MPU6050_address+1);
	MyI2C_ReciveAck();
	Data=MyI2C_ReadByte();
	MyI2C_SeedAck(1);
	MyI2C_Stop();
	return Data;
}
/*
      *函数名      :MPU6050_ReadRegData(uint16_t*Ax,uint16_t*Ay,uint16_t*Az,
						uint16_t*Gx,uint16_t*Gy,uint16_t*Gz)
      *函数功能    :连续读取MPU6050寄存器中的数据(数字量)
      *输入        :Ax:x轴的加速度  0-32768
					 Ay:y轴的加速度  0-32768
					 Az:z轴的加速度  0-32768
					 Gx:x轴的角速度  0-32768
					 Gy:y轴的角速度  0-32768
					 Gz:z轴的角速度  0-32768
      *输出        :无
*/
void MPU6050_ReadRegData(uint16_t*Ax,uint16_t*Ay,uint16_t*Az,
						uint16_t*Gx,uint16_t*Gy,uint16_t*Gz)
{
	int16_t Data_H,Data_L=0;
	MyI2C_Start();
	MyI2C_WriteByte(MPU6050_address);
	MyI2C_ReciveAck();
	MyI2C_WriteByte(MPU6050_ACCEL_XOUT_H);
	MyI2C_ReciveAck();
	MyI2C_Start();
	MyI2C_WriteByte(MPU6050_address+1);
	MyI2C_ReciveAck();
	
	Data_H=MyI2C_ReadByte();
	MyI2C_SeedAck(0);
	Data_L=MyI2C_ReadByte();
	MyI2C_SeedAck(0);
	*Ax=Data_H<<8|Data_L;
	
	Data_H=MyI2C_ReadByte();
	MyI2C_SeedAck(0);
	Data_L=MyI2C_ReadByte();
	MyI2C_SeedAck(0);
	*Ay=Data_H<<8|Data_L;
	
	Data_H=MyI2C_ReadByte();
	MyI2C_SeedAck(0);
	Data_L=MyI2C_ReadByte();
	MyI2C_SeedAck(0);
	*Az=Data_H<<8|Data_L;
	
	Data_H=MyI2C_ReadByte();
	MyI2C_SeedAck(0);
	Data_L=MyI2C_ReadByte();
	MyI2C_SeedAck(0);
	Data_H=MyI2C_ReadByte();
	MyI2C_SeedAck(0);
	Data_L=MyI2C_ReadByte();
	MyI2C_SeedAck(0);
	
	Data_H=MyI2C_ReadByte();
	MyI2C_SeedAck(0);
	Data_L=MyI2C_ReadByte();
	MyI2C_SeedAck(0);
	*Gx=Data_H<<8|Data_L;
	
	Data_H=MyI2C_ReadByte();
	MyI2C_SeedAck(0);
	Data_L=MyI2C_ReadByte();
	*Gy=Data_H<<8|Data_L;
	MyI2C_SeedAck(1);
	MyI2C_Stop();
	
	Data_H=MPU6050_ReadReg(0x47);
	Data_L=MPU6050_ReadReg(0x48);
	*Gz=Data_H<<8|Data_L;
}


猜你喜欢

转载自blog.csdn.net/ssssshhbh/article/details/129638683