你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

物联网之STM32开发八(I2C总线通信)

[复制链接]
STMCU 发布时间:2020-9-28 13:22
STM32-I2C总线通信内容概要

I2C总线通信原理

三轴加速度传感器mpu6050介绍

I2C通信实例


I2C总线通信原理

内容概要:

I2C总线简介

I2C总线协议

I2C总线读写操作

STM32F0-I2C控制器特性


I2C总线简介:

I2C总线介绍:I2C(Inter-Integrated Circuit)总线(也称IIC或I2C)是由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备,是微电子通信控制领域广泛采用的一种总线标准。它是同步通信的一种特殊形式,具有接口线少,控制方式简单,期间封装形式少,通信速率高等优点。

I2C总线特征:

    两条总线线路:一条串行数据SDA,一条串行时钟线SCL来完成数据的传输及外围器件的扩展  

    I2C总线上的每一个设备都可以作为主设备或者从设备,而且每一个设备都会对应一个唯一的地址  

    I2C总线数据传输速率在标准模式下可达100kbit/s,快速模式下可达400kbit/s,高速模式下 可达3.4Mbit/s。一般通过I2C总线接口可编程时钟来实现传输速率的调整,同时也跟所接的上拉电阻的阻值有关。  

    I2C总线上的主设备与从设备之间以字节(8位)为单位进行单双工的数据传输。



I2C总线物理·拓扑结构:

1_meitu_1.jpg



I2C 总线在物理连接上分别由SDA(串行数据线)和SCL(串行时钟线)及上拉电阻组成。通信原理是通过对SCL和SDA线高低电平时序的控制,来产生I2C总线协议所需要的信号进行数据的传递。在总线空闲状态时,这两根线一般被上面所接的上拉电阻拉高,保持着高电平。



I2C总线协议:


2_meitu_2.jpg



I2C协议规定:  总线上数据的传输必须以一个起始信号作为开始条件,以一个结束信号作为传输的停止条件。起始和结束信号总是由主设备产生。总线在空闲状态时,SCL和SDA都保持着高电平。



起始信号:当SCL为高电平而SDA由高到低的跳变,表示产生一个起始条件

结束信号:当SCL为高电平而SDA由低到高的跳变,表示产生一个停止条件




数据传输:


    数据传输以字节为单位 , 主设备在SCL线上产生每个时钟脉冲的过程中将在SDA线上传输一个数据位,数据在时钟的高电平被采样,一个字节按数据位从高位到低位的顺序进行传输

    主设备在传输有效数据之前 要先指定从设备的地址,一般为7位,然后再发生数据传输的方向位, 0表示主设备向从设备写数据,1表示主设备向从设备读数据


应答信号:

    接收数据的器件在接收到 8bit 数据后,向发送数据的器件发出低电平的应答信号,表示已收到数据。这个信号可以是主控器件发出,也可以是从动器件发出。总之,由接收数据的器件发出。


I2C总线读写操作:

主设备往从设备写数据:

4_meitu_4.jpg

主设备读从设备数据:

5_meitu_5.jpg


注:当主设备不想接收从设备的数据时,主设备产生一个非应答信号,从设备接收到这个信号之后就停止发送数据。


主设备读从设备的某个寄存器:

                                                                           6_meitu_6.jpg


STM32F0-I2C控制器特性:


软件模拟I2C时序:由于直接控制 GPIO 引脚电平产生通讯时序时,需要由 CPU 控制每个时刻的引脚状态,所以称之为“软件模拟协议”方式。


硬件控制产生I2C时序:STM32 的 I2C 片上外设专门负责实现 I2C 通讯协议,只要配置好该外设,它就会自动根据协议要求产生通讯信号,收发数据并缓存起来,CPU只要检测该外设的状态和访问数据寄存器,就能完成数据收发。这种由硬件外设处理 I2C协议的方式减轻了 CPU 的工作,且使软件设计更加简单。


STM32F0-I2C控制器特性:

7_meitu_7.jpg



I2C的主要特点:

● I2C总线规范 rev03 兼容性:

    - 从机模式和主机模式

    - 多主机功能

    - 标准模式(高达 100kHz )

    - 快速模式(高达 400kHz )

    - 超快速模式(高达 1 MHz )

    - 7 位和 10 位地址模式

    - 软件复位


● 1 字节缓冲带 DMA 功能


STM32F0-I2C控制:

8_meitu_8.jpg



注:STM32F0XX中,PB6或者PB8任意一个可以作为I2C1的SCL,PB7或者PB9任意一个可作为I2C的SDA



I2C的主要特点:

 64KB片上闪存的F0带2个I2C:I2C1和I2C2

 32KB片上闪存的F0只带1个I2C:I2C1

 I2C2比I2C1所支持的功能少些,不具备

     对SMBus的硬件支持

     20mA的驱动能力

     模块双时钟域以及从停止模式唤醒



三轴加速度传感器mpu6050介绍

内容概要:

MPU6050简介

MPU6050特性参数

MPU6050寄存器介绍

MPU6050简介:

MPU-6050 是全球首例 6轴运动处理传感器。它集成了 3 轴 MEMS 陀螺仪,3 轴 MEMS 加速度计,以及一个可扩展的数字运动处理器 DMP(Digital Motion Processor),可用I2C 接口连接一个第三方的数字传感器,比如磁力计。扩展之后还可以通过其 I2C 输出一个 9 轴的信号。MPU-6050 也可以通过其 I2C 接口连接非惯性的数字传感器,比如压力传感器。



9_meitu_9.jpg



三轴加速度测量:

10_meitu_10.jpg



注意:加速度测量计反应的加速向量与当前的受力方向是相反的,如上图,受力方向向左,但是加速度的向量方向为右

陀螺仪:

陀螺仪,是用来测量角速度的,单位为度每秒(deg/s)



11_meitu_11.jpg



一个旋转物体的旋转轴所指的方向在不受外力影响时,是不会改变的。人们根据这个道理,用它来保持方向。Mpu6050有3个陀螺仪,可测X,Y,Z方向的角速度值



MPU6050的特性参数:

12_meitu_12.jpg



注:加速度最高分辨率算法:因为加速度是由16位的寄存器存放,故 精度 = 加速度测量范围/(2的16次方)  ,分辨率 = 1/精度 ,所以当加速测量范围越小,精度越好,分辨率越高。由上图表可知加速度测量范围是 正负2g的时候,由最高分辨率 (2的16次方)/(2-(-2)) = 16384 LSB/g。



MPU6050的寄存器介绍:

POWER MANAGEMENT电源管理寄存器:

13_meitu_13.jpg


SLEEP 该位置 1 ,  MPU-60X0 进入睡眠模式。  

CLKSEL置 0,可选择使用MPU-60X0 默认的内部8M振荡器作为时钟源


典型设置:

    I2C_WriteReg(MPU6050_RA_PWR_MGMT_1, 0x00);//解除休眠状态

SAMPLE RATE DIVIDER 采样频率分频器:


14_meitu_14.jpg


采样频率= 陀螺仪输出频率/ ( 1+SMPLRT_DIV )


当 DLPF s is disabled ( 0 DLPF_CFG=0 r or 7 7 7 7) ) ,陀螺输出频率 =8kHz ;


典型设置:

    I2C_WriteReg(MPU6050_RA_SMPLRT_DIV , 0x07); //陀螺仪采样率,1KHz


CONFIGURATION 低通滤波配置寄存器:


15_meitu_15.jpg



该寄存器配置外部引脚采样,陀螺仪和加速度计的数字低通滤波器。


典型设置:


    I2C_WriteReg(MPU6050_RA_CONFIG , 0x06); //低通滤波频率,典型值:0x06(带宽5KHz)

GYROSCOPE CONFIGURATION 陀螺仪配置寄存器:



16_meitu_16.jpg


17_meitu_17.jpg



该寄存器是用来触发陀螺仪自检和配置陀螺仪的满量程范围。


典型设置:
    I2C_WriteReg(MPU6050_RA_GYRO_CONFIG, 0x18);  //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)

ACCELEROMETER CONFIGURATION 加速度配置寄存器:




19_meitu_19.jpg



