STM32学习(十)
I2C模块内部结构
I2C(Inter-Integrated Circuit)模块是一种由Philips公司开发的二线式串行总线协议,用于短距离通信,允许多个设备共享相同的总线。
- 硬件连接简单:I2C通信仅需要两条总线,即SCL(时钟线)和SDA(数据线),大大简化了系统的硬件设计12。
- 支持多设备共享:在I2C总线中,可以挂载多个从设备,每个设备都有一个唯一的地址,主设备通过广播地址的方式与从设备进行通信25。
- 传输速率灵活:I2C总线传输模式具有向下兼容性,传输速率在标准模式下可达100kbps,快速模式下可达400kbps,高速模式下更是可达3.4Mbps34。
引脚初始化
引脚映射表
引脚实现代码
void My_I2C_Init(){
//对I2C进行重映射RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);GPIO_PinRemapConfig(GPIO_Remap_I2C1,ENABLE);
//对PB8和PB9进行初始化RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;GPIO_Init(GPIOB,&GPIO_InitStruct)
}
连接电路
波特率
I2C的波特率指的是I2C总线上的数据传输速率,它可以根据不同的模式达到不同的速率。具体来说:
- 在标准模式下,I2C的波特率为100kHz12。
- 在快速模式下,I2C的波特率可以达到400kHz12。
- 还有一些更高速的模式,如快速模式+,波特率可以达到1MHz1。
I2C总线中的波特率由主机控制,主机通过产生SCL(时钟线)信号来分配给所有从机,因此主机可以通过控制时钟信号频率来调节波特率,即控制通信速度。这种灵活性使得I2C总线能够适应不同的通信需求和应用场景。
占空比
在I2C总线通信中,占空比是指数据线(SDA)上的高电平持续时间与整个时钟周期(由时钟线SCL控制)的比例。这个比例决定了数据传输的稳定性和可靠性12。
在没有明确的情况下我们选择2/1的占空比
初始化I2C模块代码
void My_I2C_Init(){
//对I2C进行重映射RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);GPIO_PinRemapConfig(GPIO_Remap_I2C1,ENABLE);
//对PB8和PB9进行初始化RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;GPIO_Init(GPIOB,&GPIO_InitStruct);RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);//开启I2C的时钟RCC_APB1PeriphResetCmd(RCC_APB1Periph_CAN1,ENABLE);//施加复位信号RCC_APB1PeriphResetCmd(RCC_APB1Periph_CAN1,DISABLE);//释放复位信号I2C_InitTypeDef I2C_InitStruct;I2C_InitStruct.I2C_ClockSpeed = 400000;//波特率400kI2C_InitStruct.I2C_Mode = I2C_Mode_I2C;//标准的I2CI2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;//占空比2:1I2C_Init(I2C1,&I2C_InitStruct);I2C_Cmd(I2C1,ENABLE);//闭合I2C1的总开关
}
写数据
数据发送的流程
主设备向从设备发送数据
- 发送起始信号:主设备在SCL(时钟线)为高电平时,将SDA(数据线)从高拉低,产生起始信号,通知所有从设备准备接收数据。
- 发送设备地址:主设备紧接着发送从设备的7位地址,以及一个写信号(通常是低电平),指示这是一个写操作。
- 等待从设备响应:从设备监测到自己的地址后,通过在下一个时钟周期拉低SDA线(发送ACK)来响应,确认它准备好了接收数据。
- 发送数据:主设备开始发送数据,每个字节数据后会跟着等待接收来自从设备的响应(ACK)。从设备在接收到每个字节后,都会发送一个ACK信号来确认。
- 发送停止信号:数据发送完毕后,主设备发送停止信号(SCL高时SDA从低变高),终止传输。
从设备向主设备发送数据
- 主设备初始化读取操作:主设备发送起始信号,然后发送从设备的地址以及一个读取位(通常是高电平),指示这是一个读取操作。
- 从设备响应:从设备监测到自己的地址后,通过发送ACK信号来响应。
- 主设备发送重复开始信号或停止信号:如果主设备计划在同一事务中连续读取多个从设备或进行连续读取,它可以发送重复开始信号来保持总线控制权。如果仅从当前从设备读取且读取操作即将结束,主设备在收到从设备的ACK后可直接发送停止信号。
- 从设备发送数据:在收到读取命令后,从设备开始发送数据。主设备在接收到每个字节后,都会发送一个ACK信号来确认。当接收到最后一个数据字节后,主设备可能会发送一个无效响应(NACK),然后发送停止信号来终止传输。
等待总线空闲
发送数据前要监控总线是否繁忙,从BUSY标志位来判断总线是否空闲,I2C_GetFlagStatus函数用来获取BUSY标志。I2C_GetFlagStatus
函数是一个在 STM32 微控制器的 I2C(Inter-Integrated Circuit)库函数中常用的函数,用于检查 I2C 接口的状态标志。这个函数通常用于轮询(polling)方式,以确定 I2C 总线上的特定事件或状态是否已经发生,例如数据传输完成、接收到起始信号、检测到错误等。
FlagStatus I2C_GetFlagStatus(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG);
I2Cx
:指向要检查的 I2C 接口的指针。例如,对于 STM32F103 系列,可能是I2C1
或I2C2
。I2C_FLAG
:要检查的特定 I2C 状态标志。这些标志在 STM32 的 I2C 库头文件中定义,通常是以I2C_FLAG_
开头的宏。- 返回值是
FlagStatus
枚举类型,它通常有两个可能的值:SET
(标志已设置)和RESET
(标志未设置)。
发送起始位
发送起始位是向START寄存器内写数值1,使用函数I2C_GenerateStart完成。
I2C_GenerateStart
函数是用于生成 I2C 通信起始条件(START condition)的函数。在 I2C 通信中,起始条件是一个重要的信号,用于通知所有连接到总线的设备即将开始数据传输。当 NewState
参数为 ENABLE
时,I2C_GenerateStart
函数会设置相应的寄存器位,从而在 I2C 总线上生成一个起始条件。起始条件是一个在 SCL(时钟线)为高电平时,SDA(数据线)由高电平变为低电平的边沿。这个边沿会被所有连接到总线的 I2C 设备检测到,并通知它们即将开始数据传输。
void I2C_GenerateSTART(I2C_TypeDef* I2Cx, FunctionalState NewState);
I2Cx
:指向要操作的 I2C 接口的指针。在 STM32 微控制器中,这通常是I2C1
、I2C2
等。NewState
:这是一个FunctionalState
枚举类型的值,用于指定是否生成起始条件。它可以是ENABLE
(生成起始条件)或DISABLE
(不生成起始条件)。
在发送起止位后我们需要确定起止位是否发送完毕,我们通过SB标志来判断。
while(I2C_GetFlagStatus(I2Cx,I2C_FLAG_SB) == RESET);
发送地址
AF标志位是ACK应答标志位,当AF为1时ACK答应失败未收到答应,ADDR寻址成功标志位,当寻址成功值为1,失败值为0。在发送地址前我们需要清理AF标志位的值然后发送地址。
I2C_ClearFlag(I2Cx,I2C_FLAG_AF);//清除AF
I2C_SendData(I2Cx,Addr & 0xfe);//发送地址和RW
在发送的过程中需要持续判断AF和ADDR标识符的状态
while(1){if(I2C_GetFlagStatus(I2Cx,I2C_FLAG_ADDR) == SET){break;}if(I2C_GetFlagStatus(I2Cx,I2C_FLAG_AF) == SET){I2C_GenerateSTOP(I2Cx,ENABLE);return -1;}
}
后续我们继续清除ADDR状态标示符
I2C_ReadRegister(I2Cx,I2C_Register_SR1);
I2C_ReadRegister(I2Cx,I2C_Register_SR2);
发送数据
发送数据过程中我们要持续监控ACK和发送数据寄存器的状态,AF为1标示为响应ACK,停止发送数据,BTF负责监控发送数据寄存器内是否有数据,保证在其空的情况下推送数据进入。
发送停止位
代码
int main(){My_I2C_Init();uint8_t commands[] = {0x00,0x8d,0x14,0xaf,0xa5};My_I2C_SendBytes(I2C1,0x78,commands,5);
}void My_I2C_Init(){
//对I2C进行重映射RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);GPIO_PinRemapConfig(GPIO_Remap_I2C1,ENABLE);
//对PB8和PB9进行初始化RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;GPIO_Init(GPIOB,&GPIO_InitStruct);RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);//开启I2C的时钟RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,ENABLE);//施加复位信号RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,DISABLE);//释放复位信号I2C_InitTypeDef I2C_InitStruct;I2C_InitStruct.I2C_ClockSpeed = 400000;//波特率400kI2C_InitStruct.I2C_Mode = I2C_Mode_I2C;//标准的I2CI2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;//占空比2:1I2C_Init(I2C1,&I2C_InitStruct);I2C_Cmd(I2C1,ENABLE);//闭合I2C1的总开关
}int My_I2C_SendBytes(I2C_TypeDef *I2Cx,uint8_t Addr,uint8_t *pData,uint16_t Size){//等待总线空闲while(I2C_GetFlagStatus(I2Cx,I2C_FLAG_BUSY) == SET){}//发送起止位I2C_GenerateSTART(I2C1,ENABLE);//确定起止位是否发送完毕 while(I2C_GetFlagStatus(I2Cx,I2C_FLAG_SB) == RESET){}//发送地址//清除AFI2C_ClearFlag(I2Cx,I2C_FLAG_AF);I2C_SendData(I2Cx,Addr & 0xfe);while(1){if(I2C_GetFlagStatus(I2Cx,I2C_FLAG_ADDR) == SET){break;}if(I2C_GetFlagStatus(I2Cx,I2C_FLAG_AF) == SET){I2C_GenerateSTOP(I2Cx,ENABLE);return -1;//寻址失败}}//清除ADDRI2C_ReadRegister(I2Cx,I2C_Register_SR1);I2C_ReadRegister(I2Cx,I2C_Register_SR2);//发送数据 for(uint8_t i = 0;i<Size;i++){while(1){if(I2C_GetFlagStatus(I2Cx,I2C_FLAG_AF) == SET){I2C_GenerateSTOP(I2Cx,ENABLE);return -2;}if(I2C_GetFlagStatus(I2Cx,I2C_FLAG_TXE) == SET){break;}}I2C_SendData(I2Cx,pData[i]);}while(1){if(I2C_GetFlagStatus(I2Cx,I2C_FLAG_AF) == SET){I2C_GenerateSTOP(I2Cx,ENABLE);return -2;}if(I2C_GetFlagStatus(I2Cx,I2C_FLAG_BTF) == SET){break;}}//发送停止位I2C_GenerateSTOP(I2Cx,ENABLE);return 0;
}
相关文章:

