当前位置: 首页 > article >正文

嵌入式开发--STM32用HAL库硬件I2C读取MPU6050的数据

MPU6050简介

在这里插入图片描述

MPU6050是一款6轴传感器,可检测3轴位移和3轴加速度,MCU可通过I2C接口操作。注意接口线需要上拉电阻,一般为10K,在距离远或干扰强的场合,可降低通讯速率,和适当减小电阻值,比如4.7K。

STM32的I2C接口

一般通过2种方式来操作I2C接口

软件I2C

控制GPIO引脚来模拟I2C的时序,这就是常说的软件I2C,也是应用得比较多的方式。正点原子的例程均以软件I2C方式。
这种方式可控性强,也便于理解I2C时序。但是增加了MCU的负担,操作周期会大于硬件方式,效率不高。

硬件I2C

用STM32自带的I2C硬件控制器来操作,也就是硬件I2C。
正点原子不推荐这种方式,理由是STM32的I2C不好用。网上也普遍流传说STM32的I2C容易死机等等,但这属于人云亦云的说法,我做过测试,证明STM32的I2C是完全可用的,具体测试和问题排查可以看我另一篇文章,《嵌入式开发-STM32硬件I2C驱动OLED屏》。
本文就以硬件I2C的方式来进行操作。

MPU6050电路

我是将MPU6050做在一块扩展板上,再通过数据线与MCU的主控板相连,原理图如下:
在这里插入图片描述
第9脚是用来设置MPU6050的设备地址的,接地后,设备地址是0x68,但是在I2C协议中是用高7位表示设备地址,所以0x68需要左移一位,就变成了0xD0,最低位为1表示读操作,最低位为0表示写操作。
也就是最后的地址是0xD1(读)和0xD0(写)

CubeMX设置

用的是PC8和PC9引脚
在这里插入图片描述

开启I2C3,默认的基本设置

在这里插入图片描述
在GPIO标签,需要将引脚速度设置为高或非常高
在这里插入图片描述

用到的函数

是用正点原子的例程改的,其实改动也就是读和写的相关函数,总共就4个。
读,写,连续读,连续写。而且只改写这4个函数的内容,接口保持不变。
HAL库提供可以用的函数有4个,分为mem和master,具体如下:

HAL_I2C_Master_Transmit()
HAL_I2C_Master_Receive()
HAL_I2C_Mem_Read()
HAL_I2C_Mem_Write()

可以只用前2个函数,也可以只用后2个,最后的效果基本等价,这里讲一下他们的区别。
以读操作为例,代码如下:

u8 MPU_Read_Byte(u8 reg)
{
  u8 data;
  
  HAL_I2C_Mem_Read(&hi2c3, MPU6050_WRITE_ADDR, MPU_DEVICE_ID_REG, 1, &data, 1, 100);

  HAL_Delay(1); 	//上下代码二选一,同样功能,在此只是为了演示方便
    
  HAL_I2C_Master_Transmit(&hi2c3, MPU6050_WRITE_ADDR, &reg, 1, 100);
  HAL_I2C_Master_Receive(&hi2c3, MPU6050_READ_ADDR, &data, 1, 100);
  
  return data;
}

接下来演示一下读ID号的波形差别。

MPU_Read_Byte(MPU_DEVICE_ID_REG);

可以看到mem函数一行就可以了,而master函数需要2行,mem函数要简洁一些,用逻辑分析仪看二者的波形如下:先是mem后master
在这里插入图片描述
在这里插入图片描述
可以看到二者时序略有不同,但功能是一样的。最终的运行时间也只相差了半个I2C时钟周期而已,可以忽略。

全部代码

修改的代码如下,只改了这4个函数,其他参照正点原子。

#define MPU6050_I2C           hi2c3

//AD0引脚(9脚)接低,表示0x68为地址,再左移1位为0xd0,最低位表示读写选择
#define MPU_ADDR				0X68
#define MPU6050_READ_ADDR     (MPU_ADDR<<1)|1
#define MPU6050_WRITE_ADDR    (MPU_ADDR<<1)|0


