基于HALL库STM32F4利用SPI驱动MPU6500
从时序图可以看见,SCLK空闲时为高电平,其低电平时数据改变,高电平时读取数据(下降沿移出,上升沿移入),故SPI的模式为模式三:CPOL=1、CPHA=1。其中(a)图为IIC时序,(b)图为SPI时序。这部分可以先略过,先看下边的代码编写再看此寄存器去理解代码。
一、前言
MPU6500为MPU6050的更新产品,其中MPU6050仅支持IIC通信,而MPU6500不仅支持IIC,还支持SPI通信,而SPI相较于IIC能提供更高的数据传输速率。该陀螺仪具有±250、±500、±1000和±2000度/秒的可编程满量程范围和0.01 dps/kHz时的极低速率噪声。加速度计范围为±2g、±4g、± 8 g和± 16 g。有可编程数字滤波器、-40 ° C至85°C范围内1%漂移的精密时钟、嵌入式温度传感器和可编程中断。该器件具有IC和SPI串行接口,VDD工作范围为1.71至3.6V,以及独立的数字IO电源,VDDIO范围为1.71 V至3.6V。与器件所有寄存器的通信使用400 kHz的I C或1 MHz的SPI进行。对于需要更快通信的应用,传感器和中断寄存器可以使用SPI以20 MHz通信。而本文将介绍如何使用这款芯片。
二、MPU6500的介绍
2.1 时序介绍

从时序图可以看见,SCLK空闲时为高电平,其低电平时数据改变,高电平时读取数据(下降沿移出,上升沿移入),故SPI的模式为模式三:CPOL=1、CPHA=1。
2.2 原理图介绍

其中(a)图为IIC时序,(b)图为SPI时序。
三、相关寄存器的介绍
这部分可以先略过,先看下边的代码编写再看此寄存器去理解代码。
3.1 PWR_MGMT_1(电源管理 1:0X6B)
主要是在初始化中用得到,比如初始化代码会先在最高位写入1来恢复默认设置,然后再写入0x00来唤醒MCU。
3.2 PWR_MGMT_2(电源管理 2:0X6C)

其中第[7:6]是设置唤醒频率用的(一般用不上),使用条件为:
(i) Set CYCLE bit to 1 将 CYCLE 位设置为 1
(ii) Set SLEEP bit to 0 将 SLEEP 位设置为 0
(iii) Set TEMP_DIS bit to 1 将 TEMP_DIS 位设置为 1
(iv) Set DIS_XG, DIS_YG, DIS_ZG bits to 1 将 DIS_XG、DIS_YG DIS_ZG 位设置为 1其中步骤 (i) 到(iii)中提到的位可以在PWR_MGMT_1寄存器中找到,在此模式下,设备将关闭除主 I C 接口之外的所有设备,仅以固定间隔唤醒加速度计以进行一次测量。唤醒频率可以通过 LP_WAKE_CTRL 进行配置,如下所示。
在初始化函数中我们一般将此寄存器都设置为0。
3.3 User Control(用户控制:0X6A)
用于设置一些相关参数,如设置为0X11:置于SPI模式以及重置路径。
3.4 Accelerometer Configuration 2 (加速度计配置 2:0X1D)

其原理可以不用管,主要是设置加速度计数据速率和带宽,想了解的可以自己去查阅数据手册。我们初始化中配置为0x03。
3.5 Interrupt Enable(中断使能:0X38)


此寄存器为中断使能引脚,我们一般只使能运动中断,也就是设置为0X40。
3.6 Accelerometer Interrupt Control(加速度计中断控制:0X69)

主要是启用Accel硬件智能,初始化为0xC0。
3.7 Low Power Accelerometer ODR Contro(低功耗加速度计 ODR 控制:0X1E)

主要是设置唤醒频率
3.8 Wake-on Motion Threshold(唤醒运动阈值:0X1F)

3.9 WHOAMI(我是谁:0X75)
我们使用的SPI通信,所以读这个寄存器正确的值应该为0x70。
3.10 FIFO Enable(FIFO使能寄存器:0X23)

