STM32的I2C通信

来源:互联网 发布:淘宝购物后怎么评价 编辑:程序博客网 时间:2024/06/05 14:53

  STM32的两个GPIO引脚,分别用于SCL和SDA,按照I2C规约的时序,像控制LED灯那样控制引脚输出,若是接收数据时则读取SDA线上的电平,那就可以实现I2C通信了,这也是我们在51单片机上的“软件模拟协议”做法。但是STM32上还配有I2C控制器片上外设,只要配置好该外设,它就可以依据规约产生通讯信号。收/发数据置于缓存寄存器中,cpu只要检测该外设的状态和数据寄存器就能完成数据收发。但是利用该外设来实现I2C通讯,存在许多硬件Bug,下来还是简单讲解这种做法。

1. I2C通讯时序

  通俗来讲,IIC的时序就是主机向从设备发出一个数据后,要间隔多少时间从机才会回复,或者说SCL上的信号要维持多久的高电平、低电平才使得SDA的信号正确传输到从机等,这些是在I2C协议明确规约的,在51单片机软件模拟IIC时序时,编程中我们需要自己实现函数去延时。在STM32的I2C控制器下的IIC时序将不需要这么繁琐。如何实现?看下面摘自《STM32中文参考手册_V10.pdf》I2C章节的两图(STM32系统既可以当IIC主机也可以当IIC从机,以I2C主机模式为例)。

主机发送:
这里写图片描述
(1) 主机端代码控制IIC控制器产生起始信号(S),当发生起始信号后,控制器产生事件“EV5”,并会对SR1寄存器的“SB”位置1,表示起始信号已经发送。
(2) 紧接着发送设备地址,然后等待从机的应答信号,若从机有回答,控制器将产生“EV6”及“EV8”
(3) I2C外设通过SDA信号线将数据一位一位发送出去,一字节数据发送完毕后,控制器将会产生“EV8”,重复此过程可以发送多个字节数据
(4) 发送完所有数据后,代码控制IIC控制器产生结束信号(P),控制器将会产生“EV8_2”事件,表示通讯结束。

假设我们使能了I2C中断,以上所有事件都可以产生I2C中断信号,进入同一个中断处理函数,在该函数中通过访问对应寄存器判断是哪一事件。

主机接收:
这里写图片描述
(1) 主机端代码控制IIC控制器产生起始信号(S),当发生起始信号后,控制器产生事件“EV5”,并会对SR1寄存器的“SB”位置1,表示起始信号已经发送。
(2) 紧接着发送设备地址,然后等待从机的应答信号,若从机有回答,控制器将产生“EV6”
(3) 从机向主机端发送数据,当主机接收到数据后,会产生“EV7”事件。接下来若要继续接收数据则发出应答信号ACK,若发出非应答信号(NACK)则停止传输
(4) 主机端发送非应答信号,产生停止信号,传输结束

利用标准库函数I2C_CheckEvent()可以检测EV5事件的发生与否,如:

I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT); //I2C_EVENT_MASTER_MODE_SELECT表EV5

2.I2C初始化描述结构体

I2C初始化描述结构体:typedef struct{  uint32_t I2C_ClockSpeed;         /* 设置SCL线上的时钟频率,此值不可高于400000 */  uint16_t I2C_Mode;               /* 指定工作模式,I2C模式或者SMBUS模式可选 */  uint16_t I2C_DutyCycle;          /* 时钟占空比,即高电平时间/低电平时间 */  uint16_t I2C_OwnAddress1;        /* 指定I2C自身设备的地址 */  uint16_t I2C_Ack;                /* 应答使能或关闭,一般为使能 */  uint16_t I2C_AcknowledgedAddress;/* 指定地址长度,7位/10位可选 */}I2C_InitTypeDef;

(1) I2C_ClockSpeed:设置I2C的数据传输速率,此数值不得高于400000
(2) I2C_Mode:STM32的I2C外设可用于I2C通讯的主机/从机,还可用于SMBus协议通讯使用。此值取值可为:

I2C_Mode_I2C:I2C模式,I2C模式不需要指定主从机。I2C_Mode_SMBusHost:SMBus主模式I2C_Mode_SMBusDevice:SMBus从模式

(3) I2C_DutyCycle:指定SCL的占空比,即高电平时间/低电平时间,取值可为I2C_DutyCycle_2或者I2C_DutyCycle_16_9。对此值要求并不严格,可任意选择。
(4) I2C_OwnAddress1:配置I2C设备自身的地址,挂接在I2C总线上的设备,包括主机,都有自己的地址。STM32的I2C外设可同时使用两个地址,即对两个地址都作出反应。这里设置的是第一个地址,第二个地址通过函数I2C_OwnAddress2Config()设置。
(5) I2C_Ack:是否发送响应信号,可设置为使能2C_Ack_Enable或者非使能2C_Ack_Enable,一般I2C通讯都使用使能。
(6) I2C_AcknowledgedAddress:设置I2C的寻址模式,可设置为7位(I2C_AcknowledgedAddress_7bit)或者10位(I2C_AcknowledgedAddress_10bit),若要使用10位寻址模式,需要将此值设置为I2C_AcknowledgedAddress,I2C_OwnAddress1才是有效的10位地址。

配置好这个结构体,通过函数I2C_Init()设置到实际控制器中。

3. I2C通讯引脚

STM32F10x中是有两个I2C外设的,分别为I2C1和I2C2。但是我在手上的《STM32中文参考手册_V10.pdf》中看到的只是I2C1的SCL和SDA引脚设置:
这里写图片描述
在正点原子MiniSTM32开发板的原理图看到,确实存在I2C2,I2C2的SCL和SDA分别是PB10和PB11。
这里写图片描述

  以上只是了解一下标准库对STM32的硬件I2C的封装。因为硬件I2C这种方式的不稳定,所以详细的编码就不再记录。在STM32上实现I2C通讯,个人觉得还是采用在学习51单片机的时候估计大部分人都折腾过,用软件模拟I2C时序的方法,虽然貌似复杂度增加,但是比较稳定,下来有时间再折腾并记录。