目录

一、I2C

1.I2C简介

2.MPU6050参数 

3.I2C时序基本单元

二、I2C外设

1.I2C外设简介

2.配置I2C基本结构

3.初始化函数模板

4.常用函数 


一、I2C

1.I2C简介


本节课使用的是MPU6050硬件外设

2.MPU6050参数 


3.I2C时序基本单元

这里发送应答是指主机发送,即STM32作为主机,MPU6050或其他I2C通信外设作为从机,我们接收到从机的数据后要给从机发送应答位以供从机判断我们是不是还需要数据。

接收应答则是判断从机有没有接收到数据,并且我们要将SDA的控制权转交给从机,即释放SDA(拉高)。

结合以下两种时序理解上面6种基本时序单元

 在起始条件后紧跟着的一个字节就是七位从机地址和一位读写位,0代表写,1代表读。

不同的芯片厂商对第二位字节数据的作用要求不同,MPU6050规定第二个字节数据是指定寄存器地址

在对寄存器进行读写时,地址指针会自动加1,比如这里地址一开始指向0x19,写入数据后指向0x1A,所以想要对特定地址进行读操作,就要先写入寄存器地址,再重复起始条件发送从机地址和读操作,这时候没有指定寄存器的操作,从机会自动将数据发送给你。 

以上就是I2C通信的时序,可以通过GPIO口软件模拟I2C通信,本节主要学习STM32的硬件I2C外设


二、I2C外设

1.I2C外设简介


2.配置I2C基本结构


由于硬件I2C不同于软件模拟,我们不知道一个字节的数据是否发送完毕等等,因此STM32设置了许多代表不同事件的标志位


3.初始化函数模板

void MPU6050_Init(void)
{	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2,ENABLE);//I2C1和2都是APB1的设备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);//初始化I2CI2C_InitTypeDef I2C_InitStructure;I2C_InitStructure.I2C_Mode=I2C_Mode_I2C;//选择I2C模式I2C_InitStructure.I2C_ClockSpeed=50000;//时钟速度 可配置SCL时钟频率I2C_InitStructure.I2C_DutyCycle=I2C_DutyCycle_2;//配置占空比I2C_InitStructure.I2C_Ack=I2C_Ack_Enable;//应答位配置I2C_InitStructure.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit;//作为从机时能响应多少位的地址I2C_InitStructure.I2C_OwnAddress1=0x00;//STM32作为从机时的地址,长度和上面参数对应I2C_Init(I2C2,&I2C_InitStructure);I2C_Cmd(I2C2,ENABLE);
}

这里GPIO口模式选择复用开漏输出,虽然是输出,但仍然可以输入,应为这里默认高电平是一种弱上拉,从机要发送数据只需要进行拉低电平或释放这一种操作,“拉”或“不拉”,主机读取电平就能接收从机发送的数据。PB10和PB11是I2C2的引脚。


初始化I2C后,封装指定地址写和指定地址读两个函数

//指定地址写
void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data)//参数为寄存器地址和要写入的数据
{
//	MyI2C_Start();
//	MyI2C_SendByte(0xD0);从机地址
//	MyI2C_ReceiveAck();
//	MyI2C_SendByte(RegAddress);
//	MyI2C_ReceiveAck();
//	MyI2C_SendByte(Data);
//	MyI2C_ReceiveAck();
//	MyI2C_Stop(); I2C_GenerateSTART(I2C2,ENABLE);//起始条件//判断EV5事件while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT)!=SUCCESS);I2C_Send7bitAddress(I2C2,0xD0,I2C_Direction_Transmitter);//发送从机地址,选择“写”//判断EV6事件,这里的EV6选择“发送事件已选择”while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)!=SUCCESS);I2C_SendData(I2C2,RegAddress);//发送寄存器地址//判断EV8事件,“字节正在发送”while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTING)!=SUCCESS);I2C_SendData(I2C2,Data);//发送数据//判断EV8_2事件,即移位寄存器空,且没有新数据要发while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED)!=SUCCESS);I2C_GenerateSTOP(I2C2,ENABLE);//终止条件
}

这里判断各个标志位用I2C_CheckEvent ()函数,完成各个标志位会返回SUCCESS,这里判断等于SUCCESS跳出循环,以免数据没有发送完全等。硬件I2C和软件I2C不同的是:软件I2C因为是手动模拟,发送字节数据都是完整的,是通过发送和接收应答位来判断双方交流是否正常;而硬件I2C则是判断标志位,并不需要管应答位,只需要使能ACK应答位即可。

