STM32F1的I2C模块协议简介

发布时间:2023-09-13  

I2C是一种多主从的串行通讯协议。STM32F1的I2C模块支持标速(最高100kHz)和高速(最高400kHz)两种工作模式。


一、I2C协议简介

标准的IIC接口有数据线SDA、时钟线SCL两条总线,只能工作于半双工模式,在设计中,对总线的负载电容有一定的要求,具体请查阅元件的技术手册确定。

IIC的通讯时序如图,通讯电平为正逻辑:

图片

※数据发送的起始和终止信号为:SCL为高时,

起始:SDA下降沿 终止:SDA上升沿

※当总线空闲时,SDA和SCL均为高电平,总线需要外接上拉电阻,阻值5-10k。

※每次发送一字节(8bits)信号,MSB高位先发。

二、I2C通讯时序(使用时以具体被控芯片手册为准)

通讯时序(主机发送若干数据):

※主机引脚配置为open Drain,务必不要内部上拉、下拉

***①保持SCL=1,拉低SDA,产生起始信号。

***②拉低SCL,准备发送数据;

***③将数据高位Shift Out(SDA上),随后拉高SCL。在SCL=1期间SDA电平不能变动。

***④将数据依次输出

***⑤输出最后一位数据且SCL变为低电平后,主机接SDA引脚立即变换为高阻输入模式。

⑥主机向SCL输出一个时钟方波,在方波高位检测从机是否将SDA拉低(即发送ACK);若未收到表明发送未成功。

***⑦当主机检测到SDA被拉低时,表明从机准备好接收下一字节数据。随后主机拉高SCL,从机释放SDA,形成终止信号。若错误,主机也拉高SCL并记录错误。此时SCL=1,SDA=1。***

⑧准备下一次传输。

通讯时序(从机接收若干数据):

①从机引脚均配置为输入模式

***②检测开始信号,随后接收数据(可以通过SCL上升、下降沿触发方式检测校验)

③若接收没有出现错误,从机将SDA配置为开漏,在定义的数据长度(数据位+1ACK)的前一个时钟方波之后(时钟下降沿)拉低SDA发出ACK。若接受错误(例如一个时钟信号上升下降沿SDA数据不同)则不下拉。

④检测到SCL出现上升后,释放SDA。

⑤准备下一次传输。

※IIC数据以1个数据包(主机)+1位ACK(从机)格式传送:

图片

发送地址的最后一位是数据方向位(R/W位),该位用“0”表示主机发送数据,“1”表示主机接收数据(R)。

※当STM32做主机时,在发送地址位后(10位地址模式为首序列最后一位)会根据方向位自动判断进入主发送器模式或主接收器模式**。**

三、STM32 LL库IIC驱动

STM32的I2C模块可以配置为从机输出、从机输入、主机输出、主机输入四种模式。

■主模式时,I2C接口启动数据传输并产生时钟信号。串行数据传输总是以起始条件开始并以停止条件结束。起始条件和停止条件都是在主模式下由软件控制产生。

■从模式时,I2C接口能识别它自己的地址(7位或10位)和广播呼叫地址。软件能够控制开启或禁止广播呼叫地址的识别。

※ SCL时钟信号、起始终止信号由主机输出 , 应答始终由从机应答 ;从机由主机发送地址选中(主机和从机的区别)。

1.IIC时钟配置:

在I2C_CR2寄存器中Freq[5:0]设定该模块的输入时钟( APH1旁路时钟输入,最高36MHz )。输入时钟的频率至少为:

● 标准模式下为:2MHz ● 快速模式下为:4MHz

若使用CubeMX进行模块的配置,则生成的模块初始化函数中自动设置

2.相关寄存器

①自身地址寄存器(I2C_OAR1):

图片

图片

图片

STM32的IIC模块支持双地址模式,即 可以设置两个自身地址 :

自身地址寄存器2(I2C_OAR2):

图片

图片

*②时钟控制寄存器(I2C_CCR): * (CubeMX自动配置)

在I2C_CR2中设置完成模块输入时钟后对SCL输出时钟进行配置

图片

图片

图片

③控制寄存器(I2C_CR1)

图片

图片

图片

图片

图片

④控制寄存器(I2C_CR2)

图片

图片

图片

图片

