STM32基础篇:I2C通信协议
在STM32内部有两个I2C模块(即I2C1、I2C2),挂在APB1总线上。每个I2C模块有三个引脚,分别为:SCL、SDA、SMBA;本文不涉及SMBA引脚的讲述。复用功能Remap=0Remap=1I2C1_SCLPB6PB8I2C1_SDAPB7PB9I2C1_SMBAPB5I2C2_SCLPB10I2C2_SDAPB11I2C2_SMBAPB12。
I2C总线
I2C(IIC---Inter Integrated Circuit 内部集成电路)
以上为I2C大体结构图,其中时钟线SCL用于传输时钟信号,数据线SDA来传输实际的数据。
主机与从机
1.主机的职责
假如由从机1和从机2,从机1想向SDA上发送一个低电平,从机2想向SDA上发送一个高电平,如此同一时刻就会发生冲突。为了避免冲突的发送,必须对总线的使用情况做一个管理。
我们规定:在同一时刻,只允许有一个设备向外去发送数据。此规则由主机负责管理,因此主机相当于I2C总线的管理员。
1、波特率的选择
I2C总线中,由主机产生SCL信号,通过SCL线分配给所有从机。因此主机可以通过控制时钟信号频率来调节波特率(即:控制通信速度)。
2、数据通信的方向
仅又主机可以主动向从机发起数据传输,从机不能主动向主机发送数据,必须等待主机读取从机时,从机才能把准备好的数据发送给主机。
传输方向有:主机-->从机、从机-->主机,不存在从机-->从机。
2.数据接收和发送
1、每个从机都有一个8位的地址,且地址最后一位X的取值代表读(1)或写(0);
2、主机在总线上发送地址后才能与对应的从机通信,且通信开始与结束都由主机决定;
3、当SCL为高电平时,SDA上的数据是不允许变化的,因为SCL在高电平时采集数据(起始、停止除外)。
4、设备的SDA和SCL均配置为开漏输出模式。开漏加弱上拉的模式,同时兼具了输入和输出的功能。开漏模式下,输出高电平就相当于断开引脚,在输入之前,可直接输出高电平,不需要切换输入模式。
3.I2C数据帧格式
空闲:SCL和SDA均为高电平。
起始位:当SCL为高电平时,SDA由1置0;
停止位:当SCL为高电平时,SDA由0置1;
应答ACK:主机每向从机发送一帧数据后,会立刻释放掉SDA占控权,此时SDA为高电平;随后从机立刻发送一个低电平,表示“收到”。同样,主机接收到从机发送的数据后,也会向从机发送ACK,表示接收到了。
I2C模块简介
在STM32内部有两个I2C模块(即I2C1、I2C2),挂在APB1总线上。每个I2C模块有三个引脚,分别为:SCL、SDA、SMBA;本文不涉及SMBA引脚的讲述。
如下为I2C引脚的重映射(C8T6为例):
复用功能 | Remap=0 | Remap=1 |
I2C1_SCL | PB6 | PB8 |
I2C1_SDA | PB7 | PB9 |
I2C1_SMBA | PB5 | |
I2C2_SCL | PB10 | / |
I2C2_SDA | PB11 | / |
I2C2_SMBA | PB12 | / |
寄存器组与内部结构
1.内部结构
如下为I2C内部结构框图:此图只列出寄存器里面一些重要且常用的标志位。
不管是I2C1还是I2C2,这两个片上外设的时钟都来自于PCLK1,顺着时钟往里走,有个SCL控制电路模块,将PCLK1转换为SCL信号,并且通过配置CCR来控制SCL的频率以及形状。
对于SDA,其结构与USART类似,具有双缓冲结构(图中绿色部分)。
2.I2C的初始化
首先将SDA、SCL引脚设置为开漏模式(实现“线与”),然后开启I2C时钟,配置寄存器参数,最后闭合总开关。
3.速度模式
对于I2C的时钟信号,有5种速度(频率)可选择,如下:
速度模式 | 波特率max |
标准模式(Sm) | 100K |
快速模式(Fm) | 400K |
快速增强模式(Fm+) | 1M |
高速模式(HSm) | 3.4M |
超快速模式(UFm) | 5M |
而对于STM32,只有标准模式和快速模式,即波特率最大为400K。
关于占空比的研究
按理来说,同步时序下,SCL的高电平和低电平持续多长时间都应该没问题,那为什么要有占空比的参数呢?
占空比是为了快速传输设计的。对于SCL和SDA,其下降沿变化是非常快的,但是它们的上升沿有一个缓慢上升的过程(此缓慢是相对于下降沿来说),那么缓慢的上升沿会产生什么影响?
我们知道,在I2C通信协议下,SCL上低电平时数据变化、高电平时数据读取。数据变换需要一定时间来翻转(特别是低电平—>高电平),所以在快速传输状态下,需要给低电平多分配一些时间,不然SDA上数据变换来不及。
【注意】在标准模式下(100K及以下),占空比固定为1:1,但在更快的频率下,通常延长低电平持续时间,占空比为16:9或2:1。
监控标志位的方案
1、基本状态监控
使用I2C_CheckEvent()这个函数,同时判断多个或一个标志位,用来确定EVx这个事件是否发生,与下面的时序图对应:
2、高级状态监控
使用I2C_GetLastEvent()函数,直接把SR1和SR2这两个状态寄存器里的标志位拼接成16位的数据,需要自己对这16位的数据进行判断和处理(看得出来并不是很高级)。
一般不使用此函数。
3、基于标志位的监控
使用I2C_GetFlagStatus()函数,可以判断某一个标志位是否置1了。
一些标志位※
BUSY标志位:用于查询总线的空闲状态,0-总线空闲、1-总线忙碌。
START位:用于产生一个起始位,写1-产生起始位、产生后START由硬件自动置0。
STOP位:用于产生一个停止位,写1-产生停止位、写0-无停止位。当STM32作主机接收从机数据时,当发送完NAK信号后,要立刻发送停止位。
SB标志位:用于检测起始位是否发送完成
ADDR标志位:当寻址成功时,ADDR=1;对于ADDR,当我们先读取SR1寄存器,再读取SR2寄存器后,就会清除ADDR(不要问为什么,ST公司就是这么设计的)
AF标志位:AF=1,相当于收到NAK信号;AF=0,相当于收到ACK信号。在使用AF之前,通常要先对其清零。
TxE标志位:1-发送数据寄存器TDR为空、0-TDR里面还有待发送的数据。
RxNE标志位:1-接收数据寄存器RDR非空,0-RDR为空。
BTF标志位:发送数据时:1-TDR和移位寄存器均为空,代表数据发送完成、0-数据未发送完成;接收数据时:1-RDR和移位寄存器均非空、0-相反。
ACK位:将ACK位写1-STM32芯片自动发送出ACK信号,写0-则发送NAK信号。注意,芯片只在正在进入移位寄存器或即将进入移位寄存器的字节后面发送ACK信号。
I2C通信接收数据的一般流程:
I2C通信发生数据的一般流程:
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)