求助,STM32F103 读取MPU6050数据寄存器全部为零

愤怒的鳄鱼 2023-03-25 12:41:05

我在做STM32模拟IIC读取MPU6050原始数据时,遇到一个问题,就是读取ID号以及控制寄存器时都能正确读取,但是在读取角度加速度等数据寄存器时,读出的数据始终为零,通过示波器查看时序,传出的数据确实均为0 ,换了MPU6050模块,也换了模块上面的芯片都无法解决这个问题,劳烦各位大神帮忙看一下是配置的问题还是啥问题哟,不胜感激!

#include "main.h"

SensorValue SensorValuenow;
uint8_t MPU_Onlinebit;

void MPU6050_Init(void);
uint8_t MPU6050ReadID(void);
uint8_t MPU6050_ReadByte(u8 adr);

void MPU6050intit(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitStruct.GPIO_Pin = MPU_SCK;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;//设置为推挽输出
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(MPU_port, &GPIO_InitStruct);
}

//MPU数据线模式设置,双向IO设置
void MPU_SDAmode(u8 mode)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	if(mode)
	{
		GPIO_InitStruct.GPIO_Pin = MPU_SDA;
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
		GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(MPU_port, &GPIO_InitStruct);
	}
	else
	{
		GPIO_InitStruct.GPIO_Pin = MPU_SDA;
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
		GPIO_Init(MPU_port, &GPIO_InitStruct);
	}
}

void MPU_Start(void)
{
	MPU_SDAmode(1);//SDA数据线为输出模式
	MPU_SDA_UP;//同时拉高时钟和数据线
	MPU_SCK_UP;
	delay_us(MPU_Delay);
	MPU_SDA_DN;//拉低数据线
	delay_us(MPU_Delay);
	MPU_SCK_DN;//拉低时钟线
}

void MPU_Stop(void)
{
	MPU_SDAmode(1);//SDA数据线为输出模式
	MPU_SDA_DN;//同时拉低时钟和数据线
	MPU_SCK_DN;
	delay_us(MPU_Delay);
	MPU_SDA_UP;//同时拉高时钟和数据线,iic结束信号
	MPU_SCK_UP;
	delay_us(MPU_Delay);
}

uint8_t MPU_waitAck(void)
{
	uint8_t chcktime;
	MPU_SDA_UP;//同时拉高时钟和数据线
	MPU_SCK_UP;
	MPU_SDAmode(0);//SDA数据线为输入模式
	delay_us(MPU_Delay);

	while(MPU_SDAIputStu)//获取数据线电平状态是否被拉低
	{
		chcktime ++;
		if(chcktime > 250)
		{
			MPU_Stop();
			return 1;
		}
	}
	MPU_SCK_DN;
	return 0;
}

void MPU_Ack(void)
{
	MPU_SCK_DN;
	MPU_SDAmode(1);//输出模式
	MPU_SDA_DN;//同时拉低时钟和数据线	
	delay_us(MPU_Delay);
	MPU_SCK_UP;//产生一个电平跳变
	delay_us(MPU_Delay);
	MPU_SCK_DN;
}

void MPU_NAck(void)
{
	MPU_SCK_DN;
	MPU_SDAmode(1);//输出模式
	MPU_SDA_UP;	
	delay_us(MPU_Delay);
	MPU_SCK_UP;//产生一个电平跳变
	delay_us(MPU_Delay);
	MPU_SCK_DN;
}

void MPU_SendByte(u8 DAT)
{                        
  uint8_t t;   
	MPU_SDAmode(1);//输出模式 	    
	MPU_SCK_DN;//拉低时钟开始数据传输
	delay_us(MPU_Delay);
	for(t=0;t<8;t++)
	{
		if(DAT & 0x80) MPU_SDA_UP;
		else					 MPU_SDA_DN;		
		DAT <<= 1; 	  
		delay_us(MPU_Delay);
		MPU_SCK_UP;//产生一个电平跳变
		delay_us(MPU_Delay);
		MPU_SCK_DN;
//		delay_us(MPU_Delay);
	}
}