//I2C写一个字节 
//reg:寄存器地址
//data:数据
//返回值:0,正常
//       其他,错误代码
u8 MPU_Write_Byte(u8 reg,u8 data) 				 
{
  return HAL_I2C_Mem_Write(&MPU6050_I2C, MPU6050_WRITE_ADDR, reg, 1, &data, 1, 100);
}


//I2C读一个字节 
//reg:寄存器地址 
//返回值:读到的数据
u8 MPU_Read_Byte(u8 reg)
{
  u8 data;
  
  HAL_I2C_Mem_Read(&MPU6050_I2C, MPU6050_WRITE_ADDR, MPU_DEVICE_ID_REG, 1, &data, 1, 100);

//  HAL_Delay(1);
//  
//  HAL_I2C_Master_Transmit(MPU6050_I2C, MPU6050_WRITE_ADDR, &reg, 1, 100);
//  HAL_I2C_Master_Receive(MPU6050_I2C, MPU6050_READ_ADDR, &data, 1, 100);
  
  return data;
}


//IIC连续写
//addr:器件地址 
//reg:寄存器地址
//len:写入长度
//buf:数据区
//返回值:0,正常
//       其他,错误代码
u8 MPU_Write_Len(u8 addr,u8 reg,u8 len,u8 *buf)
{
  return HAL_I2C_Mem_Write(&MPU6050_I2C, MPU6050_WRITE_ADDR, reg, 1, buf, len, 100);
}


//IIC连续读
//addr:器件地址
//reg:要读取的寄存器地址
//len:要读取的长度
//buf:读取到的数据存储区
//返回值:0,正常
//       其他,错误代码
u8 MPU_Read_Len(u8 addr,u8 reg,u8 len,u8 *buf)
{ 
  HAL_I2C_Mem_Read(&MPU6050_I2C, MPU6050_WRITE_ADDR, reg, 1, buf, len, 100);
  return 0;
}

http://www.kler.cn/news/365951.html

相关文章:

  • 最新版本jdbcutils集成log4j做详细sql日志、自动释放连接...等
  • [bug] vllm 0.6.1 RuntimeError: operator torchvision::nms does not exist
  • 如何用 obdiag 排查 OceanBase数据库的卡合并问题——《OceanBase诊断系列》14
  • sharpkeys-键盘部分按键不好用,用其它不常用按键代替
  • GD32学习知识点累计
  • 微信小程序性能优化 ==== 合理使用 setData 纯数据字段
  • React18-useEffect函数
  • mfc之tab标签控件的使用--附TabSheet源码
  • 在SpringBoot项目中利用Redis实现防止订单重复提交
  • java springboot项目如何计算经纬度在围栏内以及坐标点距离
  • SMT 生产可视化:提升电子组装流程效率
  • 常用排序算法总结
  • GPS/北斗时空安全隔离装置(卫星时空防护装置)使用手册
  • 计算机视觉篇---图像分类实战+理论讲解(6)Mobilenet
  • 数据结构入门之复杂度
  • 数据结构与算法:贪心与相关力扣题455.分发饼干、376.摆动序列、53.最大子数组和(贪心+动态规划dp)、122.买卖股票的最佳时机Ⅱ
  • 25届电信保研经验贴(自动化所)
  • 基于 STM32 单片机的智能门禁系统创新设计
  • Java从List中删除元素的几种方式
  • 【C语言刷力扣】441.排列硬币
  • 基于行业分类的目标检测与跟踪系统
  • .NET 8 Web API从基础到提高全面示例
  • 电脑技巧:Rufus——最佳USB启动盘制作工具指南
  • 【代码随想录Day51】图论Part03
  • 第五十五章 安全元素的详细信息 - ReferenceList 详情
  • 可能是NextJs(使用ssr、api route)打包成桌面端(nextron、electron、tauri)的最佳解决方式