3.11 INT Pin / Bypass Enable Configuration(INT 引脚/旁路使能配置:0X37)
3.12 Sample Rate Divider(采样率分频器:0X19)
数据应以或更高的采样率进行采样;SMPLRT_DIV仅用于 1kHz 内部采样。
3.13 Configuration (配置寄存器:0X1A)
用于配置FIFO以及设置陀螺仪滤波频率,初始化中配置为0X03。主要是依据你的滤波频率决定
3.14 Gyroscope Configuration(陀螺仪配置寄存器:0X1B)
3.15 Accelerometer Configuration(加速度计配置:0X1C)

四、读取MPU6500加速度值以及陀螺值
4.1 CubeMx的配置

这里就不介绍下载口以及时钟的配置了,我设置的时钟为84MHz。
至于为什么分频倍率选择128,这里的分频倍率可以选2、4、8、16、32、64、128、256,由于MPU6500的SPI最大速度为1MHz,如果选64分频肯定会超过这个速度,84MHz/64=1.3125MHz,故选用128分频。当然,如果你系统时钟是另一个频率可以按照这个去选最优分频倍率。当然不要忘了使能引脚NSS的初始化,配置为输出模式,然后配置串口,可以参考我的另一篇文章:串口配置,然后生成工程。
4.2 代码的编写

在之前先定义两个全局变量用于SPI的数据交换
uint8_t mpu_tx,mpu_rx;//用于数据的发送交换
4.2.1 写函数
/***** 写入一个字节的数据 *****/
uint8_t mpu_write_byte(uint8_t const reg,uint8_t const data)
{
MPU_CS(0);//开始通信
mpu_tx = reg & 0x7F;//使第一位为0,写模式
HAL_SPI_TransmitReceive(&hspi1,&mpu_tx,&mpu_rx,1,55);//写入命令地址
mpu_tx = data;
HAL_SPI_TransmitReceive(&hspi1,&mpu_tx,&mpu_rx,1,55);//写入数据
MPU_CS(1);//结束通信
return 0;
}
4.2.2 读函数
/***** 读取一个字节的数据 *****/
uint8_t mpu_read_byte(uint8_t const reg)
{
MPU_CS(0);//开始通信
mpu_tx = reg | 0x80;//使第一位为1,读模式
HAL_SPI_TransmitReceive(&hspi1,&mpu_tx,&mpu_rx,1,55);//写入读取地址
HAL_SPI_TransmitReceive(&hspi1,&mpu_tx,&mpu_rx,1,55);//为读取的数据提供存储空间
MPU_CS(1);//结束通信
return mpu_rx;
}
4.3 MPU6500的初始化
4.3.1 MPU6500初始化流程图

