I2C通信

1.I2C通信简介

简述:I2C只有一根通信线,数据在一条线上传输。同步,即由时钟线带领数据传输,可以在CPU处理其它事件时停止传输数据,处理完后再重新开始。

2.I2C的硬件电路

解释:1.SDA的控制权只有在从机发送数据和从机应答时才会交给从机,而SCL的控制权一直都在主机(即CPU)手中。

2.注意图中第二点,开漏即一边接地,一边接电阻,就是强下拉、弱上拉,避免电路短路。(开漏加弱上拉兼具输入和输出功能)

3.软件控制I2C通信(时序设计)

1.时序基本单元

1.起始和终止

2.发送

逻辑:主机控制SCL,在SCL低电平时将数据放在SDA上,从机在SCL高电平时读取主机放在SDA上的数据(注意高位先行),在这个单元中SCL和SDA都由主机控制,从机被动读取数据。

3.接收

注意:实线是主机控制的电平,虚线是从机控制的电平。

特别注意:主机在接收之前,需要释放SDA(释放相当于主机将SDA的控制权交给了从机,给从机放数据

逻辑:SCL低电平时,从机放数据在SDA上,SCL高电平时,主机读取SDA上的数据

4.应答(确认是否收到或发送成功)

2.收发时序格式

基本格式:从机地址(7字节)+读写操作(1字节)+从机应答位+寄存器地址(读操作没有)+写入(读出)数据

指定地址读:前半部分为写操作(指定地址),后半部分为读操作。(先写起始写入地址,再读起始写入数据)

注意:写入一个数据后,地址指针会自动加1(地址指针指向寄存器)。如果主机想连续读取多个字节,就要在最后一个字节给应答。(给0)

3.基本配置格式(手动配置时序)

//将置电平操作封装成函数(方便移植和修改) //Bitaction是一个枚举类型,表示这个位是高电平还是低电平 void MyI2C_W_SCL(uint8_t BitValue) { GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction)BitValue); Delay_us(10); } void MyI2C_W_SDA(uint8_t BitValue) { GPIO_WriteBit(GPIOB,GPIO_Pin_11,(BitAction)BitValue); Delay_us(10); } uint8_t MyI2C_R_SDA(void) { uint8_t BitValue; BitValue=GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11); Delay_us(10); return BitValue; } //SCL和SDA配置成开漏输出,SCL和SDA置高电平 void MyI2C_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); GPIO_InitTypeDef GPIO_InitStructure;//结构体定义 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD;//开漏输出 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10|GPIO_Pin_11;//IO口 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitStructure); GPIO_SetBits(GPIOB,GPIO_Pin_10|GPIO_Pin_11);//此函数可以把引脚设置为高电平 } //起始时序 void MyI2C_Start(void) { MyI2C_W_SDA(1); MyI2C_W_SCL(1); MyI2C_W_SDA(0); MyI2C_W_SCL(0); } //终止时序 void MyI2C_Stop(void) { MyI2C_W_SDA(0); MyI2C_W_SCL(1); MyI2C_W_SDA(1); } //主机发送、从机接收数据的时序 void MyI2C_SendByte(uint8_t Byte) { uint8_t i; for(i=0;i<8;i++) { MyI2C_W_SDA(Byte&(0x80>>i)); MyI2C_W_SCL(1); MyI2C_W_SCL(0); } } //从机发送、主机接收数据的时序 uint8_t MyI2C_ReceiveByte(void) { uint8_t Byte=0x00,i; MyI2C_W_SDA(1); MyI2C_W_SCL(1); for(i=0;i<8;i++) { MyI2C_W_SCL(1); if(MyI2C_R_SDA()==1){Byte|=(0x80>>i);} MyI2C_W_SCL(0); } return Byte; } //发送应答时序 void MyI2C_SendAck(uint8_t AckBit) { MyI2C_W_SDA(AckBit); MyI2C_W_SCL(1); MyI2C_W_SCL(0); } //接收应道时序 uint8_t I2C_ReceiveAck(void) { unsigned char AckBit; MyI2C_W_SDA(1); MyI2C_W_SCL(1); AckBit=MyI2C_R_SDA(); MyI2C_W_SCL(0); return AckBit; }

4.硬件实现I2C通信(STM32内部的I2C外设)

1.I2C外设简介

2.STM32中I2C外设的内部结构图

发送:当数据由数据寄存器转到数据移位寄存器时,状态寄存器的TXE位置1(表发送寄存器为空)

接收:当数据由数据移位寄存器转到数据寄存器时,状态寄存器的RXNE位置1(表示接收寄存器非空)

比较器、自身地址寄存器、双地址寄存器(了解):当STM32充当从机时使用

错误校验计算(了解):CRC数据校验算法,硬件自动校验

3.I2C基本结构图

此时GIOP口要配置成复用开漏输出模式

4.硬件I2C的操作流程

1.主机发送

1.STM32默认为从模式,需要给控制寄存器CR1中的Star位t写入1(会自动清除)才能进入主模式,产生起始条件

2.EV5是一个大标志位,判断是否数据起始条件已发送

3.EV6事件就是ADDR位为1,代表寻址结束

4.EV8_1事件就是TxE标志位为1,写入数据

5.EV8事件就是移位寄存器正在发送数据

6.EV8_2事件请求停止

7.P事件:配置CR1中的Stop位为1产生终止条件

2.主机接收

1.STM32默认为从模式,需要给控制寄存器CR1中的Star位t写入1(会自动清除)才能进入主模式,产生起始条件

2.EV5是一个大标志位,判断是否数据起始条件已发送

3.EV6事件就是ADDR位为1,代表寻址结束

4.EV6_1事件就是数据正在通过移位寄存器进行输入

5.EV7事件就是数据输入完成后,RxNE标志位置1,表示数据寄存器非空

6.EV7_1事件请求停止,应答位ACK置0

7.EV9事件配置CR1中的Stop位为1产生终止条件

3.硬件I2C的实战代码

1.部分函数功能
//生成起始条件 void I2C_GenerateSTART(I2C_TypeDef* I2Cx, FunctionalState NewState); //生成终止条件 void I2C_GenerateSTOP(I2C_TypeDef* I2Cx, FunctionalState NewState); //配置CR1的ACK(即为从机应答位,给1为非应答,给0为应答) void I2C_AcknowledgeConfig(I2C_TypeDef* I2Cx, FunctionalState NewState); //将数据写入DR寄存器 void I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data); //读取DR寄存器的数据 uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx); //发送7位地址的专用函数 void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction);
2.配置思路
1.RCC开启时钟(把I2C外设和对应的GPIO口的时钟打开)
2.配置GPIO(配置成复用开漏输出模式)
3.配置I2C外设
4.开启I2C(使能)
3.基本配置格式(使用库函数实现时序)

注意:硬件配置I2C是非阻塞式的,需要等待标志位,否则得到的波形会出现问题。(利用MPU6050_WaitEvent()函数监控标志位)

//此代码为通过硬件I2C外设来控制MPU6050的配置代码(包含头文件MPU6050_Reg) //注意:建议配合江协视频和MPU6050的芯片手册观看 #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); MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);//等待EV6事件 I2C_SendData(I2C2, RegAddress); 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);//等待EV5事件 I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Transmitter); MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);//等待EV6事件(主机发送) I2C_SendData(I2C2, RegAddress); MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);//等待EV8事件 //开始正式读取 I2C_GenerateSTART(I2C2, ENABLE); MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);//等待EV5事件 I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Receiver); MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);//等待EV6事件(主机接收) I2C_AcknowledgeConfig(I2C2, DISABLE);//ACK置0 I2C_GenerateSTOP(I2C2, ENABLE);//配置停止位 MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED); Data = I2C_ReceiveData(I2C2); I2C_AcknowledgeConfig(I2C2, ENABLE);//恢复ACK return Data; } //初始化 void MPU6050_Init(void) { //I2C1和I2C2都是APB1上的外设 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_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;//应答位配置(ACK) I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//STM32作为从机时用多少位地址 I2C_InitStructure.I2C_OwnAddress1 = 0x00; I2C_Init(I2C2, &I2C_InitStructure); I2C_Cmd(I2C2, ENABLE); }
//此代码为头文件MPU6050_Reg(就是MPU6050相关的寄存器的地址) #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

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

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

相关文章

如何一键生成炫酷效果闪图?闪图在线制作教程

闪图凭借明快的切换节奏、醒目的视觉效果&#xff0c;成为社交分享、海报点缀、短视频素材的热门选择。不用掌握复杂设计技巧&#xff0c;借助便捷的在线闪图制作工具&#xff0c;就能轻松制作出炫酷闪图&#xff0c;无论是日常娱乐还是创意创作&#xff0c;都能让你的内容脱颖…

1小时验证创意:VLA原型开发实战

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 提供三个可选原型模板&#xff1a;1) 社交媒体自动标注工具 2) 无障碍阅读辅助器 3) 智能相册管理器。用户选择模板后&#xff0c;自动生成对应代码框架和示例数据集。每个模板预置…

C语言一维与二维数组名详解:从本质理解到高手应用

在C语言中&#xff0c;数组名看似简单&#xff0c;却是许多初学者容易混淆的重点和难点。理解数组名的本质&#xff0c;是掌握C语言数组编程的关键一步。数组是C语言中最基础且重要的数据结构之一&#xff0c;而数组名作为数组的标识符&#xff0c;其背后隐藏的语义和特性对于初…

15.华为OD机考 - 执行任务赚积分

一、题目描述 现有N个任务需要处理,同一时间只能处理一个任务,处理每个任务所需要的时间固定为1。 每个任务都有最晚处理时间限制和积分值,在最晚处理时间点之前处理完成任务才可获得对应的积分奖励。 可用于处理任务的时间有限,请问在有限的时间内,可获得的最多积分。 二…

深入解析strspn:字符串扫描的精确尺子

<摘要> strspn是C标准库中一个极具特色的字符串函数&#xff0c;它像一把精确的尺子&#xff0c;用于测量字符串开头连续包含在指定字符集中的字符数量。本文将用生活化的比喻&#xff08;如安检通道、货币兑换窗口等&#xff09;生动解释其功能&#xff0c;详细剖析函数…

《Ascend C 进阶实战:高性能 Softmax 算子设计与数值稳定性优化》

《Ascend C 进阶实战&#xff1a;高性能 Softmax 算子设计与数值稳定性优化1. 引言&#xff1a;Softmax 的挑战Softmax 是分类任务中的核心算子&#xff0c;定义为&#xff1a;Softmax(xi​)∑j​exj​exi​​看似简单&#xff0c;但在 NPU 上高效实现却面临三大挑战&#xff1…

路径覆盖是一种白盒测试方法,旨在设计足够的测试用例,使得程序中的每一条可能执行路径至少被执行一次

路径覆盖的实际可行情况 路径覆盖是一种白盒测试方法&#xff0c;旨在设计足够的测试用例&#xff0c;使得程序中的每一条可能执行路径至少被执行一次。理论上&#xff0c;若一段代码包含多个分支&#xff08;如 if-else、循环等&#xff09;&#xff0c;其组合会产生大量路径。…

如何进行gif动画制作?GIF动画在线制作全攻略

想制作专属表情包、工作演示动图&#xff0c;或是记录生活中的趣味瞬间?不用纠结专业软件的复杂操作&#xff0c;一款便捷的GIF动画在线制作工具就能满足需求&#xff0c;从素材上传到动画生成全程简单易懂&#xff0c;新手也能快速上手&#xff0c;轻松解锁创意动画制作技能。…

设计一个支持多种任务类型的任务调度器,需综合考虑任务的触发机制、执行周期、优先级管理

设计一个支持多种任务类型的任务调度器&#xff0c;需综合考虑任务的触发机制、执行周期、优先级管理、资源分配和同步协调。其核心目标是实现高响应性、可预测性和可扩展性&#xff0c;尤其适用于嵌入式系统、实时系统或复杂业务平台。 设计思路与关键组件&#xff1a; 任务抽…

临时笔记1

Maven:管 jar 包和项目构建,不用手动下载 / 配置 jar 包; MyBatis:管 DAO 层,不用手写 JDBC 和反射; Spring:管所有对象的创建和依赖,不用手动 new,还能统一处理日志 / 异常; SpringBoot:管整个项目的配置和…

Jenkins自由风格作业构建和推送dokcer镜像

云原生环境下Dockerfile 职责分工的主流实践—— 核心逻辑是「研发主导编写、运维兜底适配、Dockerfile 随代码版本化管理」&#xff0c;既符合 “谁开发谁负责” 的权责匹配&#xff0c;也保障了镜像构建的标准化和环境兼容性,Dockerfile 本质是「应用运行环境的代码化描述」&…

雨燕直播案例分析:如何打造高并发直播平台

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 分析一个高并发直播平台的架构设计&#xff0c;包括&#xff1a;1. 负载均衡策略&#xff1b;2. 视频流分发网络(CDN)配置&#xff1b;3. 弹幕消息队列处理&#xff1b;4. 用户行为…

普中开发板基于51单片机贪吃蛇游戏设计

基于51单片机贪吃蛇游戏设计( proteus仿真程序设计报告讲解视频&#xff09; 仿真图proteus8.17(有低版本) 程序编译器&#xff1a;keil 4/keil 5 编程语言&#xff1a;C语言 设计编号&#xff1a;P24 1主要功能&#xff1a; 基于51单片机的贪吃蛇游戏设计 1、采用8*8点…

告别等待:CentOS 7.6镜像极速下载方案

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 设计一个CentOS 7.6镜像加速下载工具。利用多线程、CDN优选和P2P技术提升下载速度。自动选择最快的镜像站点&#xff0c;支持断点续传。包含速度测试功能&#xff0c;可实时显示下载…

小白也能懂的连接错误解决指南

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个交互式新手学习应用&#xff1a;1. 用快递送货比喻网络连接 2. 设计5个常见错误的动画演示 3. 提供一键检测按钮 4. 输出带emoji的简单报告 5. 内置救命按钮连接社区支持。…

QMS软件系统——全链可控·数据驱动·知识沉淀:全星QMS赋能企业质量数字化

QMS软件系统——全链可控数据驱动知识沉淀&#xff1a;全星QMS赋能企业质量数字化 在当今日益激烈的市场竞争中&#xff0c;质量不仅是企业的生命线&#xff0c;更是赢得客户信任、提升品牌价值的核心要素。《全星质量管理QMS软件系统》作为一套集成了15大核心功能模块的全面质…

用AI优化GPU性能测试:Furmark的智能分析新思路

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个基于AI的GPU性能分析工具&#xff0c;能够自动解析Furmark测试数据。要求&#xff1a;1. 实时读取Furmark测试结果数据 2. 使用机器学习模型分析温度曲线、帧率稳定性等指标…

如何用AI快速生成Flink面试题答案?

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个AI辅助工具&#xff0c;能够根据用户输入的Flink面试题自动生成详细的解答。解答应包括&#xff1a;1. 问题分析&#xff1b;2. 核心概念解释&#xff1b;3. 代码示例&…

21、Ubuntu 软件安装、卸载与系统维护全攻略

Ubuntu 软件安装、卸载与系统维护全攻略 在 Ubuntu 系统中,软件的安装与卸载以及系统的维护和安全保障是日常使用中非常重要的环节。下面将详细介绍多种软件管理方式以及系统维护的相关内容。 1. Synaptic 软件包管理器 Synaptic 除了有用于显示类别和安装状态的“Sections…

Jenkins部署零基础入门:AI帮你写出第一个Pipeline

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 为完全的新手生成一个最简单的Jenkins部署教程。要求&#xff1a;1. 从安装Jenkins开始&#xff1b;2. 创建一个简单的HTML项目部署流水线&#xff1b;3. 每个步骤都有详细解释&…