STM32学习(十)
I2C模块内部结构 I2C(Inter-Integrated Circuit)模块是一种由Philips公司开发的二线式串行总线协议,用于短距离通信,允许多个设备共享相同的总线。 硬件连接简单:I2C通信仅需要两条总线,即SCL&…...

进阶篇-Day17:JAVA的日志、枚举、类加载器、反射等介绍】
目录 1、日志1.1 日志概念1.2 日志框架(1) Logback框架:(2)配置文件介绍: 2、枚举3、类加载器3.1 类加载器的介绍3.2 类加载器的加载过程:加载、链接、初始化3.3 类加载器的分类3.4 双亲委派模式…...

Java设计模式 —— 【行为型模式】责任链模式(Chain-of-responsibility Pattern) 详解
文章目录 模式介绍优缺点适用场景模式结构案例实现 模式介绍 责任链模式又名职责链模式,它是一种对象行为的设计模式,为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链&…...
C++和Python中负数取余结果的区别
C中的负数取余规则(取模%)规则 在C中,取余运算( % )的结果符号与被除数相同。从数学定义角度看,C遵循的是尽量让商向零取整的规则。例如计算 -7/3,商是 -2 (向零取整)&a…...

rust学习——环境搭建
rust安装:https://kaisery.github.io/trpl-zh-cn/ch01-01-installation.html 1、vscode装插件: toml语法支持 依赖管理 rust语法支持 2、创建demo 3、查看目录 4、执行文件的几种方式: rust安装:https://www.rust-lang.org/z…...