//指定地址读
uint8_t MPU6050_ReadReg(uint8_t RegAddress)//参数为寄存器地址
{uint8_t Data;//	MyI2C_Start();
//	MyI2C_SendByte(0xD0);从机地址
//	MyI2C_ReceiveAck();
//	MyI2C_SendByte(RegAddress);
//	MyI2C_ReceiveAck();
//	
//	MyI2C_Start();
//	MyI2C_SendByte(0xD0|0x01);
//	MyI2C_ReceiveAck();
//	Data=MyI2C_ReceiveByte();
//	MyI2C_SendAck(1);
//	MyI2C_Stop();//这里和指定地址写的前三步一样,即指定寄存器地址I2C_GenerateSTART(I2C2,ENABLE);//起始条件while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT)!=SUCCESS);I2C_Send7bitAddress(I2C2,0xD0,I2C_Direction_Transmitter);//发送从机地址,选择“写”while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)!=SUCCESS);I2C_SendData(I2C2,RegAddress);//发送寄存器地址while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTING)!=SUCCESS);I2C_GenerateSTART(I2C2,ENABLE);//重复起始条件//判断EV5while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT)!=SUCCESS);I2C_Send7bitAddress(I2C2,0xD0,I2C_Direction_Receiver);//发送从机地址,选择“读”//等待EV6事件,选择“接收事件已选择”while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)!=SUCCESS);//在接收最后一个字节时,要提前将ACK置0,并且产生终止条件I2C_AcknowledgeConfig(I2C2,DISABLE);//ACK=0,不给应答I2C_GenerateSTOP(I2C2,ENABLE);//STOP=1,申请产生终止条件//判断EV7事件,意味着数据移到DR寄存器,可以读走了while(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED)!=SUCCESS);Data=I2C_ReceiveData(I2C2);//读取数据//最后将应答位置1I2C_AcknowledgeConfig(I2C2,ENABLE);return Data;
}

 指定地址读的前三步和指定地址写一样,起始条件后发送从机地址,写寄存器地址,然后重复起始条件,发送从机地址选择“读”,这里判断EV6事件就不同于指定地址写。

因为我们写和读都是只有一个字节的数据,所以指定地址读后就是接收最后一个字节,如果接收多个字节则是判断EV7事件,这里接收一个字节也是最后一个字节,要提前将ACK置0(失能),同时申请终止条件。最后终止条件产生后判断EV7事件,读走DR寄存器的数据。最后将ACK置1(使能)(我的理解是因为要在主循环里不断调用读的操作,在初始化函数里通过结构体参数I2C_Ack使能ACK,意味着正常读写ACK都是处于使能的状态,而函数I2C_AcknowledgeConfig可以单独配置ACK的状态,为了后续正常运行,所以最后还要将ACK使能)

附:在主发送和主接收的序列图中,发送从机地址后,我们会判断EV6事件,可以看到后面还接了一个EV8_1事件,这个事件是提醒我们该写入数据发送出去了,因此我们不需要判断EV8_1事件

参数列表里也没有EV8_1事件。


4.常用函数 

I2C_GenerateSTART,生成起始条件

I2C_GenerateSTOP,生成终止条件

l2C_SendData,发送数据

I2C_ReceiveData,接收数据

I2C_AcknowledgeConfig,使能或失能ACK,给ENABLE就是就是给从机应答

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

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

相关文章

HSA22HSA29美光固态芯片D8BJVC8BJW

HSA22HSA29美光固态芯片D8BJVC8BJW 美光固态芯片D8BJVC8BJW系列:技术革新与行业应用深度解析 一、技术解析:核心架构与创新突破 美光D8BJVC8BJW系列固态芯片(如MT29F8T08EQLEHL5-QAES:E、MT29F512G08CUCABH3-12Q等)的技术竞争力…

【Linux网络与网络编程】06.应用层协议HTTP