⑤数据寄存器(I2C_DR)

图片

图片

⑥状态寄存器(I2C_SR1)

图片

图片

PEC校验的使用较为复杂,使用时请具体参看手册

图片

图片

图片

图片

图片

图片

对包序号的判断(第几个包?)从起始条件开始计算。

⑦状态寄存器(I2C_SR2)

图片

图片

图片

图片

图片

3.传输时序(请参考传输时序进行开发)

** ①主发送器模式**

※7位地址最后一位为R/W位,10位帧头最后一位为R/W,此时设置为"0",由本机发送

图片

** ②主接收器模式(主模式下起始、终止条件都由本机发出)**

※7位地址最后一位为R/W位,10位帧头最后一位为R/W,此时设置为"1",由本机发送

图片

** ③从接收器模式**

※地址R/W位非本机发送,由硬件自动比对本机地址判断是否被选中。此时R/W位为"0"

图片

** ④从发送器模式**

※地址R/W位非本机发送,由硬件自动比对本机地址判断是否被选中。此时R/W位为"0"

图片

关于主从模式:

*** ■模块默认处于从模式***

*** ■当本机通过START位主动发送起始条件时,进入主模式***

*** ■当主模式最后一字节传输完成后,由本机置STOP位发送停止条件,进入从模式***

*** ■从模式下模块自动检测总线上的电平变化***
*** ■发送/接收模式的选择通过硬件自动判断R/W实现***

■注意发送/接收地址后,读ADDR才能进入主/从模式下一步的数据传输


LL库函数:


1、初始化结构体LL_I2C_InitTypeDef


typedef struct

{

  uint32_t PeripheralMode;/*

  选择模块工作模式,通过LL_I2C_SetMode()实现

  @ref     LL_I2C_MODE_I2C //I2C模式

           LL_I2C_MODE_SMBUS_HOST //

           LL_I2C_MODE_SMBUS_DEVICE //

           LL_I2C_MODE_SMBUS_DEVICE_ARP //

  */

  uint32_t ClockSpeed;/*

  配置时钟频率(< 400kHz(高速);< 100kHz(标准));通过LL_I2C_SetClockPeriod()、LL_I2C_SetDutyCycle()、

  LL_I2C_SetClockSpeedMode()、LL_I2C_ConfigSpeed()实现

    //示例: 若需要100kHz时钟,则输入100000

  */

  uint32_t DutyCycle;/*

  设置高速模式(仅)下信号占空比;通过LL_I2C_SetDutyCycle()实现 

  @ref     LL_I2C_DUTYCYCLE_2 //低:高=2

           LL_I2C_DUTYCYCLE_16_9 //低:高=16:9

 */

  uint32_t OwnAddress1;/*

  设置自身的主地址,通过 LL_I2C_SetOwnAddress1()实现

  //10位模式最大为0x3FF, 7位最大为0x7F

  ※该结构体及模块初始化函数不提供设置第二地址(副地址)的方式

 */

  uint32_t TypeAcknowledge;/*

  配置ACK使能;通过LL_I2C_AcknowledgeNextData()实现

  @ref     LL_I2C_ACK //在接收到一个字节后返回一个应答(匹配的地址或数据)

           LL_I2C_NACK //无应答

  */

  uint32_t OwnAddrSize;/*

  设置自身地址长度;通过LL_I2C_SetOwnAddress1()实现

  ※在双地址模式下只能设置为7位长度

  @ref     LL_I2C_OWNADDRESS1_7BIT //7位长度

           LL_I2C_OWNADDRESS1_10BIT //10位长度

  */

} LL_I2C_InitTypeDef;

2、工作模式设置


void LL_I2C_SetMode(I2C_TypeDef *I2Cx, uint32_t PeripheralMode);/*

设置模块工作模式

@reg       CR1- >SMBUS、SMBTYPE、ENARP

@ref     LL_I2C_MODE_I2C //I2C模式

           LL_I2C_MODE_SMBUS_HOST //

           LL_I2C_MODE_SMBUS_DEVICE //

           LL_I2C_MODE_SMBUS_DEVICE_ARP //

*/

uint32_t LL_I2C_GetMode(I2C_TypeDef *I2Cx);

3、模块开启/关闭函数