Linux系统中解决端口占用问题
在日常的 Linux 系统管理和开发过程中,端口占用是一个常见且令人头疼的问题。无论是部署新服务、调试应用程序,还是进行系统维护,遇到端口被占用都可能导致服务无法正常启动或运行。本文将详细介绍在 Linux 系统中如何识别和解决端口占用问题…...
现代软件架构设计:14个质量属性的定义、权衡与最佳实践
1. 引言 1.1 技术架构的重要性 技术架构是指导软件系统设计和开发的核心,它定义了系统的高层结构及关键技术选型。一个优秀的技术架构可以提高开发效率、系统稳定性和扩展能力,确保项目成功落地。面对复杂业务场景,技术架构的设计至关重要&…...

【UE5 C++课程系列笔记】25——多线程基础——FGraphEventRef的简单使用
目录 概念 使用示例1 使用示例2 概念 FGraphEventRef 本质上是对一个异步任务或者一组相关异步任务在虚幻引擎任务图系统中的一种引用(reference)。虚幻引擎的任务图系统用于高效地调度和管理各种异步任务,协调它们的执行顺序以及处理任务…...
计算机网络之---信号与编码
信号 在物理层,信号是用来传输比特流的物理量,它可以是电压、电流、光强度等形式,通常通过电缆、光纤或者无线信道等媒介传播。 信号主要分为以下两种类型: 模拟信号(Analog Signal):信号在时间…...
linux下用命令行给串口写数据和读数据
在 Linux 系统中,串口设备(如 /dev/ttyS3)可以通过命令行进行读写操作。您遇到的问题是因为 Bash 解释了命令行中的字符串 “dis vlan\n”,但并没有按预期向串口设备发送数据。你应该将数据通过重定向发送到串口设备。 下面是如何…...
【生物信息】如何使用 h5py 读取 HDF5 格式文件中的数据并将其转换为 NumPy 数组
data_mat h5py.File(args.data_file) x1 np.array(data_mat[X1]) x2 np.array(data_mat[X2]) if not args.no_labels: y np.array(data_mat[Y]) data_mat.close() 这段代码展示了如何使用 h5py 读取 HDF5 格式文件中的数据并将其转换为 NumPy 数组。以下是代码的详细解释&a…...

