STM-32:I2C外设总线—硬件I2C读写MPU6050
目录
- 一、I2C外设简介
- 二、I2C框图
- 三、I2C基本结构
- 四、主机发送
- 五、主机接收
- 六、I2C的中断请求
- 七、软件/硬件波形对比
- 八、应用实例:硬件I2C读写MPU6050
- 8.1接线图
- 8.2程序代码
一、I2C外设简介
STM32内部集成了硬件I2C收发电路,可以由硬件自动执行时钟生成、起始终止条件生成、应答位收发、数据收发等功能,减轻CPU的负担【对比USART外设是串口通信的的硬件收发器】
支持多主机模型【分为固定多主机和可变多主机,STM32为可变多主机】
支持7位/10位地址模式
10位地址模式下,发送的前2个字节为地址,其中前5位是10位寻址的标志位(11110),后10位是地址位
支持不同的通讯速度,标准速度(高达100 kHz),快速(高达400 kHz)
支持DMA
兼容SMBus协议(主要用于电源管理系统中)
STM32F103C8T6 硬件I2C资源:I2C1、I2C2
二、I2C框图
主要操作控制寄存器(CR),数据寄存器(DR),状态寄存器(SR)
引脚设定
当数据从数据寄存器转到移位寄存器时,就会置状态寄存器TXE为1,表示发送寄存器为空
当数据从移位寄存器转到接收寄存器时,就会置状态寄存器RXNE为1,表示接收寄存器非空
自身地址寄存器:设定从机地址
双地址寄存器:也是设定从机地址
比较器:stm32作为从机时有从机地址,会将收到的寻址通过比较器进行判断
三、I2C基本结构
I2C通信是高位先行
使用硬件I2C时,GPIO口的模式为复用开漏输出
对于SDA线的GPIO口,可以完成复用开漏输出和复用功能输入,【硬件I2C使用复用开漏模式,软件I2C采用通用开漏模式】
四、主机发送
起始条件写1,当起始条件发出后自动清零,接口在生成起始条件后自动从从模式切换到主模式
EV5事件修改了SB标志位,也是由硬件自动清零
EV6事件修改ADDR标志位,在主模式下表示地址发送结束
EV8事件修改TXE标志位,此时数据寄存器为空,移位寄存器非空,可以写入新的数据到DR中,该状态表示移位寄存器正在发送数据
EV8_2事件修改BTF标志位,表示字节发送结束
停止条件P写1
五、主机接收
EV7事件修改RXNE标志位,此时DR寄存器非空,移位寄存器为空
六、I2C的中断请求
七、软件/硬件波形对比
I2C同步时序对于波形的要求不高,硬件I2C的波形更加标准
八、应用实例:硬件I2C读写MPU6050
8.1接线图
8.2程序代码
MPU6050.c
#include "stm32f10x.h" // Device header
#include "MPU6050_Reg.h"#define MPU6050_ADDRESS 0xD0
//等待和超时退出函数
void MPU6050_WaitEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{uint32_t Timeout;Timeout = 10000;while (I2C_CheckEvent(I2Cx, I2C_EVENT) != SUCCESS){Timeout --;if (Timeout == 0){break;}}
}//指定地址写
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{I2C_GenerateSTART(I2C2, ENABLE);//生成起始条件/*非阻塞式函数需要通过状态标志位判断是否完成*/MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);//检查EV5事件I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Transmitter);//发送7位地址,读写标志位由第三个参数决定,该函数自带接收应答的过程【接收数据也自带发送应答功能】MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);//检查EV6事件I2C_SendData(I2C2, RegAddress);//将数据写入DR寄存器,硬件自动转到移位寄存器MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING);//检查EV8事件I2C_SendData(I2C2, Data);MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);//检查EV8——2事件I2C_GenerateSTOP(I2C2, ENABLE);//生成终止条件
}
//指定地址读,先指定地址写,再调用当前地址读
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{uint8_t Data;//指定地址写I2C_GenerateSTART(I2C2, ENABLE);MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Transmitter);MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);I2C_SendData(I2C2, RegAddress);MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);//当前地址读I2C_GenerateSTART(I2C2, ENABLE);//重复起始条件MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Receiver);//发送7位地址,读写标志位由第三个参数决定,不是发送则则置1,发送则为0MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);//EV6事件/*如果只需要接收一个字节,则在EV6事件之后需要ACK置0且配置stop标志位,否则会多读取一个字节如果是接收多个字节则直接等待EV7事件,在EV7_1事件之前ACK置0且配置stop标志位为1*/I2C_AcknowledgeConfig(I2C2, DISABLE);//配置ACK应答位为0I2C_GenerateSTOP(I2C2, ENABLE);//配置停止位MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED);//等待EV7事件Data = I2C_ReceiveData(I2C2);//将数据读取到DR寄存器,硬件自动转到移位寄存器I2C_AcknowledgeConfig(I2C2, ENABLE);//恢复ACK应答位为1,方便指定地址收多个字节return Data;
}
//硬件I2C初始化和指定地址写
void MPU6050_Init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);//I2C初始化I2C_InitTypeDef I2C_InitStructure;I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;I2C_InitStructure.I2C_ClockSpeed = 50000;//最大400KHzI2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;/*在标准速度下占空比为1:1,在快速模式下设置才有用,有2个参数可以选择,低电平:高电平分别是16:9和2:1,因为在scl低电平时sda会切换电平,此时适当多分配低电平时间可以在快速模式下完成电平变化。*/I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;//配置ack应答位I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//stm32作为从机可以响应多少位地址I2C_InitStructure.I2C_OwnAddress1 = 0x00;//作为从机时设置自身地址1I2C_Init(I2C2, &I2C_InitStructure);I2C_Cmd(I2C2, ENABLE);MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);MPU6050_WriteReg(MPU6050_CONFIG, 0x06);MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);
}uint8_t MPU6050_GetID(void)
{return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}
//获取数据寄存器函数,参数为指针,指向各个数据寄存器的地址
void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ)
{uint8_t DataH, DataL;DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);*AccX = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);*AccY = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);*AccZ = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);*GyroX = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);*GyroY = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);*GyroZ = (DataH << 8) | DataL;
}
MPU6050.h
#ifndef __MPU6050_H
#define __MPU6050_Hvoid MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data);
uint8_t MPU6050_ReadReg(uint8_t RegAddress);void MPU6050_Init(void);
uint8_t MPU6050_GetID(void);
void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ);#endif
MPU6050_Reg.h
使用宏定义,将寄存器地址用一个字符串表示
#ifndef __MPU6050_REG_H
#define __MPU6050_REG_H#define MPU6050_SMPLRT_DIV 0x19
#define MPU6050_CONFIG 0x1A
#define MPU6050_GYRO_CONFIG 0x1B
#define MPU6050_ACCEL_CONFIG 0x1C#define MPU6050_ACCEL_XOUT_H 0x3B
#define MPU6050_ACCEL_XOUT_L 0x3C
#define MPU6050_ACCEL_YOUT_H 0x3D
#define MPU6050_ACCEL_YOUT_L 0x3E
#define MPU6050_ACCEL_ZOUT_H 0x3F
#define MPU6050_ACCEL_ZOUT_L 0x40
#define MPU6050_TEMP_OUT_H 0x41
#define MPU6050_TEMP_OUT_L 0x42
#define MPU6050_GYRO_XOUT_H 0x43
#define MPU6050_GYRO_XOUT_L 0x44
#define MPU6050_GYRO_YOUT_H 0x45
#define MPU6050_GYRO_YOUT_L 0x46
#define MPU6050_GYRO_ZOUT_H 0x47
#define MPU6050_GYRO_ZOUT_L 0x48#define MPU6050_PWR_MGMT_1 0x6B
#define MPU6050_PWR_MGMT_2 0x6C
#define MPU6050_WHO_AM_I 0x75#endif
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "MPU6050.h"uint8_t ID;
int16_t AX, AY, AZ, GX, GY, GZ;int main(void)
{OLED_Init();MPU6050_Init();OLED_ShowString(1, 1, "ID:");ID = MPU6050_GetID();OLED_ShowHexNum(1, 4, ID, 2);while (1){MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ);OLED_ShowSignedNum(2, 1, AX, 5);OLED_ShowSignedNum(3, 1, AY, 5);OLED_ShowSignedNum(4, 1, AZ, 5);OLED_ShowSignedNum(2, 8, GX, 5);OLED_ShowSignedNum(3, 8, GY, 5);OLED_ShowSignedNum(4, 8, GZ, 5);}
}
参考视频:江科大自化协
STM-32:I2C外设总线—硬件I2C读写MPU6050相关推荐
- STM32——I2C外设总线
文章目录 一.I2C外设简介 二.I2C框图 三.I2C基本结构 四.主机发送 五.主机接收 六.I2C的中断请求 七.软件/硬件波形对比 八.硬件I2C读写MPU6050 电路设计 关键代码 状态监 ...
- 基于I2C/SPI总线的温湿度采集与OLED显示
实验一 实验目的 学习I2C总线通信协议,使用STM32F103完成基于I2C协议的AHT20温湿度传感器的数据采集,并将采集的温度-湿度值通过串口输出.具体任务: 1)解释什么是"软件I2 ...
- STC8系列单片机硬件I2C使用教程(二)
硬件I2C(中断方式)以STC8F2K08S2单片机为例 一.I2C相关的寄存器 二.I2C中断相关的寄存器 ① I2C中断源 ② I2C中断允许位 ③ I2C中断标志位 三.程序编写 ① 寄存器和相 ...
- STM32F10x_硬件I2C读写EEPROM(标准外设库版本)
Ⅰ.写在前面 上一篇文章是"STM32F10x_模拟I2C读写EEPROM",讲述使用IO口模拟I2C总线通信,对EEPROM(AT24Xxx)进行读写操作的过程. 上一篇文章主要 ...
- STM32CubeMX学习教程之十:硬件I2C读写AT24C02
完整源码下载: https://github.com/simonliu009/STM32CubeMX-hardware-I2C-AT24C02 网上有流传已久一种说法,就是STM的I2C有bug,不好 ...
- bme280 环境传感器开发板_STM32Cube14 | 使用硬件I2C读写环境光强度传感器
更多精彩~点击上面蓝字关注我们呀! 寻求更好的阅读体验,请点击阅读原文移步:Mculover666的个人博客. 本篇详细的记录了如何使用STM32CubeMX配置STM32L431RCT6的硬件I ...
- STC8A8K64单片机关于AT24C04基本读写操作(包含硬件I2C与软件模拟I2C)
实验:AT24C04基本读写操作 步骤及现象:在下载程序前,选择stc-isp的IRC频率:12MHz. 程序下载完成后,在串口助手界面,HEX模式下,选择波 特率9600,然后点击"打开串 ...
- STM32HAL库学习笔记--硬件I2C读写AT24C512
摘要:由于需要实现掉电存储功能,在无线传输模块上增加了一块EEPROM芯片,因为工程使用CubeMx配置并生成,为了方便不再使用IO口模拟I2C,而是使用f1自带的硬件I2C来实现.配置和调试过程和遇 ...
- I2C总线及AT24C02读写
I2C总线介绍 I2C总线(Inter IC BUS)是由Philips公司开发的一种通用数据总线 两根通信线:SCL(Serial Clock).SDA(Serial Data) 同步.半双工,带数 ...
最新文章
- AttributeError: module ‘os‘ has no attribute ‘mknod‘
- java json解析 代码_Java构造和解析Json数据的两种方法详解一
- 以太坊服务器是什么_搭建以太坊节点服务器https API
- su一键封面插件_插件分享丨一键制作SU爆炸分析图插件分享
- java 二分法 应用_介绍一下java中的二分法运用
- vtk鼠标不交互_vtk 各种不同的鼠标交互方式
- RocketMQ为什么速度快
- string会传null吗_JVM 解剖公园(10): String.intern()
- Asterisk权威指南/第二章 Asterisk架构
- STM32之SDIO例程
- 虚拟机网络驱动(共享文件夹)不见了的解决方案-适用于win7~win10 and Windows Server 2008~Windows Server 2012R2
- 用jquery怎么删除table的一行
- 法语语音教学课件下载
- 存储器的分类及层次结构
- 太牛了,值得收藏!7000字22张图,精讲 Redis 知识!
- 网络新手ip隐藏器 v1.10 官方
- Extended Kalman Filter vs. Error State Kalman Filter for Aircraft Attitude Estimation 翻译
- 第13届中国生物特征识别大会即将盛大开幕,中科博宏期待您的到来!
- 王炸-GPT4.0的新能力与商业价值
- 后缀自动机入门/基本概念