4.3.2 MPU6050的初始化
uint8_t MPU6500_Init(void)
{
uint8_t res = 0;
mpu_write_byte(MPU_PWR_MGMT1_REG,0x80);//重置内部寄存器并恢复默认设置
mpu_delay(100);
mpu_write_byte(MPU_PWR_MGMT1_REG,0x00); //解除休眠状态
mpu_delay(100);
mpu_write_byte(MPU_USER_CTRL_REG,0x11);//设置为SPI通信
mpu_delay(10);
res = mpu_read_byte(MPU_DEVICE_ID_REG);//读取ID号
if(res==MPU6500_ID)//ID号正确
{
mpu_write_byte(MPU_PWR_MGMT2_REG,0x00);//打开加速度计以及陀螺仪
mpu_delay(10);
mpu_write_byte(MPU_GYRO_CFG_REG,0x18);//设置陀螺仪自检及测量范围,0x018:不自检,2000deg/s
mpu_delay(10);
mpu_write_byte(MPU_ACCEL_CFG_REG,0x00);//设置陀螺仪加速计自检、测量范围及高通滤波频率,0x00:不自检,2G
mpu_delay(10);
mpu_write_byte(MPU_ACCEL_CFG2_REG,0x03);//设置速率与宽带
mpu_delay(10);
mpu_write_byte(MPU_INT_EN_REG,0x40);//仅使能运动中断
mpu_delay(10);
mpu_write_byte(MPU_MDETECT_CTRL_REG,0xC0);//启用硬件智能
mpu_delay(10);
// mpu_write_byte(MPU_MOTION_DET_REG,0xC0);//设置运动阈值
// mpu_delay(10);
// mpu_write_byte(MPU_ACCEL_ODR_REG,0xC0);//设置唤醒频率
// mpu_delay(10);
mpu_write_byte(MPU_PWR_MGMT1_REG,0x01);//选择最佳时钟源
mpu_delay(10);
mpu_write_byte(MPU_CFG_REG,0x03);
mpu_delay(10);
mpu_write_byte(MPU_FIFO_EN_REG,0x00);//FIFO使能
mpu_delay(10);
mpu_write_byte(MPU_INTBP_CFG_REG,0x82); //配置中断引脚为低电平有效
mpu_delay(10);
mpu_write_byte(MPU_SAMPLE_RATE_REG,0x31);//设置陀螺仪采样率,0x31:20Hz
mpu_delay(10);
mpu_write_byte(MPU_CFG_REG,0x06);//设置陀螺仪滤波频率,0x04:42Hz(相当于20Hz)
mpu_delay(10);
}
else
return 1;
return 0;
}
4.4 加速度与陀螺仪数据的读取
4.4.1 加速度的读取
| Addr (Hex) | Register Name | Serial I/F | Bit |
|---|---|---|---|
| 0X3B | ACCEL_XOUT_H | R | ACCEL_XOUT_H[15:8] |
| 0X3C | ACCEL_XOUT_L | R | ACCEL_XOUT_L[7:0] |
| 0X3D | ACCEL_YOUT_H | R | ACCEL_YOUT_H[15:8] |
| 0X3E | ACCEL_YOUT_L | R | ACCEL_YOUT_L[7:0] |
| 0X3F | ACCEL_ZOUT_H | R | ACCEL_ZOUT_H[15:8] |
| 0X40 | ACCEL_ZOUT_L | R | ACCEL_ZOUT_L[7:0] |
//得到加速度值(原始值)
//gx,gy,gz:陀螺仪x,y,z轴的原始读数(带符号)
void Get_MPU6500_Accelerometer(short *ax,short *ay,short *az)
{
u8 BUF[6];
BUF[0]=mpu_read_byte(MPU_ACCEL_XOUTL_REG);
BUF[1]=mpu_read_byte(MPU_ACCEL_XOUTH_REG);
*ax=((u16)BUF[1]<<8)|BUF[0];
BUF[2]=mpu_read_byte(MPU_ACCEL_YOUTL_REG);
BUF[3]=mpu_read_byte(MPU_ACCEL_YOUTH_REG);
*ay=((u16)BUF[3]<<8)|BUF[2];
BUF[4]=mpu_read_byte(MPU_ACCEL_ZOUTL_REG);
BUF[5]=mpu_read_byte(MPU_ACCEL_ZOUTH_REG);
*az=((u16)BUF[5]<<8)|BUF[4];
}
4.4.2 陀螺仪的读取
/**
* @brief 得到陀螺仪值(原始值)
* @param gx,gy,gz:陀螺仪x,y,z轴的原始读数(带符号)
* @retval 无
*/
void Get_MPU6500_GYRO(short *gx,short *gy,short *gz)
{
u8 BUF[6];
BUF[0]=mpu_read_byte(MPU_GYRO_XOUTL_REG);
BUF[1]=mpu_read_byte(MPU_GYRO_XOUTH_REG);
*gx=((u16)BUF[1]<<8)|BUF[0];
BUF[2]=mpu_read_byte(MPU_GYRO_YOUTL_REG);
BUF[3]=mpu_read_byte(MPU_GYRO_YOUTH_REG);
*gy=((u16)BUF[3]<<8)|BUF[2];
BUF[4]=mpu_read_byte(MPU_GYRO_ZOUTL_REG);
BUF[5]=mpu_read_byte(MPU_GYRO_ZOUTH_REG);
*gz=((u16)BUF[5]<<8)|BUF[4];
}
4.4.3 温度的读取
要将温度传感器的输出转换为摄氏度,请使用以下公式:

//得到温度值
//返回值:温度值(扩大了100倍)
short MPU_Get_Temperature(void)
{
u8 BUF[2]; //用于存放温度
short raw;
float temp;
BUF[0]=mpu_read_byte(TEMP_OUT_L);
BUF[1]=mpu_read_byte(TEMP_OUT_H);
raw=((u16)BUF[1]<<8)|BUF[0];//将8位数据整合为16位
temp = 21+ ((double)(raw - 21))/333.87;// 读取计算出温度
return temp*100;//为了好处理数据,这里扩大100倍
}
4.5 读取MPU6500数据
我们将MPU6500平放与桌面上,此时在Z轴上会收到1g的重力加速度。例子中设置量程范围为2g,也就是65536/4=16384,此时在z轴的加速度读数应该在16384附近,由于我没完全平放模块,所以会大了一点点,如下图:

那么我设置量程为16g呢?读数65536/32=2048左右,试试:


那么关于读取MPU的原始数据就先到这里就结束了,往后给大家带来MPU6500的姿态解算。文章源代码:链接:https://pan.baidu.com/s/1v99GScyPQGAJEG8S3IaeTw?pwd=x8hc 提取码: x8hc
bsp_mpu6500_reg.h
#ifndef __BSP_MPU6500_REG_H
#define __BSP_MPU6500_REG_H
//#define MPU_ACCEL_OFFS_REG 0X06 //accel_offs寄存器,可读取版本号,寄存器手册未提到
//#define MPU_PROD_ID_REG 0X0C //prod id寄存器,在寄存器手册未提到
#define MPU_SELF_TESTX_REG 0X0D //自检寄存器X
#define MPU_SELF_TESTY_REG 0X0E //自检寄存器Y
#define MPU_SELF_TESTZ_REG 0X0F //自检寄存器Z
#define MPU_SELF_TESTA_REG 0X10 //自检寄存器A
#define MPU_SAMPLE_RATE_REG 0X19 //采样频率分频器
#define MPU_CFG_REG 0X1A //配置寄存器
#define MPU_GYRO_CFG_REG 0X1B //陀螺仪配置寄存器
#define MPU_ACCEL_CFG_REG 0X1C //加速度计配置寄存器
#define MPU_ACCEL_CFG2_REG 0X1D
#define MPU_ACCEL_ODR_REG 0X1E //设置唤醒频率
#define MPU_MOTION_DET_REG 0X1F //唤醒运动阈值
#define MPU_FIFO_EN_REG 0X23 //FIFO使能寄存器
#define MPU_I2CMST_CTRL_REG 0X24 //IIC主机控制寄存器
#define MPU_I2CSLV0_ADDR_REG 0X25 //IIC从机0器件地址寄存器
#define MPU_I2CSLV0_REG 0X26 //IIC从机0数据地址寄存器
#define MPU_I2CSLV0_CTRL_REG 0X27 //IIC从机0控制寄存器
#define MPU_I2CSLV1_ADDR_REG 0X28 //IIC从机1器件地址寄存器
#define MPU_I2CSLV1_REG 0X29 //IIC从机1数据地址寄存器
#define MPU_I2CSLV1_CTRL_REG 0X2A //IIC从机1控制寄存器
#define MPU_I2CSLV2_ADDR_REG 0X2B //IIC从机2器件地址寄存器
#define MPU_I2CSLV2_REG 0X2C //IIC从机2数据地址寄存器
#define MPU_I2CSLV2_CTRL_REG 0X2D //IIC从机2控制寄存器
#define MPU_I2CSLV3_ADDR_REG 0X2E //IIC从机3器件地址寄存器
#define MPU_I2CSLV3_REG 0X2F //IIC从机3数据地址寄存器
#define MPU_I2CSLV3_CTRL_REG 0X30 //IIC从机3控制寄存器
#define MPU_I2CSLV4_ADDR_REG 0X31 //IIC从机4器件地址寄存器
#define MPU_I2CSLV4_REG 0X32 //IIC从机4数据地址寄存器
#define MPU_I2CSLV4_DO_REG 0X33 //IIC从机4写数据寄存器
#define MPU_I2CSLV4_CTRL_REG 0X34 //IIC从机4控制寄存器
#define MPU_I2CSLV4_DI_REG 0X35 //IIC从机4读数据寄存器
#define MPU_I2CMST_STA_REG 0X36 //IIC主机状态寄存器
#define MPU_INTBP_CFG_REG 0X37 //中断/旁路设置寄存器
#define MPU_INT_EN_REG 0X38 //中断使能寄存器
#define MPU_INT_STA_REG 0X3A //中断状态寄存器
#define MPU_ACCEL_XOUTH_REG 0X3B //加速度值,X轴高8位寄存器
#define MPU_ACCEL_XOUTL_REG 0X3C //加速度值,X轴低8位寄存器
#define MPU_ACCEL_YOUTH_REG 0X3D //加速度值,Y轴高8位寄存器
#define MPU_ACCEL_YOUTL_REG 0X3E //加速度值,Y轴低8位寄存器
#define MPU_ACCEL_ZOUTH_REG 0X3F //加速度值,Z轴高8位寄存器
#define MPU_ACCEL_ZOUTL_REG 0X40 //加速度值,Z轴低8位寄存器
#define MPU_TEMP_OUTH_REG 0X41 //温度值高八位寄存器
#define MPU_TEMP_OUTL_REG 0X42 //温度值低8位寄存器
#define MPU_GYRO_XOUTH_REG 0X43 //陀螺仪值,X轴高8位寄存器
#define MPU_GYRO_XOUTL_REG 0X44 //陀螺仪值,X轴低8位寄存器
#define MPU_GYRO_YOUTH_REG 0X45 //陀螺仪值,Y轴高8位寄存器
#define MPU_GYRO_YOUTL_REG 0X46 //陀螺仪值,Y轴低8位寄存器
#define MPU_GYRO_ZOUTH_REG 0X47 //陀螺仪值,Z轴高8位寄存器
#define MPU_GYRO_ZOUTL_REG 0X48 //陀螺仪值,Z轴低8位寄存器
#define MPU_I2CSLV0_DO_REG 0X63 //IIC从机0数据寄存器
#define MPU_I2CSLV1_DO_REG 0X64 //IIC从机1数据寄存器
#define MPU_I2CSLV2_DO_REG 0X65 //IIC从机2数据寄存器
#define MPU_I2CSLV3_DO_REG 0X66 //IIC从机3数据寄存器
#define MPU_I2CMST_DELAY_REG 0X67 //IIC主机延时管理寄存器
#define MPU_SIGPATH_RST_REG 0X68 //信号通道复位寄存器
#define MPU_MDETECT_CTRL_REG 0X69 //运动检测控制寄存器
#define MPU_USER_CTRL_REG 0X6A //用户控制寄存器
#define MPU_PWR_MGMT1_REG 0X6B //电源管理寄存器1
#define MPU_PWR_MGMT2_REG 0X6C //电源管理寄存器2
#define MPU_FIFO_CNTH_REG 0X72 //FIFO计数寄存器高八位
#define MPU_FIFO_CNTL_REG 0X73 //FIFO计数寄存器低八位
#define MPU_FIFO_RW_REG 0X74 //FIFO读写寄存器
#define MPU_DEVICE_ID_REG 0X75 //器件ID寄存器
#define MPU6500_ID 0x70
#endif
更多推荐






所有评论(0)