纯手工(不基于maven的pom.xml、Web容器)连接MySQL数据库的详细过程(Java Web学习笔记)
1 引言 最近读一些Java Web开发类的书籍时,发现书中的连接数据库的过程缺少了一些关键性的过程,这对初学者非常不友好。为此,本文将给出详细的连接MySQL数据库的过程,并且是纯手工,不依赖于pom.xml和Web容器ÿ…...

thingsboard通过mqtt设备连接及数据交互---记录一次问题--1883端口没开,到服务器控制面板中打开安全组1883端口
1,链接不上:原因是1883端口没开,到服务器控制面板中打开安全组1883端口 2,参考链接: https://blog.csdn.net/bujingyun8/article/details/120024788...
联邦学习中的LoRA:FedLoRA
联邦学习中的LoRA:FedLoRA 联邦学习中的LoRA(Low-Rank Adaptation of Large Language Models)是一种用于在联邦学习场景下对大型语言模型进行低秩适应和高效微调的方法。以下是其原理及示例说明: 原理 低秩矩阵分解:在联邦学习中,通常会涉及到对预训练的大型模型进行微…...
PyTorch reshape函数介绍
torch.reshape 是 PyTorch 用于改变张量形状的函数之一。它不会改变张量的数据,而是重新组织其元素以适应新的形状。 reshape 的使用 torch.reshape(input, shape) → Tensorinput:输入张量。shape:新形状,使用整数或 -1 指定各维…...
Linux内核 -- 邮箱子系统之`mbox_controller` 的 `txdone_irq` 用法
Linux Kernel 中 mbox_controller 的 txdone_irq 用法 1. txdone_irq 的作用 txdone_irq 是一个布尔类型字段,用来指示邮件框控制器是否支持通过中断通知传输完成事件。 如果设置为 true: 硬件会在数据传输完成后生成中断。内核中相应的中断处理程序会…...

Linux/Ubuntu/银河麒麟 arm64 飞腾FT2000 下使用 arm64版本 linuxdeployqt 打包Qt程序
文章目录 一、前言二、环境三、准备1、下载Linuxdeployqt源码2、下载Appimagetool-aarch64.AppImage四、编译linuxdeployqt1.配置环境变量2.编译linuxdeployqt五、安装patchelf六、配置Appimagetool七、打包Qt程序重要提示:测试启动应用八、其他九、最后一、前言 因为项目需要…...

Excel | 空格分隔的行怎么导入excel?
准备工作:windows,一个记事本程序和微软的Excel软件。 打开记事本,选中所有内容,按CtrlA全选,然后复制(CtrlC)。 在Excel中,定位到你想粘贴的单元格,按CtrlV进行粘贴。粘贴后,你会在…...
如何将某两个提交去掉父提交的合并
q: 在一个两个月前的分支,我想保持纯净,但是需要把另一个变化很大的分支只将某两个提交的变更同步过来,基于idea的git操作该怎么做 a: 其实很多人会一下想到cherry pick,这个确实方便,但是会将父提交连带合…...
Windows下安装最新版的OpenSSL,并解决OpenSSL不是当前版本的问题,或者安装不正确的问题
文章目录 1. 文章引言1.1 需求描述1.2 简单介绍1.3 支持平台1.4 源码地址1.5 组件介绍2. 下载OpenSSL3. 安装OpenSSL5. 查看安装目录6. 解决OpenSSL的错误1. 文章引言 1.1 需求描述 今天接到一需求,解密php加密后的数据,由于php使用 openssl_encrypt的方式加密,java也需要使…...

stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...