一、程序流程图
原始数据的数据读取十分简单,就是先对传感器进行一系列的初始化,然后再读取特定寄存器的值就行了。所谓的初始化,就是对传感器的配置寄存器写入特定值。单片机与传感器之间采用SPI通信,流程图如下:

根据流程图,我们只需要写四个函数就能实现读取功能:
1、SPI初始化函数
2、写MPU6500寄存器函数
3、读MPU6500寄存器函数
4、初始化MPU6500函数
二、代码详解
1、SPI初始化函数
SPI初始化函数就不多讲了,原子野火均有讲解,为了文章完整性,代码粘贴如下:
void Init_SPI5(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI5, ENABLE);
GPIO_PinAFConfig(GPIOF,GPIO_PinSource7,GPIO_AF_SPI5);
GPIO_PinAFConfig(GPIOF,GPIO_PinSource8,GPIO_AF_SPI5);
GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_SPI5);
/*SCK、MISO、MOSI*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOF, &GPIO_InitStructure);
GPIO_SetBits(GPIOF,GPIO_Pin_7 | GPIO_Pin_8 |GPIO_Pin_9);
/*NSS*/
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;
GPIO_Init(GPIOF, &GPIO_InitStructure);
GPIO_SetBits(GPIOF,GPIO_Pin_6);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //10
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //01
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; // !!!MSB先行
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI5, &SPI_InitStructure);
SPI_Cmd(SPI5, ENABLE);
}
2、MPU6500读写寄存器函数
SPI是双向全双工通信协议,发送和接收是同时进行的。就是说,当单片机用SPI向传感器发送一个字节,同时会收到来自传感器的一个字节数据。所以通常把读写都写在一起,在对传感器寄存器写值时可以丢弃返回的数据,而在读取寄存器值时发送一个空字节,然后接收数据就好了。
读写函数:
两个while 用于确保数据稳定发送(接收)
uint8_t SPI5_Read_Write_Byte(uint8_t TxData)
{
uint8_t retry = 0;
while (SPI_I2S_GetFlagStatus(SPI5, SPI_I2S_FLAG_TXE) == RESET)
{
retry++;
if(retry > 250) return 0;
}
SPI_I2S_SendData(SPI5, TxData); //发送数据到DR寄存器
retry = 0;
while (SPI_I2S_GetFlagStatus(SPI5, SPI_I2S_FLAG_RXNE) == RESET)
{
retry++;
if(retry > 250) return 0;
}
return SPI_I2S_ReceiveData(SPI5); //从DR寄存器接收数据
}
写一个字节:
uint8_t MPU_Write_Byte(uint8_t reg,uint8_t data)
{
uint8_t status;
MPU_NSS_LOW;
delay_200ns(1);
status = SPI5_Read_Write_Byte(reg);
SPI5_Read_Write_Byte(data);
MPU_NSS_HIGH;
delay_200ns(1);
return status;
}
读一个字节:
/*mpu6500 SPI读取寄存器时候,需要在寄存器地址最高 置1*/
uint8_t MPU_Read_Byte(uint8_t reg)
{
uint8_t reg_val; //寄存器值
MPU_NSS_LOW; //片选拉低
delay_200ns(1);
SPI5_Read_Write_Byte(reg|0x80); //写入寄存器地址,地址最高位置1
reg_val=SPI5_Read_Write_Byte(0xff); //主机发送一个空字节获取寄存器值
MPU_NSS_HIGH; //片选拉高
delay_200ns(1);
return(reg_val);
}
这里读者也许会对reg|0x80有疑问,查询MPU6500产品说明书英文版第34页可知:

所以在SPI初始化时一定要配置为MSB先行,这是要求!
3、MPU6500初始化
初始化就是对寄存器写值!
uint8_t Mpu_Init(void)
{
delay_ms(100);
id = MPU_Read_Byte(MPU6500_WHO_AM_I);
uint8_t i = 0;
uint8_t MPU6500_Init_Data[10][2] = {{ MPU6500_PWR_MGMT_1, 0x80 }, /* Reset Device */
{ MPU6500_PWR_MGMT_1, 0x03 }, /* Clock Source - Gyro-Z */
{ MPU6500_PWR_MGMT_2, 0x00 }, /* Enable Acc & Gyro */
{ MPU6500_CONFIG, 0x04 }, /* LPF 41Hz */
{ MPU6500_GYRO_CONFIG, 0x18 }, /* +-2000dps */
{ MPU6500_ACCEL_CONFIG, 0x10 }, /* +-8G */
{ MPU6500_ACCEL_CONFIG_2, 0x02 }, /* enable LowPassFilter Set Acc LPF */
{ MPU6500_USER_CTRL, 0x20 },}; /* Enable AUX */
for (i = 0; i < 10; i++)
{
MPU_Write_Byte(MPU6500_Init_Data[i][0], MPU6500_Init_Data[i][1]);
delay_ms(1);
}
Ist8310_Init(); //这是磁力计的初始化,可以忽略,有空再改天讲
return 0;
}
4、MPU6500数据获取
获取数据就是读取寄存器值!
当然这里的代码还有优化空间,就交给优秀的读者们吧!
void Get_MPU6500_Data(void)
{
//加速度数据
mpu_data.ax = Get_16Bit_Data(MPU6500_ACCEL_XOUT_H,MPU6500_ACCEL_XOUT_L);
mpu_data.ay = Get_16Bit_Data(MPU6500_ACCEL_YOUT_H,MPU6500_ACCEL_YOUT_L);
mpu_data.az = Get_16Bit_Data(MPU6500_ACCEL_ZOUT_H,MPU6500_ACCEL_ZOUT_L);
/* 陀螺仪温度数据 2000dps -> °/s */
mpu_data.gx = Get_16Bit_Data(MPU6500_GYRO_XOUT_H,MPU6500_GYRO_XOUT_L) / 16.384f;
mpu_data.gy = Get_16Bit_Data(MPU6500_GYRO_YOUT_H,MPU6500_GYRO_YOUT_L) / 16.384f;
mpu_data.gz = Get_16Bit_Data(MPU6500_GYRO_YOUT_H,MPU6500_GYRO_YOUT_L) / 16.384f;
mpu_data.temp = Get_16Bit_Data(MPU6500_TEMP_OUT_H,MPU6500_TEMP_OUT_L)/333.87f +21;
/*磁力计数据 转换成 uT*/
mpu_data.mx = 0.3f*Get_16Bit_Data(MPU6500_EXT_SENS_DATA_00,MPU6500_EXT_SENS_DATA_01);
mpu_data.my = 0.3f*Get_16Bit_Data(MPU6500_EXT_SENS_DATA_02,MPU6500_EXT_SENS_DATA_03);
mpu_data.mz = 0.3f*Get_16Bit_Data(MPU6500_EXT_SENS_DATA_04,MPU6500_EXT_SENS_DATA_05);
}
//将两个字节数据处理成字
float Get_16Bit_Data(uint8_t addr_h, uint8_t addr_l)
{
static uint8_t buf[2];
static short data;
buf[0] = MPU_Read_Byte(addr_l);
buf[1] = MPU_Read_Byte(addr_h);
data = (buf[1]<<8)|buf[0];
return data;
}
运行程序,在仿真界面可查看到数据已成功读取
