目录
概述
1 STM32Cube控制配置I2C
1.1 I2C参数配置
1.2 使用STM32Cube产生工程
2 HAL库函数介绍
2.1 初始化函数
2.2 写数据函数
2.3 读数据函数
3 认识MP6050
3.1 MP6050功能介绍
3.2 加速计测量寄存器
编辑3.3 温度计量寄存器
3.4 陀螺仪测量寄存器
4 MP6050驱动程序实现
4.1 驱动函数实现
4.2 完整驱动代码
5 测试
6 逻辑分析仪捕捉波形
概述
本文主要介绍STM32F4的内部I2C接口的使用方法,包括使用STM32Cube配置i2c接口函数,还介绍了STM32 HAL库中的接口函数,为了验证接口函数的是否能够正常工作,还使用mp6050
作为device,以I2C接口作为通信接口,以实现该芯片数据的读写操作。
1 STM32Cube控制配置I2C
STM32CubeMX 版本: 6.11
HAL库版本: STM32Cube_FW_F4_V1.27.1
1.1 I2C参数配置
STM32F407 的标准I2C接口最大支持100K工作频率,笔者选择最大工作频100k,以配置I2C的参数。
I2C使用的GPIO接口如下:
使用MCU类型和HAL库的版本
1.2 使用STM32Cube产生工程
在配置完成项目后,点击GENERATE生成项目,打开项目后项目目录如下,和I2C相关的代码如下:
代码第40行:选择I2C2作为硬件接口
代码第41行:I2C通信速率为100K
代码第44行:定义地址位7bit
2 HAL库函数介绍
STM32 HAL库函数数量很多,本文仅介绍笔者使用的一些函数接口。其他函数在使用的时候在具体研究,而不许把每个函数搞清楚才去应用。
2.1 初始化函数
函数原型:
HAL_StatusTypeDef HAL_I2C_Init(I2C_HandleTypeDef *hi2c);
参数介绍
hi2c: 指向I2C_HandleTypeDef结构体的指针,该结构体包含指定I2C的配置信息。
一个使用案例: 如果已经初始化完成hi2c结构,初始化时,直接调用该结构体即可。
2.2 写数据函数
函数原型:
HAL_StatusTypeDef HAL_I2C_Mem_Write( I2C_HandleTypeDef *hi2c,
uint16_t DevAddress,
uint16_t MemAddress,
uint16_t MemAddSize,
uint8_t *pData,
uint16_t Size, uint32_t Timeout)
参数介绍:
hi2c: 指向I2C_HandleTypeDef结构体的指针,该结构体包含指定I2C的配置信息。
DevAddress: 目标设备地址:设备的7位地址值在调用接口之前,必须将数据表向左移动
MemAddress:内存地址
MemAddSize:内存地址大小
pData: 写数据指针
Size: 写数据大小
Timeout: 写数据超时时间
2.3 读数据函数
函数原型:
HAL_StatusTypeDef HAL_I2C_Mem_Read( I2C_HandleTypeDef *hi2c,
uint16_t DevAddress,
uint16_t MemAddress,
uint16_t MemAddSize,
uint8_t *pData,
uint16_t Size,
uint32_t Timeout)
参数介绍:
hi2c: 指向I2C_HandleTypeDef结构体的指针,该结构体包含指定I2C的配置信息。
DevAddress: 目标设备地址:设备的7位地址值在调用接口之前,必须将数据表向左移动
MemAddress:内存地址
MemAddSize:内存地址大小
pData: 读数据指针
Size: 读数据大小
Timeout: 读数据超时时间
3 认识MP6050
3.1 MP6050功能介绍
™ MPU-6000™ 和MPU-6050™, 统称为MPU-60X0™ 或MPU™.MPU设备提供了世界上第一个集成的6轴运动处理器解决方案,消除了与离散解决方案相关的封装级陀螺仪和加速度计交叉轴未对准。这个该设备将同一硅芯片上的3轴陀螺仪和3轴加速度计与车载数字运动处理器™ (DMP)™) 温度单元:能够处理复杂的9轴传感器融合算法使用经过现场验证的专有MotionFusion™ 发动机MPU-6000和MPU-6050的集成9轴MotionFusion算法可访问外部磁力计或通过辅助主I2C总线的其他传感器,允许设备收集全套传感器数据而不需要系统处理器的干预。这些设备采用相同的4x4x0.9 mm QFN与当前MPU-3000一样的占地面积和引脚™ 集成3轴陀螺仪家族,提供了一个简单的升级路径并便于在已经空间受限的电路板上放置。
对于快速和慢速运动的精确跟踪,MPU-60X0具有用户可编程功能陀螺仪满刻度范围为±250、±500、±1000和±2000°/秒(dps)。这些零件还具有用户可编程的加速度计满量程范围,分别为±2g、±4g、±8g和±16g。MPU-6000系列由两部分组成,即MPU-6000和MPU-6050。这些部件与我会处理好的。
MPU-6050支持高达400kHz的I2C通信,并具有定义其接口电压电平的VLOGIC引脚;MPU-6000还支持高达20MHz的SPI到I2C,并且具有单个电源引脚VDD,VDD既是设备的逻辑参考电源,也是模拟电源供应零件。有关MPU-60X0设备的更多详细信息,请参阅“MPU-6000和MPU-6050产品规范”。
3.2 加速计测量寄存器
寄存器59至64–加速计测量:ACCEL_XOUT_H、ACCEL_QUEUT_L、ACCE_YOUT_H,ACCEL_YOUT_L,ACCE_ZOUT_H和ACCEL_ZOUT_L
这些寄存器存储最新的加速度计测量值。加速度计测量值以中定义的采样率写入这些寄存器寄存器25。加速度计测量寄存器与温度测量寄存器一起,陀螺仪测量寄存器和外部传感器数据寄存器由两组寄存器:内部寄存器集和面向用户的读取寄存器集。加速度计传感器内部寄存器组中的数据总是在采样时更新速度同时,面向用户的读取寄存器集复制内部寄存器集的数据值每当串行接口空闲时。这保证了传感器寄存器的突发读取来自相同采样时刻的测量。请注意,如果不使用突发读取,则用户负责确保一组单字节读取对应于单个采样瞬间检查数据就绪中断。每个16位加速度计测量都具有在ACCEL_FS(寄存器28)中定义的满刻度。对于每个满刻度设置,加速度计ACCEL_xOUT中每个LSB的灵敏度如表所示在下面:
3.3 温度计量寄存器
寄存器65 and 66: TEMP_OUT_H and TEMP_OUT_L
这些寄存器存储最新的温度传感器测量值。温度测量值以寄存器中定义的采样率写入这些寄存器
25.这些温度测量寄存器与加速度计测量寄存器一起,陀螺仪测量寄存器和外部传感器数据寄存器由两组寄存器:内部寄存器集和面向用户的读取寄存器集。温度传感器内部寄存器组中的数据始终以采样率进行更新。同时,面向用户的读取寄存器集复制内部寄存器集的数据值每当串行接口空闲时。这保证了传感器寄存器的突发读取来自相同采样时刻的测量。请注意,如果不使用突发读取,则用户负责确保一组单字节读取对应于单个采样瞬间检查数据就绪中断。温度传感器的比例因子和偏移可在电气规格表中找到。
3.4 陀螺仪测量寄存器
寄存器67至72——陀螺仪测量:GYRO_XOUT_H、GYRO_XOUT_L、GYRO_YOUT_H,GYRO_YOUT_L,GYRO_ZOUT_H和GYRO_ ZOUT_L
这些寄存器存储最新的陀螺仪测量值。陀螺仪测量值以寄存器中定义的采样率写入这些寄存器
25.这些陀螺仪测量寄存器与加速度计测量寄存器一起,温度测量寄存器和外部传感器数据寄存器由两组寄存器:内部寄存器集和面向用户的读取寄存器集。陀螺仪传感器内部寄存器组中的数据始终以采样率进行更新。同时,面向用户的读取寄存器集复制内部寄存器集的数据值每当串行接口空闲时。这保证了传感器寄存器的突发读取来自相同采样时刻的测量。请注意,如果不使用突发读取,则用户负责确保一组单字节读取对应于单个采样瞬间检查数据就绪中断。每个16位陀螺仪测量都具有FS_SEL(寄存器27)中定义的满刻度。对于每满刻度设置,GYRO_xOUT中每个LSB的陀螺仪灵敏度如下表所示:
4 MP6050驱动程序实现
4.1 驱动函数实现
1)写寄存器函数
代码第25行: 调用HAL_I2C_Mem_Write实现写寄存器功能
2)读寄存器函数
代码第37行: 调用HAL_I2C_Mem_Read实现读寄存器功能
4.2 完整驱动代码
1)创建mp6050.c文件,编写如下代码
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : mpu6050.c
* Description : I2C drive based on STM32F4
* STM32 HAL library ver: STM32Cube_FW_F4_V1.27.1
*
******************************************************************************
* @attention
*
* Copyright (c) 2024~2029 mingfei.tang
* All rights reserved.
*
*************************************************************************
*/
/* USER CODE END Header */
#include "mpu6050.h"
MPU6050_T g_tMPU6050;
static uint8_t mpu6050_WeReg( uint16_t regAdd, uint8_t *pData, uint16_t Size )
{
HAL_StatusTypeDef status;
status = HAL_I2C_Mem_Write( &hi2c2, MPU6050_SLAVE_ADDRESS, regAdd,
I2C_MEMADD_SIZE_8BIT, pData, Size, 1000);
if( status == HAL_OK)
return MPU6050_OK;
else
return MPU6050_ERROR;
}
static uint8_t mpu6050_RdReg( uint16_t regAdd, uint8_t *pData, uint16_t Size )
{
HAL_StatusTypeDef status;
status = HAL_I2C_Mem_Read( &hi2c2, MPU6050_SLAVE_ADDRESS, regAdd,
I2C_MEMADD_SIZE_8BIT, pData, Size, 1000);
if( status == HAL_OK)
return MPU6050_OK;
else
return MPU6050_ERROR;
}
void mpu6050_Init(void)
{
uint8_t cmd;
cmd = 0x00;
mpu6050_WeReg(PWR_MGMT_1, &cmd,1); //解除休眠状态
cmd = 0x07;
mpu6050_WeReg(SMPLRT_DIV, &cmd,1);
cmd = 0x06;
mpu6050_WeReg(CONFIG, &cmd,1);
cmd = 0xE8;
mpu6050_WeReg(GYRO_CONFIG, &cmd,1);
cmd = 0x01;
mpu6050_WeReg(ACCEL_CONFIG, &cmd,1);
}
void mpu6050_ReadData(void)
{
uint8_t ucReadBuf[14];
mpu6050_RdReg( ACCEL_XOUT_H, ucReadBuf,14);
/* 将读出的数据保存到全局结构体变量 */
g_tMPU6050.Accel_X = (ucReadBuf[0] << 8) + ucReadBuf[1];
g_tMPU6050.Accel_Y = (ucReadBuf[2] << 8) + ucReadBuf[3];
g_tMPU6050.Accel_Z = (ucReadBuf[4] << 8) + ucReadBuf[5];
g_tMPU6050.Temp = (int16_t)((ucReadBuf[6] << 8) + ucReadBuf[7]);
g_tMPU6050.GYRO_X = (ucReadBuf[8] << 8) + ucReadBuf[9];
g_tMPU6050.GYRO_Y = (ucReadBuf[10] << 8) + ucReadBuf[11];
g_tMPU6050.GYRO_Z = (ucReadBuf[12] << 8) + ucReadBuf[13];
}
void mpu6050_test( void )
{
mpu6050_Init();
while(1)
{
HAL_Delay(1000);
mpu6050_ReadData();
{
printf("AX=%6d,AY=%6d,AZ=%6d,",
g_tMPU6050.Accel_X,
g_tMPU6050.Accel_Y,
g_tMPU6050.Accel_Z);
printf("GX=%6d,GY=%6d,GZ=%6d,T=%6d \r",
g_tMPU6050.GYRO_X,
g_tMPU6050.GYRO_Y,
g_tMPU6050.GYRO_Z,
g_tMPU6050.Temp);
}
}
}
/* End of this file */
2)创建mp6050.h,编写如下代码
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : mpu9050.h
* Description : I2C drive based on STM32F4
*
******************************************************************************
* @attention
*
* Copyright (c) 2024~2029 mingfei.tang
* All rights reserved.
*
*************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MPU6050_H
#define __MPU6050_H
#ifdef __cplusplus
extern "C" {
#endif
#include "stdio.h"
#include "main.h"
#define MPU6050_OK 1
#define MPU6050_ERROR 0
#define bsp_DelayMS HAL_Delay
#define MPU6050_SLAVE_ADDRESS 0xD0 /* I2C从机地址 */
//****************************************
// 定义MPU6050内部地址
//****************************************
#define SMPLRT_DIV 0x19 //陀螺仪采样率,典型值:0x07(125Hz)
#define CONFIG 0x1A //低通滤波频率,典型值:0x06(5Hz)
#define GYRO_CONFIG 0x1B //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
#define ACCEL_CONFIG 0x1C //加速计自检、测量范围及高通滤波频率,典型值:0x01(不自检,2G,5Hz)
#define ACCEL_XOUT_H 0x3B
#define ACCEL_XOUT_L 0x3C
#define ACCEL_YOUT_H 0x3D
#define ACCEL_YOUT_L 0x3E
#define ACCEL_ZOUT_H 0x3F
#define ACCEL_ZOUT_L 0x40
#define TEMP_OUT_H 0x41
#define TEMP_OUT_L 0x42
#define GYRO_XOUT_H 0x43
#define GYRO_XOUT_L 0x44
#define GYRO_YOUT_H 0x45
#define GYRO_YOUT_L 0x46
#define GYRO_ZOUT_H 0x47
#define GYRO_ZOUT_L 0x48
#define PWR_MGMT_1 0x6B //电源管理,典型值:0x00(正常启用)
#define WHO_AM_I 0x75 //IIC地址寄存器(默认数值0x68,只读)
typedef struct
{
int16_t Accel_X;
int16_t Accel_Y;
int16_t Accel_Z;
int16_t Temp;
int16_t GYRO_X;
int16_t GYRO_Y;
int16_t GYRO_Z;
}MPU6050_T;
extern MPU6050_T g_tMPU6050;
void mpu6050_test( void );
#ifdef __cplusplus
}
#endif
#endif /*__MPU6050_H */
5 测试
1)编写测试代码
void mpu6050_test( void )
{
mpu6050_Init();
while(1)
{
HAL_Delay(1000);
mpu6050_ReadData();
{
printf("AX=%6d,AY=%6d,AZ=%6d,",
g_tMPU6050.Accel_X,
g_tMPU6050.Accel_Y,
g_tMPU6050.Accel_Z);
printf("GX=%6d,GY=%6d,GZ=%6d,T=%6d \r",
g_tMPU6050.GYRO_X,
g_tMPU6050.GYRO_Y,
g_tMPU6050.GYRO_Z,
g_tMPU6050.Temp);
}
}
}
2)编写代码,并下载到板卡中,运行代码
6 逻辑分析仪捕捉波形
读取数据的波形