该寄存器是用来触发加速度计自检和配置加速度计的满量程范围。



典型设置:

    I2C_WriteReg(MPU6050_RA_ACCEL_CONFIG , 0x00); //配置加速度传感器工作在 2G 模式,不自检

读取X, Y, Z 三轴加速度的值:



20_meitu_20.jpg


21_meitu_21.jpg


读取X, Y, Z 三轴陀螺仪的值:


22_meitu_22.jpg


23_meitu_23.jpg


读取温度值:


24_meitu_24.jpg



摄氏度的温度可以用寄存器的置这么计算:


    Temperature n in s degrees C =      (TEMP_OUT  Register e Value  as  a signed  quantity)/340  + 36.53



MPU6050的设备地址:


25_meitu_25.jpg


MPU6050电气原理图:

26_meitu_26.jpg


注:R4未接,AD0直接接到电源上,因此设备地址为110 1001既0x69



I2C通信实例

利用STM32-I2C总线配置MPU6050,并读取三轴加速度的原始数据

过程如下:

27_meitu_27.jpg



28_meitu_28.jpg


29_meitu_29.jpg


将自己编写的mpu6050.h文件(主要是对mpu6050的一些寄存器地址 宏定义)拷贝到该工程对应的目录下:



30_meitu_30.jpg


新建文件mpu6050.c,然后添加到工程中:


31_meitu_31.jpg



32_meitu_32.jpg



33_meitu_33.jpg


34_meitu_34.jpg



  1. mpu6050.h文件内容如下:

  2. #ifndef __MPU6050_H
  3. #define __MPU6050_H

  4. /* Includes ------------------------------------------------------------------*/


  5. //****************************************
  6. // MPU6050 IIC测试程序
  7. // 功能: 显示加速度计和陀螺仪的16位原始数据
  8. //****************************************
  9. #include <math.h>    //IAR library
  10. #include <stdio.h>   //IAR library
  11. #include <stdint.h>
  12. //typedef unsigned char  uchar;
  13. typedef unsigned short ushort;
  14. //typedef unsigned int   uint;

  15. typedef short int16_t;


  16. //****************************************
  17. // 定义MPU6050内部地址
  18. //****************************************
  19. #define        ADDRESS_Write   SlaveAddress | 0x00                //
  20. #define        ADDRESS_Read    SlaveAddress | 0x01                        //



  21. #define        PWR_MGMT_1                0x6B              //电源管理,典型值:0x00(正常启用)
  22. #define        SMPLRT_DIV                0x19        //陀螺仪采样率,典型值:0x07(125Hz)
  23. #define        CONFIG                        0x1A        //低通滤波频率,典型值:0x06(5Hz)
  24. #define        GYRO_CONFIG                0x1B        //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
  25. #define        ACCEL_CONFIG        0x1C        //加速计自检、测量范围及高通滤波频率,典型值:0x00(不自检,2G,5Hz)

  26. #define        ACCEL_XOUT_H        0x3B
  27. #define        ACCEL_XOUT_L        0x3C
  28. #define        ACCEL_YOUT_H        0x3D
  29. #define        ACCEL_YOUT_L        0x3E
  30. #define        ACCEL_ZOUT_H        0x3F
  31. #define        ACCEL_ZOUT_L        0x40

  32. #define        TEMP_OUT_H                0x41
  33. #define        TEMP_OUT_L                0x42

  34. #define        GYRO_XOUT_H                0x43
  35. #define        GYRO_XOUT_L                0x44
  36. #define        GYRO_YOUT_H                0x45
  37. #define        GYRO_YOUT_L                0x46
  38. #define        GYRO_ZOUT_H                0x47
  39. #define        GYRO_ZOUT_L                0x48



  40. #define        WHO_AM_I                        0x75        //IIC地址寄存器(默认数值0x68,只读)
  41. //#define        SlaveAddress                //IIC写入时的地址字节数据,+1为读取
  42. #define MPU6050_ADDRESS_AD0_LOW     0x68 // address pin low (GND), default for InvenSense evaluation board
  43. #define MPU6050_ADDRESS_AD0_HIGH    0x69 // address pin high (VCC)
  44. #define SlaveAddress     (MPU6050_ADDRESS_AD0_HIGH<<1)

  45. void mpu6050_init(void);
  46. void mpu6050_getaccel(int16_t *x, int16_t *y, int16_t *z); //获取寄存器中三轴加速度的值
  47. void  mpu6050_verify(int16_t *x, int16_t *y, int16_t *z);
  48. #endif