uint8_t MPU_ReadByte(uint8_t ack)
{                        
  uint8_t t,dat;   
	MPU_SDAmode(0);//输入模式 	    
	
	for(t=0;t<8;t++)
	{
		MPU_SCK_DN;//拉低时钟开始数据传输
		delay_us(MPU_Delay);
		MPU_SCK_UP;
		dat <<= 1;
		if(MPU_SDAIputStu) dat ++;
		delay_us(MPU_Delay);
	}
	if(!ack)  MPU_NAck();//无应答信号
	else			MPU_Ack();//应答信号
	
	return dat;
} 

//MPU6050写寄存器指令
u8 MPU6050_WriteReg(u8 adr,u8 dat)
{
	MPU_Start();
	MPU_SendByte((MPU6050_ADDRESS<<1) + 0);//写MPU器件地址
	if(MPU_waitAck())
	{
		MPU_Stop();
		return 1;
	}
	MPU_SendByte(adr);//写需要操作的寄存器地址
	MPU_waitAck();
	MPU_SendByte(dat);//写入数据
	if(MPU_waitAck())
	{
		MPU_Stop();
		return 1;
	}
	MPU_Stop();
	delay_ms(5);
	return 0;
}

void MPU6050_Init(void)
{
//	u8 res;
	MPU6050intit();//初始化IIC总线
	MPU6050_WriteReg(MPU6050_RA_PWR_MGMT_1,0x80);
	delay_ms(50);
	MPU6050_WriteReg(MPU6050_RA_PWR_MGMT_1,0x80);
	delay_ms(50);
	MPU6050_WriteReg(MPU6050_RA_PWR_MGMT_1,0x80);
	delay_ms(50);
	MPU6050_WriteReg(MPU6050_RA_PWR_MGMT_1,0x00);
	delay_ms(50);
	MPU6050_WriteReg(MPU6050_RA_PWR_MGMT_1,0x00);
	delay_ms(50);
	MPU6050_WriteReg(MPU6050_RA_PWR_MGMT_1,0x00);
	MPU6050_WriteReg(MPU6050_RA_SMPLRT_DIV,9);	//19采样率,采样频率 = 陀螺仪输出频率 / (1+SMPLRT_DIV)
	MPU6050_WriteReg(MPU6050_RA_CONFIG , 4);//配置寄存器,设置为50Hz
	MPU6050_WriteReg(MPU6050_RA_ACCEL_CONFIG , 0x00);//0, ±2g; 1,±4g; 2,±8g; 3,±16g,一般设置为0,±2g ,灵敏度为65536/4=16384 LSB/g
	MPU6050_WriteReg(MPU6050_RA_GYRO_CONFIG, 0x18);//0,±250° /S; 1,±500° /S; 2,±1000° /S; 3,±2000° /S;\
																									一般设置为3,±2000dps,因为陀螺仪的ADC为16位分辨率,所以得到灵敏度为65536/4000 = 16.4LSB(°/S)
	MPU6050_WriteReg(MPU_INT_EN_REG,0X00);	//关闭所有中断
	MPU6050_WriteReg(MPU_USER_CTRL_REG,0X00);	//I2C主模式关闭
	MPU6050_WriteReg(MPU_FIFO_EN_REG,0X00);	//关闭FIFO
	MPU6050_WriteReg(MPU_INTBP_CFG_REG,0X00);	//INT引脚低电平有效
	
	if(MPU6050ReadID()) 
	{
		MPU_Onlinebit = 1;
		MPU6050_WriteReg(MPU6050_RA_PWR_MGMT_1,0x01);//配置电源,时钟以X轴频率为准
		MPU6050_WriteReg(MPU6050_RA_PWR_MGMT_2,0x00);//全部输出运行
		MPU6050_WriteReg(MPU6050_RA_SMPLRT_DIV,9);	//采样率,采样频率 = 陀螺仪输出频率 / (1+SMPLRT_DIV)
		MPU6050_WriteReg(MPU6050_RA_CONFIG , 4);//配置寄存器,设置为50Hz
	}
	else MPU_Onlinebit = 0;
}

