3,848
社区成员




我在做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;
}
}
多读几个btye,例如寄存器的值的长度有32位,你只读8位(一个字节Byte),默认是读到最高的8位,当然大概率是0