复制代码

  1. ​mpu6050.c文件内容如下:

  2. #include"mpu6050.h"
  3. #include "i2c.h"
  4. #include "usart.h"

  5. void mpu6050_init(void)   //STM32F051K8通过I2C初始化mpu6050
  6. {                       
  7.   uint8_t temp        ;
  8.        
  9.         temp = 0x00;
  10.         HAL_I2C_Mem_Write(&hi2c1, ADDRESS_Write, PWR_MGMT_1, I2C_MEMADD_SIZE_8BIT, &temp, 1, 0x10);
  11. /*函数功能,向mpu6050的相关寄存器中写入数据。参数一:使用的是哪一个I2C,参数二:
  12. mpu6050的地址(7位)和读写操作标志位(1位),参数三:写到mpu6050内部的哪个寄存器,参数四:要写
  13. 的寄存器是多少位(宽度)的,参数五:写入寄存器的值,参数六:写多少个数据,参数七:设置超时*/
  14.        
  15.         temp = 0x07;
  16.         HAL_I2C_Mem_Write(&hi2c1, ADDRESS_Write, SMPLRT_DIV, I2C_MEMADD_SIZE_8BIT, &temp, 1, 0x10);
  17.        
  18.         temp = 0x06;
  19.         HAL_I2C_Mem_Write(&hi2c1, ADDRESS_Write, CONFIG, I2C_MEMADD_SIZE_8BIT, &temp, 1, 0x10);
  20.        
  21.                 temp = 0x18;
  22.         HAL_I2C_Mem_Write(&hi2c1, ADDRESS_Write, GYRO_CONFIG, I2C_MEMADD_SIZE_8BIT, &temp, 1, 0x10);
  23.        
  24.         temp = 0x00;
  25.         HAL_I2C_Mem_Write(&hi2c1, ADDRESS_Write, ACCEL_CONFIG, I2C_MEMADD_SIZE_8BIT, &temp, 1, 0x10);
  26.        
  27. }


  28. void mpu6050_getaccel(int16_t *x, int16_t *y, int16_t *z) //获取寄存器中三轴加速度的值
  29. {
  30.         uint8_t value[2];
  31.        
  32.          HAL_I2C_Mem_Read(&hi2c1, ADDRESS_Read, ACCEL_XOUT_L,I2C_MEMADD_SIZE_8BIT, &value[0], 1,0x10);
  33. /*函数功能:读取mpu6050内部寄存器的值。参数一:使用的是哪一个I2C,参数二:
  34. mpu6050的地址(7位)和读写操作标志位(1位),参数三:要读取mpu6050内部哪一个寄存器的值,参数
  35. 四:要读的寄存器是多少位(宽度)的,参数五:存放读取的数值的地址,参数六:读多少个数据,参数七:设
  36. 置超时*/  //获取x轴加速度值的低八位
  37.          HAL_I2C_Mem_Read(&hi2c1, ADDRESS_Read, ACCEL_XOUT_H,I2C_MEMADD_SIZE_8BIT, &value[1], 1,0x10);
  38. //获取x轴加速度值的高八位
  39.          *x = (value[1] << 8) + value[0];
  40.        
  41.          HAL_I2C_Mem_Read(&hi2c1, ADDRESS_Read, ACCEL_YOUT_L,I2C_MEMADD_SIZE_8BIT, &value[0], 1,0x10);
  42. //获取y轴加速度值的低八位
  43.          HAL_I2C_Mem_Read(&hi2c1, ADDRESS_Read, ACCEL_YOUT_H,I2C_MEMADD_SIZE_8BIT, &value[1], 1,0x10);
  44. //获取y轴加速度值的高八位
  45.          *y = (value[1] << 8) + value[0];
  46.        
  47.          HAL_I2C_Mem_Read(&hi2c1, ADDRESS_Read, ACCEL_ZOUT_L,I2C_MEMADD_SIZE_8BIT, &value[0], 1,0x10);
  48. //获取z轴加速度值的低八位
  49.          HAL_I2C_Mem_Read(&hi2c1, ADDRESS_Read, ACCEL_ZOUT_H,I2C_MEMADD_SIZE_8BIT, &value[1], 1,0x10);
  50. //获取z轴加速度值的高八位
  51.          *z = (value[1] << 8) + value[0];
  52.        
  53.         printf("acce value: %d  %d  %d\n",*x,*y,*z);
  54.        
  55. }
