STM32学习笔记14-I2C硬件控制

I2C外设简介


  • STM32内部集成了硬件I2C收发电路(硬件收发器:自动生产波形,自动翻转电平等),可以由硬件自动执行时钟生成、起始终止条件生成、应答位收发、数据收发等功能,减轻CPU的负担——软件只需要写入控制寄存器CR和DR,还有实时监控时序状态的状态寄存器SR
  • 支持多主机模型
  • 支持7位/10位地址模式
  • 支持不同的通讯速度,标准速度(高达100 kHz),快速(高达400 kHz)
  • 支持DMA
  • 兼容SMBus协议
  • STM32F103C8T6 硬件I2C资源:I2C1、I2C2

补:多主机模型:固定多主机(有固定的主机数和固定的从机数)和可变多主机(任何设备,都可以从空闲的状态跳出来作为主机,然后指定通信,之后又跳回来),采用10位地址的时序:起始条件后的两个字节都是寻址,其中前一个字节,是帧头:内容是5位的标志位11110+2位地址+1位读写位,后一个字节:纯粹的8位地址。

I2C框图

引脚对应关系

I2C基本结构(一主多从)

硬件I2C的操作流程:

主机发送

主机接收

软件/硬件波形对比

手册——对应24章

接线图

10-2 硬件I2C读写MPU6050


  1. 开启I2C外设和对应GPIO口的时钟
  2. 把I2C外设对应的GPIO口初始化为复用开漏模式
  3. 使用结构体,对整个I2C进行配置
  4. I2C_Cmd,使能I2C

相关函数:

void I2C_DeInit(I2C_TypeDef* I2Cx);

void I2C_Init(I2C_TypeDef* I2Cx, I2C_InitTypeDef* I2C_InitStruct);

void I2C_StructInit(I2C_InitTypeDef* I2C_InitStruct);

void I2C_Cmd(I2C_TypeDef* I2Cx, FunctionalState NewState);

void I2C_GenerateSTART(I2C_TypeDef* I2Cx, FunctionalState NewState);  //生产起始条件

void I2C_GenerateSTOP(I2C_TypeDef* I2Cx, FunctionalState NewState);  //生产结束条件

void I2C_AcknowledgeConfig(I2C_TypeDef* I2Cx, FunctionalState NewState);  //配置应答ACK

void I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data);  //数据写入DR寄存器

uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx);  //读取DR的数值

void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction);  //发送7位地址的专用函数

//EV——多种监控

I2C_CheckEvent()  //基本

I2C_GetLastEvent()  //高级

I2C_GetFlagStatus()   //基于状态位的标准监控

void I2C_ClearFlag(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG);

ITStatus I2C_GetITStatus(I2C_TypeDef* I2Cx, uint32_t I2C_IT);

void I2C_ClearITPendingBit(I2C_TypeDef* I2Cx, uint32_t I2C_IT);