uint8_t ID;
//MPU6050单字节数据
uint8_t MPU6050_ReadByte(u8 adr)
{
	unsigned char dat;
	
	MPU_Start();
	MPU_SendByte((MPU6050_ADDRESS<<1) | 0);//器件地址+写命令
	MPU_waitAck();
	MPU_SendByte(adr);//读取的寄存器地址
	MPU_waitAck();
	
	MPU_Start();
	MPU_SendByte((MPU6050_ADDRESS<<1) | 1);//器件地址+读命令 
	MPU_waitAck();

	dat = MPU_ReadByte(0);
	MPU_Stop();
	return dat;
}

//MPU6050读取寄存器的值
void MPU6050_ReadData(u8 adr,unsigned char*Read,u8 num)
{
	unsigned char i;
	
	MPU_Start();
	MPU_SendByte((MPU6050_ADDRESS<<1) + 0);//器件地址+写命令
	MPU_waitAck();
	MPU_SendByte(adr);//读取的寄存器地址
	MPU_waitAck();
	
	MPU_Start();
	MPU_SendByte((MPU6050_ADDRESS<<1) + 1);//器件地址+读命令
	MPU_waitAck();
	
	for(i=0;i<(num-1);i++)//连续读取多个直接数据
	{
		*Read = MPU_ReadByte(1);//带应答读取
		Read++;
	}
	*Read = MPU_ReadByte(0);
	MPU_Stop();
}

//读取陀螺仪寄存器值
void MPU6050ReadGyro(short *GYRODat)
{
    u8 buf[6];
    MPU6050_ReadData(MPU6050_GYRO_ADR,buf,6);
    GYRODat[0] = (buf[0] << 8) | buf[1];
    GYRODat[1] = (buf[2] << 8) | buf[3];
    GYRODat[2] = (buf[4] << 8) | buf[5];
}

//读取加速度寄存器值
void MPU6050ReadAcc(short *ACCDat)
{
    u8 buf[6];
    MPU6050_ReadData(MPU6050_ACC_ADR, buf, 6);
    ACCDat[0] = (buf[0] << 8) | buf[1];
    ACCDat[1] = (buf[2] << 8) | buf[3];
    ACCDat[2] = (buf[4] << 8) | buf[5];
}

void MPU6050ReadTemp(short *tempData)
{
	u8 buf[2];
	MPU6050_ReadData(MPU6050_RA_TEMP_OUT_H,buf,2);     //读取温度值
	*tempData = (buf[0] << 8) | buf[1];
}

//读取MPU6050的温度数据,转化成摄氏度
void MPU6050_ReturnTemp(float *Temperature)
{
	short temp3;
	u8 buf[2];
	
	MPU6050_ReadData(MPU6050_RA_TEMP_OUT_H,buf,2);     //读取温度值
  temp3= (buf[0] << 8) | buf[1];	
	*Temperature=((double) temp3/340.0)+36.53;
}

//读器件地址是否为0x68
uint8_t MPU6050ReadID(void)
{
	unsigned char Re = 0;
	MPU6050_WriteReg(0X6B,0X01);	//设置CLKSEL,PLL X轴为参考
	MPU6050_WriteReg(0X6C,0X00);	//加速度与陀螺仪都工作
	MPU6050_ReadData(MPU6050_WHO_AM_I,&Re,1); 
//	MPU6050_ReadByte(MPU6050_WHO_AM_I,&Re);
	if (Re != 0x68) return 0;
	else 	return 1;
}

//读取MPU6050数据
short Accel[3];
short Gyro[3];
short temperature;
u8 regadr=0x43;
void ReadMPU6050Data(void)
{	
//	Accel[0] = 
	if(MPU6050ReadID())
	{
		temperature = MPU6050_ReadByte(regadr);
		MPU6050ReadAcc(Accel);
//		MPU6050ReadGyro(Gyro);
//		MPU6050ReadTemp(&temperature);
	}
	else
	{
		Accel[1] = 0x68;Gyro[1] = 0x68;
	}
}

 

...全文
1178 1 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
m0_70184683 2023-11-22
  • 打赏
  • 举报
回复

多读几个btye,例如寄存器的值的长度有32位,你只读8位(一个字节Byte),默认是读到最高的8位,当然大概率是0

3,848

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 无线
社区管理员
  • 无线
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