复制代码

35_meitu_35.jpg



  1. #include "mpu6050.h"

  2. int fputc(int ch,FILE *f){       
  3.     while((USART1->ISR&(1<<7)) == 0);       
  4.     USART1->TDR=(uint8_t)ch;
  5.     return ch;
  6. }
复制代码


main函数中初始化mpu6050



36_meitu_36.jpg


  1. #include "mpu6050.h"

  2. int fputc(int ch,FILE *f){       
  3.     while((USART1->ISR&(1<<7)) == 0);       
  4.     USART1->TDR=(uint8_t)ch;
  5.     return ch;
  6. }
复制代码

每隔一秒打印一次mpu6050三轴加速度的值:



37_meitu_37.jpg



  1. ​int16_t x, y, z;
  2. mpu6050_getaccel(&x, &y, &z);//获取并打印mpu6050三轴加速度的值
  3. HAL_Delay(1000);
复制代码

测试结果:

38.png



另外可实现读取并打印mpu6050三轴加速度的值(同三轴加速度的值获取和打印方法相同):


39_meitu_38.jpg



  1. ​​void  mpu6050_verify(int16_t *x, int16_t *y, int16_t *z)//获取寄存器中三轴角速度的值
  2. {
  3.         uint8_t value[2];
  4.        
  5.          HAL_I2C_Mem_Read(&hi2c1, ADDRESS_Read, GYRO_XOUT_L,I2C_MEMADD_SIZE_8BIT, &value[0], 1,0x10);
  6. /*函数功能:读取mpu6050内部寄存器的值。参数一:使用的是哪一个I2C,参数二:mpu6050的地址
  7. (7位)和读写操作标志位(1位),参数三:要读取mpu6050内部哪一个寄存器的值,参数四:要读的寄存器是多
  8. 少位(宽度)的,参数五:存放读取的数值的地址,参数六:读多少个数据,参数七:设置超时*/
  9.          HAL_I2C_Mem_Read(&hi2c1, ADDRESS_Read, GYRO_XOUT_H,I2C_MEMADD_SIZE_8BIT, &value[1], 1,0x10);
  10.          *x = (value[1] << 8) + value[0];
  11.        
  12.          HAL_I2C_Mem_Read(&hi2c1, ADDRESS_Read, GYRO_YOUT_L,I2C_MEMADD_SIZE_8BIT, &value[0], 1,0x10);
  13.          HAL_I2C_Mem_Read(&hi2c1, ADDRESS_Read, GYRO_YOUT_H,I2C_MEMADD_SIZE_8BIT, &value[1], 1,0x10);
  14.          *y = (value[1] << 8) + value[0];
  15.        
  16.          HAL_I2C_Mem_Read(&hi2c1, ADDRESS_Read, GYRO_ZOUT_L,I2C_MEMADD_SIZE_8BIT, &value[0], 1,0x10);
  17.          HAL_I2C_Mem_Read(&hi2c1, ADDRESS_Read, GYRO_ZOUT_H,I2C_MEMADD_SIZE_8BIT, &value[1], 1,0x10);
  18.          *z = (value[1] << 8) + value[0];
  19.        
  20.         printf("verify value: %d  %d  %d\n",*x,*y,*z);
  21. }
复制代码


测试结果:



40.png

3_meitu_3.jpg
18_meitu_18.jpg
收藏 评论0 发布时间:2020-9-28 13:22

举报

0个回答

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版