void LL_I2C_Enable(I2C_TypeDef *I2Cx);/*

使能(开启)I2C模块

@reg  CR1- >PE

*/

void LL_I2C_Disable(I2C_TypeDef *I2Cx);/*

禁用(关闭)I2C模块

@reg  CR1- >PE

*/

uint32_t LL_I2C_IsEnabled(I2C_TypeDef *I2Cx);/*

检测I2C模块是否开启

@retval: 1//开启

         0//关闭

*/

4.时钟延长控制(ClockStretching)


参考https://blog.csdn.net/happygaohualei/article/details/52864694


通过将SCL线拉低来暂停一个传输.直到释放SCL线为高电平,传输才继续进行。一般情况是从机在发送过程中将SCL接地,主机无法拉高电平后暂停传输,从机处理完成任务后释放SCL,传输继续。 大多数外设不支持时钟延长功能。


※STM32默认允许时钟延长


void LL_I2C_EnableClockStretching(I2C_TypeDef *I2Cx);/*

使能时钟延长。

@reg    CR1- >NOSTRETCH

*/

void LL_I2C_DisableClockStretching(I2C_TypeDef *I2Cx);/*

禁用时钟延长

@reg    CR1- >NOSTRETCH

*/

uint32_t LL_I2C_IsEnabledClockStretching(I2C_TypeDef *I2Cx);/*

检测是否启用时钟延长

@retval     1//启用

*/

5.自身地址设置


地址在从模式下由硬件自动比较


void LL_I2C_SetOwnAddress1(I2C_TypeDef *I2Cx, uint32_t OwnAddress1, uint32_t OwnAddrSize);/*

设置自身主地址,并设置地址模式(7位或10位)

@reg  ADD0    ADD1_7   ADD8_9   ADDMODE 

@param  OWnAddress//自身主地址

        OwnAddrSize//地址模式(7位或10位),@ref    LL_I2C_OWNADDRESS1_7BIT

                                               LL_I2C_OWNADDRESS1_10BIT

※若启用第二地址,设置为7位地址模式

*/

void LL_I2C_EnableOwnAddress2(I2C_TypeDef *I2Cx);/*

双地址模式(启用第二地址),启用后只支持7位地址模式

@reg  OAR2- >ENDUAL

*/

void LL_I2C_SetOwnAddress2(I2C_TypeDef *I2Cx, uint32_t OwnAddress2);/*

设置第二地址(7位)

*/

void LL_I2C_DisableOwnAddress2(I2C_TypeDef *I2Cx);/*

禁用双地址模式

@reg  OAR2- >ENDUAL

*/

6.广播呼叫控制(General Call)


当本机作为从机接收到地址0x00时,将被选中并发ACK(如果使能ACK),0x00即广播地址。


void LL_I2C_EnableGeneralCall(I2C_TypeDef *I2Cx);/*

使能广播呼叫。

@reg    CR1- >ENGC

*/

void LL_I2C_DisableGeneralCall(I2C_TypeDef *I2Cx);/*

禁用广播呼叫.

@reg    CR1- >ENGC

*/

uint32_t LL_I2C_IsEnabledGeneralCall(I2C_TypeDef *I2Cx);/*

检测是否启用了广播呼叫。

@retval  1//启用

*/

7.模块时钟配置


请在模块关闭的状态下配置*

void LL_I2C_SetClockPeriod(I2C_TypeDef *I2Cx, uint32_t ClockPeriod);/*

配置SCL时钟周期;

@reg    CCR- >CCR

@note  具体配置参见MANUAL的CCR寄存器(前有)

*/

uint32_t LL_I2C_GetClockPeriod(I2C_TypeDef *I2Cx);/*

读取CCR- >CCR的值

*/

void LL_I2C_SetClockSpeedMode(I2C_TypeDef *I2Cx, uint32_t ClockSpeedMode);/*

设置速度模式(标准/高速)

@reg    CCR- >FS

@ref      LL_I2C_CLOCK_SPEED_STANDARD_MODE //标准模式(最高100kHz)

          LL_I2C_CLOCK_SPEED_FAST_MODE //高速模式(最高400kHz)

@note  ※高速模式下可设置信号占空比

*/