MPU6050.c//27硬件I2C读写MPU6050
//与软件的区别就是MyI2C.c这个文件,硬件是不需要的
//意思是:底层的逻辑会有不同,其他是一样的
#include "stm32f10x.h"                  // Device header#define MPU_ADD   0xD0
#include "MPU_Reg.h"
//封装指定地址写和指定地址读的时序
//优化:在代码中,存在很多死循环的地方——超时退出void CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT){uint32_t TimeOut;TimeOut=100;	while(I2C_CheckEvent(I2Cx, I2C_EVENT)!=SUCCESS){TimeOut--;if(TimeOut==0){break;//错误处理}}
}void MPU_WriteReg(uint8_t RegAddress,uint8_t Data){//用此函数,则会一直传输数据,所以我们需要用标志位去确定它是否操作成功了,这里就要用EV5事件来确定I2C_GenerateSTART(I2C2, ENABLE);//while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT)!=SUCCESS);//封装
//		while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT)!=SUCCESS){
//			TimeOut--;
//			if(TimeOut==0){
//				return;
//			}
//		}CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);//发送函数会自带应答位,所以我们不需要考虑应答,只需要考虑发送后的事件EV6即可I2C_Send7bitAddress(I2C2,MPU_ADD, I2C_Direction_Transmitter); CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);//EV8_1的事件是提醒应该写入DR数据,不需要等待I2C_SendData(I2C2, RegAddress); //同理,等待对应的事件EV8CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING); I2C_SendData(I2C2, Data);//当发送为最后一个数据时,就需要等待EV8_2事件CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);I2C_GenerateSTOP(I2C2, ENABLE); }uint8_t MPU_ReadingReg(uint8_t RegAddress){uint8_t Data;I2C_GenerateSTART(I2C2, ENABLE);CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT); //发送函数会自带应答位,所以我们不需要考虑应答,只需要考虑发送后的事件EV6即可I2C_Send7bitAddress(I2C2,MPU_ADD, I2C_Direction_Transmitter); CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); //EV8_1的事件是提醒应该写入DR数据,不需要等待I2C_SendData(I2C2, RegAddress); //在最后一个数据,用EV8_2while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED)!=SUCCESS); I2C_GenerateSTART(I2C2, ENABLE);while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT)!=SUCCESS); //主机接收I2C_Send7bitAddress(I2C2,MPU_ADD, I2C_Direction_Receiver); while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)!=SUCCESS); //接收从机的数据:规定:在接收数据之前,需要把ACK置0,同时设置停止位STOP//如果读取多个字节,那直接等待EV7事件,读取DR,就能收到数据,在接收最后一个字节之前EV7_1事件,需要把ACK置0,同时设置停止位STOP//如果读取一个字节,那在EV6事件之后,需要把ACK置0,同时设置停止位STOP,在等待EV7事件,不然会多一个字节I2C_AcknowledgeConfig(I2C2, DISABLE);I2C_GenerateSTOP(I2C2,ENABLE);while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED)!=SUCCESS); //读取DRData=I2C_ReceiveData(I2C2); I2C_AcknowledgeConfig(I2C2, ENABLE);  //应答值设为1,给从机应答,这样可以使指定地址收多个字节return Data;}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_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11;GPIO_Init(GPIOB, &GPIO_InitStructure);I2C_InitTypeDef I2C_InitStructure;I2C_InitStructure.I2C_Mode =I2C_Mode_I2C;  //I2C的模式I2C_InitStructure.I2C_ClockSpeed=50000;  //时钟频率,要低于400KHzI2C_InitStructure.I2C_DutyCycle=I2C_DutyCycle_2;//时钟占空比,只有在时钟频率大于100KHz才有用,小于则固定的1:1;——能更快的传输I2C_InitStructure.I2C_Ack=I2C_Ack_Enable;  //应答配置I2C_InitStructure.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit;  //STM做从机,可以被响应几位地址I2C_InitStructure.I2C_OwnAddress1=0x00;  //自身寄存器,当STM32做从机时,指定STM32的自身地址,方便主机呼叫I2C_Init(I2C2,&I2C_InitStructure);I2C_Cmd(I2C2,ENABLE);MPU_WriteReg(MPU6050_PWR_MGMT_1,0x01);  //解除睡眠,选择陀螺仪时钟MPU_WriteReg(MPU6050_PWR_MGMT_2,0x00);	//6个轴均不待机MPU_WriteReg(MPU6050_SMPLRT_DIV,0x09);	//采样分频为10MPU_WriteReg(MPU6050_CONFIG,0x06);	//滤波参数最大MPU_WriteReg(MPU6050_GYRO_CONFIG,0x18);	//陀螺仪和加速度选择最大MPU_WriteReg(MPU6050_ACCEL_CONFIG,0x18);
//	//此时的MPU就在进行大量的数据转换,数据存放在其他的寄存器里
}void MPU_Getdata(int16_t *AccX, int16_t *AccY, int16_t *AccZ, int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ)  
{//读取加速度寄存器XYZ轴的高8位和低8位uint8_t DataH, DataL;								//定义数据高8位和低8位的变量DataH = MPU_ReadingReg(MPU6050_ACCEL_XOUT_H);		//读取加速度计X轴的高8位数据DataL = MPU_ReadingReg(MPU6050_ACCEL_XOUT_L);		//读取加速度计X轴的低8位数据*AccX = (DataH << 8) | DataL;						//数据拼接,通过输出参数返回DataH = MPU_ReadingReg(MPU6050_ACCEL_YOUT_H);		//读取加速度计Y轴的高8位数据DataL = MPU_ReadingReg(MPU6050_ACCEL_YOUT_L);		//读取加速度计Y轴的低8位数据*AccY = (DataH << 8) | DataL;						//数据拼接,通过输出参数返回DataH = MPU_ReadingReg(MPU6050_ACCEL_ZOUT_H);		//读取加速度计Z轴的高8位数据DataL = MPU_ReadingReg(MPU6050_ACCEL_ZOUT_L);		//读取加速度计Z轴的低8位数据*AccZ = (DataH << 8) | DataL;						//数据拼接,通过输出参数返回DataH = MPU_ReadingReg(MPU6050_GYRO_XOUT_H);		//读取陀螺仪X轴的高8位数据DataL = MPU_ReadingReg(MPU6050_GYRO_XOUT_L);		//读取陀螺仪X轴的低8位数据*GyroX = (DataH << 8) | DataL;						//数据拼接,通过输出参数返回DataH = MPU_ReadingReg(MPU6050_GYRO_YOUT_H);		//读取陀螺仪Y轴的高8位数据DataL = MPU_ReadingReg(MPU6050_GYRO_YOUT_L);		//读取陀螺仪Y轴的低8位数据*GyroY = (DataH << 8) | DataL;						//数据拼接,通过输出参数返回DataH = MPU_ReadingReg(MPU6050_GYRO_ZOUT_H);		//读取陀螺仪Z轴的高8位数据DataL = MPU_ReadingReg(MPU6050_GYRO_ZOUT_L);		//读取陀螺仪Z轴的低8位数据*GyroZ = (DataH << 8) | DataL;						//数据拼接,通过输出参数返回}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/93621.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/93621.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电子电气架构 --- 软件开发数字化转型

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 简单,单纯,喜欢独处,独来独往,不易合同频过着接地气的生活,除了生存温饱问题之外,没有什么过多的欲望,表面看起来很高冷,内心热情,如果你身…

我国空间站首次应用专业领域 AI大模型

据中国载人航天工程办公室消息&#xff0c;北京时间2025年8月15日22时47分&#xff0c;经过约6.5小时的出舱活动&#xff0c;神舟二十号乘组航天员陈冬、陈中瑞、王杰密切协同&#xff0c;在空间站机械臂和地面科研人员的配合支持下&#xff0c;圆满完成既定任务&#xff0c;出…

WPF真入门教程35--手搓WPF出真汁【蜀味正道CS版】

1、项目介绍 本项目采用多层架构设计&#xff0c;使用wpf&#xff0c;Panuon.UI.Silver控件库&#xff0c;AduSkin皮肤&#xff0c;MVVM等技术开发具有复杂交互和视觉效果的CS应用程序。WPF适用于企业级桌面应用&#xff1a;如ERP、CRM系统&#xff0c;需复杂表单和报表。WPF适…

JMeter与大模型融合应用之构建AI智能体:评审性能测试脚本

JMeter与大模型融合应用之构建AI智能体&#xff1a;评审性能测试脚本 一、引言 随着DevOps和持续测试的普及&#xff0c;性能测试已成为软件开发生命周期中不可或缺的环节。Apache JMeter作为最流行的开源性能测试工具之一&#xff0c;被广泛应用于各种性能测试场景。然而&…

K8s 和 Docker的区别

一、各自诞生背景——为什么需要两个东西Docker&#xff08;2013&#xff0c;Docker Inc.&#xff09; • 目的&#xff1a;解决“我的代码在你机器跑不起来”的经典环境问题。 • 做法&#xff1a;用 Linux 内核的 cgroup/namespace 做轻量隔离&#xff0c;把“应用 依赖”打…

10.0 UML的介绍以及VisualStudio中查看类图

本文介绍UML图的含义、以及如何在VisualStudio中查看类图。 一、UML图介绍 UML(Unified Modeling Language,统一建模语言)是一种标准化的建模语言,用于可视化、规范、构建和记录软件系统的各个方面的图表工具。 UML图分为结构图和行为图两大类: 结构图‌…

【Virtual Globe 渲染技术笔记】6 着色

着色&#xff08;Shading&#xff09; 曲面细分只是地球渲染的第一步。接下来是着色——通过模拟光线与材质的相互作用&#xff0c;计算每个像素的最终颜色。本节先回顾基础的光照与纹理映射&#xff0c;再讲解虚拟地球特有的经纬网格和夜景灯光效果。6.1 光照&#xff08;Ligh…

OpenCV Python——图像拼接(一)(图像拼接原理、基础知识、单应性矩阵 + 图像变换 + 拼接)

1 图像拼接基础知识1.1 特征匹配 原理及代码示例1.2 单应性矩阵 原理及代码示例2 图像拼接&#xff08;一&#xff09;&#xff08;直接拼接&#xff09;3 图像拼接&#xff08;二&#xff09;&#xff08;单应性矩阵 图像变换 拼接&#xff09;3.1 单应性矩阵函数3.2 拼接函…

Git 中切换到指定 tag

在 Git 中切换到指定 tag&#xff08;比如 v1.22.1&#xff09;的正确做法如下&#xff1a;1️⃣ 查看已有的 taggit tag会列出所有可用的版本&#xff0c;比如&#xff1a;v1.21.0 v1.22.0 v1.22.1 v1.23.02️⃣ 切换到指定 taggit checkout tags/v1.22.1 -b v1.22.1解释&…

rust 从入门到精通之变量和常量

变量和常量 随着软件系统安全的重要性与日俱增, rust这门集聚高并发, 安全, 适配云环境的编程语言在市场上得到了越来越高的认可和关注。但其复杂的机制使其难以学习。且其很多特性对于其他语言是全新的&#xff0c;这加剧了学习的困难程度。教程主要针对rust基础进行讲解, 虽然…

2508C++,支持rdma通信的高性能rpc库

原文 [重磅]支持rdma通信的高性能的rpc库–yalantinglibs.coro_rpc yalantinglibs的coro_rpc是基于C20的协程的高性能的rpc库,提供了简洁易用的接口,让用户几行代码就可实现rpc通信,现在coro_rpc除了支持tcp通信之外还支持了rdma通信(ibverbs). 通过简单示例来感受一下rdma通…

FastAPI + React:现代 Web 前后端分离开发的全栈实践指南

一、为什么选 FastAPI React&#xff1f; 性能&#xff1a;FastAPI 基于 Starlette Uvicorn&#xff0c;QPS 与 Node/Go 同级&#xff0c;实测 3 倍于 Flask&#xff1b;React 虚拟 DOM 代码分割&#xff0c;首屏 < 1.2 s。效率&#xff1a;FastAPI 内置 Swagger/OpenAPI…

嵌入式硬件篇---电平转换电路

电平转换电路是电子电路中用来实现不同电压信号之间转换的关键电路&#xff0c;比如把 3.3V 的信号转换成 5V&#xff0c;或者把 5V 转换成 1.8V&#xff0c;确保不同电压的芯片、模块能正常通信。下面用通俗易懂的方式介绍几种常见的电平转换电路&#xff1a;一、电阻分压电路…

SAP ABAP IS SUPPLIED

效果 此谓词表达式用于检查过程的某个形式参数“para”是否已赋值或被请求使用。如果在调用时实际参数被赋值给了该形式参数&#xff0c;则该表达式为真。 这种关系表达式仅能在函数模块和方法中使用。而对于“para”而言&#xff0c;所有可选的形参都可以进行指定。 加上“NOT…

视频内容提取与AI总结:提升学习效率的实用方法

文章目录1、前言2、方法介绍2.1 B站视频处理方案2.2 通用视频处理方案2.3 AI内容总结3、实际效果4、使用建议5、技术发展趋势6、总结&#x1f343; 作者介绍&#xff1a;25届双非本科网络工程专业&#xff0c;阿里云专家博主&#xff0c;专注于 AI 原理、AI 应用开发、AI 产品设…

JVM 面试精选 20 题

目录1. 什么是 JVM、JDK 和 JRE&#xff1f;它们之间的关系是什么&#xff1f;2. Java 内存区域&#xff08;运行时数据区&#xff09;有哪些&#xff1f;3. 说说你对 JVM 垃圾回收机制的理解。4. 常用的垃圾回收算法有哪些&#xff1f;5. 什么是 Minor GC、Major GC 和 Full G…

CMIP6 气候模式核心特性解析

在全球气候变化研究中&#xff0c;CMIP6&#xff08;第六次耦合模式比较计划&#xff09;的气候模式是关键工具。以下从研发背景与核心能力角度&#xff0c;解析五类主流模式的技术特点与适用场景。 一、主流模式技术特性 1. CanESM5/CanESM5-1&#xff08;加拿大环境与气候变…

【牛客刷题】BM63 跳台阶:三种解法深度解析(递归/DP动态规划/记忆化搜索)

文章目录 一、题目介绍 1.1 题目描述 1.2 示例 二、算法设计思路 2.1 核心问题分析 2.2 斐波那契数列关系 三、流程图 解法1:递归法(自顶向下) 解法2:动态规划(自底向上) 解法3:记忆化搜索(递归优化) 解法4: 优化DP流程(推荐) 四、解法实现 五、复杂度分析对比 六、…

《解构WebSocket断网重连:指数退避算法的前端工业级实践指南》

WebSocket作为客户端与服务器双向通信的核心载体,支撑着从在线协作、金融行情到即时通讯等各类高实时性场景。然而,网络环境的动态变化—从用户设备的Wi-Fi与蜂窝网络切换,到公共网络的临时拥塞,再到服务器的短暂重启—都可能导致WebSocket连接中断,进而引发数据传输停滞、…

医疗洁净间的“隐形助手”:富唯智能复合机器人如何重塑手术器械供应链

当手术刀片在无影灯下传递时&#xff0c;0.01mm的抓取偏差可能意味着感染风险——而富唯智能复合机器人以0.02mm的重复定位精度与99.999%无菌操作的硬实力&#xff0c;正成为高端医疗产线中替代人力的关键技术支点。一、医疗上下料的三大痛点&#xff1a;精度、洁净与连续性1.毫…