前言 虽然应用层协议是我们程序猿自己定的,但实际上已经有大佬们定义了一些现成的又非常好用的应用层协议供我们直接参考使用,HTTP(超文本传输协议)就是其中之一。 在互联网世界中,HTTP(HyperText Transfer Protocol&#xff0c…

磁悬浮轴承的“生死线”:磁轴承气隙与保护轴承气隙的可靠性设计

在高速旋转机械的尖端领域,磁悬浮轴承(AMB)凭借无摩擦、超高转速、免润滑等优势傲视群雄。然而,其核心参数——气隙的设置,尤其是额定工作气隙与保护轴承(辅助轴承)气隙之间的大小关系与具体数值…

QT 学习笔记摘要(一)

第一节 QT介绍 1. QT概述 简单来说,QT就是一个跨平台的客户端技术,HTML画网页一样,而QT就是画客户端的,它不仅可以绘制界面而且可以做单机应用开发,还可以做网络程序的客户端界面开发 更专业的说法是:Qt 是…

QCustomPlot 叠加对象(Overlay Items)

QCustomPlot 提供了一系列可以在图表上叠加显示的对象(items),这些对象不属于数据本身,而是用于标注、辅助线等用途。以下是主要叠加对象的详细说明和使用方法。 1. QCPItemStraightLine (无限直线) 特性: 无限延伸的…

Flink源码阅读环境准备全攻略:搭建高效探索的基石

想要深入探索Flink的底层原理,搭建一套完整且适配的源码阅读环境是必经之路。这不仅能让我们更清晰地剖析代码逻辑,还能在调试过程中精准定位关键环节。接下来,结合有道云笔记内容,从开发工具安装、源码获取导入到调试配置&#x…

Dify,FastGPT,RagFlow有啥区别,在智能问答方面有啥区别

Dify、FastGPT、RagFlow都是当前非常流行的低代码AI应用开发平台,它们都专注于让用户能够快速构建AI应用,但在设计理念、功能特色和适用场景上有明显区别。 让我详细对比一下这三个平台: 1. 平台定位对比 Dify 定位:全栈AI应用…

基站定位接口如何如何用PHP实现调用?

随着“新基建”战略的推进,我国移动通信基站数量快速增长。截至2024年底,全国基站总数已达1265万个,其中5G基站超425万个,构建起全球规模最大、技术领先的通信网络。 在这一基础上,基站查询API通过整合三大运营商数据…

Day 4:Shell流程控制——从“直线思维“到“智能决策“的进化

目录 一、if语句:你以为简单其实暗藏杀机1. 基础语法(看似简单却容易踩坑)2. 安全写法规范(企业级建议) 二、条件测试的六大门派1. 文件测试(运维最爱)2. 字符串比较(引号是灵魂&…

分布式训练中的随机种子策略:深入理解与实践指南

分布式训练中的随机种子策略:深入理解与实践指南 引言:一个容易被忽视的关键细节 在深度学习的分布式训练中,你是否见过这样的代码? torch.manual_seed(process_seed) # PyTorch操作 random.seed(process_seed) # Pyth…

金山办公发布WPS智慧教育平台,发力教育AI意义何在?

钛媒体消息,金山办公发布面向教育用户的 WPS 智慧教育平台,面对着金山办公的发力,我们该怎么分析呢? 首先,从市场拓展与用户需求响应角度看,金山办公此次推出WPS智慧教育平台,直接瞄准了教育领…

无人机航电系统之语音通信技术篇

无人机航电系统的语音通信技术是确保无人机与地面控制站、其他无人机或相关人员之间实现高效、稳定语音交互的关键技术,在军事侦察、应急救援、物流运输、航拍测绘等众多领域发挥着至关重要的作用。 一、技术原理 无人机航电系统的语音通信技术主要基于无线通信原理…

element plus 的树形控件,如何根据后台返回的节点key数组,获取节点key对应的node节点

在使用 Element Plus 的 el-tree 组件时,如果后端返回的节点 key 数组中包含了部分选中的父级节点的 key,可能会导致该父级节点下的所有子节点也被默认选中。这是因为 el-tree 的默认行为是:如果一个父节点被选中,那么其所有子节点…

什么是Sentinel

什么是 Sentinel? 在分布式系统中,服务间的依赖关系错综复杂。一个服务的故障,很可能像多米诺骨牌一样,迅速蔓延并导致整个系统崩溃,这就是我们常说的“雪崩效应”。为了避免这种灾难性后果,我们需要一种强大的机制来保护我们的系统,而 Sentinel 正是为此而生。 Senti…

AWS 使用图形化界面创建 EKS 集群(零基础教程)

无需命令行!通过 AWS 控制台图形化操作,轻松创建 Kubernetes 集群。 文章目录 文章简介 一、准备工作:登录 AWS 控制台 二、创建 EKS 集群(控制面) 1. 创建 EKS 集群 2. 设置集群基本信息 3. 配置网络设置 三、添加…

[C#] Winform - 进程间通信(SendMessage篇)

一、发送端 // 窗体:发送端 public partial class SendForm : Form {public SendForm(){InitializeComponent();}// 按钮:发送private void btnSend_Click(object sender, System.EventArgs e){IntPtr hwnd User32Helper.FindWindow(null, "接收端…

锂电池保护板测试仪:守护电池安全的幕后保障

在电动汽车、储能电站和便携式电子设备中,锂电池作为核心动力源,其能量密度与安全性始终是行业关注的焦点。锂电池在过充、过放、短路等异常情况下可能引发起火甚至爆炸,而锂电池保护板正是解决这一问题的关键组件。为确保保护板性能可靠&…

Qemu搭建RISC-V,运行opensbi+u-boot+img

✨1.先下载一个Ubuntu镜像 https://cdimage.ubuntu.com/releases/24.04/release/ 我这里下载的是这个RISC-V的 🌟1.2.解压镜像 xz -d ubuntu-24.04.2-preinstalled-server-riscv64.img.xz ✨2.准备RISC-V的QEMU 打开qemu官网https://www.qemu.org/&#xff0c…

【实战手册】银河麒麟服务器系统进入单用户模式修改密码(root)指南

目录 前言 一、银河麒麟单用户模式简介 二、进入单用户模式修改密码 三、登录验证新密码 结语 前言 在日常服务器运维工作中,忘记root密码是系统管理员偶尔会遇到的问题。作为国产操作系统的优秀代表,银河麒麟服务器系统提供了通过单用户模式重置r…

偏微分方程通解求解2

题目 求下列方程的通解: { u x y = u x u y u − 1 ; u x y = u x u y ; u x y = u x u y u u 2 + 1 ; \begin{cases} u_{xy} = u_x u_y u^{-1}; \\ u_{xy} = u_x u_y; \\ u_{xy} = \dfrac{u_x u_y u}{u^2 + 1}; \end{cases} ⎩⎪⎪⎨⎪⎪⎧​uxy​=ux​uy​u−1;uxy​=ux​…