void LL_I2C_SetPeriphClock(I2C_TypeDef *I2Cx, uint32_t PeriphClock);/*

设置模块的输入时钟(e.g.36Mhz,84Mhz...);单位Hz,函数自动与10MHz对齐;

@reg  CR2- >FREQ

*/

uint32_t LL_I2C_GetPeriphClock(I2C_TypeDef *I2Cx);/*

读取模块的输入时钟(由上一函数设置)

@reg  CR2- >FREQ =@retval

*/

void LL_I2C_SetDutyCycle(I2C_TypeDef *I2Cx, uint32_t DutyCycle);/*

设置信号占空比(※仅高速模式)

@reg            CCR- >DUTY

@ref     LL_I2C_DUTYCYCLE_2 //低:高=2

         LL_I2C_DUTYCYCLE_16_9 //低:高=16:9

*/

uint32_t LL_I2C_GetDutyCycle(I2C_TypeDef *I2Cx);/*

获取信号占空比(仅高速模式);

@reg            CCR- >DUTY

*/

void LL_I2C_SetRiseTime(I2C_TypeDef *I2Cx, uint32_t RiseTime);/*

设置主模式下SCL的最大上升时间。

@reg    TRISE- >TRISE[5:0]

@note 默认值0x02  计算方法请详细参看MANUAL

*/

uint32_t LL_I2C_GetRiseTime(I2C_TypeDef *I2Cx);/*

获取主模式下SCL的最大上升时间。

@retval  =  TRISE[5:0]

*/

时钟配置整合函数(优先使用):


void LL_I2C_ConfigSpeed(I2C_TypeDef I2Cx, uint32_t PeriphClock, uint32_t ClockSpeed,

uint32_t DutyCycle);/

配置输入时钟、时钟周期、占空比(高速模式下)

*/


8.SMbus部分


暂不补充


9.关键控制


①ACK控制(接收时)


void LL_I2C_AcknowledgeNextData(I2C_TypeDef I2Cx, uint32_t TypeAcknowledge);/

配置应答使能(是否接收到一个数据(地址或数据)后返回一个应答)

@reg CR1->ACK

@ref LL_I2C_ACK //返回应答

LL_I2C_NACK //不返回应答

*/


②生成起始条件与终止条件


void LL_I2C_GenerateStartCondition(I2C_TypeDef I2Cx);/

生成起始条件(S),可与SB配合检测起始条件的生成状况

@reg CR1->START

@note 起始条件发送后START位自动清除

*/

void LL_I2C_GenerateStopCondition(I2C_TypeDef I2Cx);/

发送终止条件(P)

@reg CR1->STOP

@note 终止条件发送后STOP位自动清除

*/


③读取/发送操作


uint8_t LL_I2C_ReceiveData8(I2C_TypeDef I2Cx);/

接收8位数据。

读取一次DR,获得8位数据

*/

void LL_I2C_TransmitData8(I2C_TypeDef I2Cx, uint8_t Data);/

发送8位数据。

向DR写入一个字节

*/


I2C中断

(摘自RM008)

图片

图片

从中可以看出,I2C模块的中断掩码非常少,一旦开启可靠性将大大降低,因此一般不使用中断功能

中断总共有两个入口,条件检测、中断配置类似UART和SPI

中断掩码控制:

void LL_I2C_EnableIT_BUF(I2C_TypeDef I2Cx);/
置位ITBUFEN
*/
void LL_I2C_DisableIT_BUF(I2C_TypeDef I2Cx);/
清零ITBUFEN
*/

void LL_I2C_EnableIT_ERR(I2C_TypeDef I2Cx);/
置位ITERREN
*/
void LL_I2C_DisableIT_ERR(I2C_TypeDef I2Cx);/
清零ITERREN
*/

void LL_I2C_EnableIT_EVT(I2C_TypeDef I2Cx);/
置位ITEVTEN
*/
void LL_I2C_DisableIT_EVT(I2C_TypeDef I2Cx);/
清零ITEVTEN
*/

I2C状态判断 ※在软件方式使用I2C时非常重要

读取状态位判断的格式为 LL_I2C_IsActiveFlag_XXX()

使用请参见前面的时序图。

DMA控制

I2C模块同样可以配置DMA传输,这通常使用在主模式下传输大量数据的情况。

但LL库使用DMA时容易发生通讯错误,因此不推荐使用。


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>