本帖最后由 DKENNY 于 2023-8-10 09:38 编辑
1. 背景
大多数嵌入式系统和单片机都提供了GPIO引脚,而I2C硬件接口可能并不总是可用或可用的GPIO引脚数量有限。通过使用GPIO模拟I2C,可以在没有硬件I2C接口的情况下实现I2C通信。使用软件IIC具有以下优点:
(1) 适应性和灵活性:在某些应用中,可能需要在不同的GPIO引脚上实现I2C通信,以适应特定的硬件布局或连接要求。使用GPIO模拟I2C可以提供更大的灵活性。
(2)自定义时序和速率:对于一些特殊需求的应用,可能需要自定义I2C通信的时序和速率。通过使用GPIO模拟I2C,可以通过软件控制时序和速率,以满足特定的需求。
(3)教育和学习目的:使用GPIO模拟I2C可以帮助学生和初学者更好地理解和学习I2C通信协议。通过手动控制GPIO引脚的状态和时序,他们可以更深入地了解I2C的工作原理。
(4)原型开发和快速迭代:在原型开发和快速迭代阶段,使用GPIO模拟I2C可以更快地验证和测试I2C设备的功能和交互。这样可以加快开发进度并节省成本。
总之,使用GPIO模拟I2C的背景主要涉及硬件限制、适应性、自定义需求、教育学习和原型开发等方面。通过使用GPIO模拟I2C,可以克服硬件限制并提供更大的灵活性和控制能力。
2. IIC简介
IIC是一种短距离通信协议,物理实现上,I2C总线由两根信号线(SDA与SCL)和一根地线组成,两根信号线为双向传输的。 两根信号线,SCL时钟线、SDA数据线。由SCL为SDA提供时序,SDA串行发送/接收数据。 SCL、SDA这两根信号线均为双向。 两个系统使用IIC总线通信时共用同一根地线。 如下图为IIC功能结构图。
iic功能结构图
2.1 IIC协议概述
数据以帧的形式传输,每一帧中由 1 个字节(8 位)组成。 在 SCL 的上升沿阶段,SDA 需要保持稳定,SDA 在 SCL 为低期间作出改变。 除了数据帧,I2C 总线还有起始信号,停止信号,应答信号。 起始位:在 SCL 为稳定的高电平期间,SDA 的一个下降沿启动传输。 停止位:在 SCL 为稳定的高电平期间,SDA 的一个上升沿停止传输。 应答位:用于表示一个字节传输成功。总线发送器(无论主机还是从机), 在发送 8 个位的数据后,SDA 将释放(由输出变为输入),在第九个时钟脉冲期间,接收器将 SDA 拉低,来应答接收到了数据。
I2C通信读写过程
如下为主机写数据至从机图。
主机写数据至从机
如下为主机由从机读取数据图。
主机由从机读取数据
备注:(IIC发送8位命令,最后一位代表读写位) (1)
:此数据由主机传输到从机 (2) S:起始信号 (3) SLAVE ADDRESS:从机地址 (4)
:此数据由从机传输到主机 (5) R/W :传输方向选择位 (6) 1 为读取 (7) 0 为写入 (8) P:停止信号
起始信号产生后,所有从机都将等待主机发送的从机地址信号,I2C 总线中,每个设备的地址都是唯一的,当地址信号与设备地址匹配后,从机将被选中,没被选中的从机将忽略以后的数据信号。
主机方向为写数据时 广播完地址后,接收到应答信号,主机向从机发传输数据,数据长度为一个字节,主机每次发完一个字节数据后,都需等待从机发送的应答信号,当传输的所有字节完成后,主机向从机发送一个停止信号(STOP),表示为传输完成。 主机方向为读数据时 广播完地址后,接收到应答信号,从机开始向主机传输数据,数据包的大小为 8位,从机每发送完一个字节数据,都要等待主机的应答信号,当主机想停止接收数据时,需要向从机返回一个非应答信号,则从机自动停止数据传输。
2.2 IIC时序 I2C在传输数据过程中共3条信号,分别是开始信号,结束信号和应答信号。 2.2.1 IIC开始信号(START) SATRT信号定义为:时钟线SCL保持高电平期间,数据线SDA电平拉低,标志着一次数据传输的开始。启动信号是一种电平跳转的时序信号,而不是一种电平信号。该信号由主设备发出,在建立该信号之前,IIC总线必须处于空闲状态。如下为START时序图。
start时序图
2.2.2 IIC停止信号(STOP) STOP信号定义为:时钟线SCL保持高电平期间,数据线SDA释放,返回高电平,标志着一次数据传输的结束。停止信号也是一种电平跳转的时序信号,而不是一种电平信号。该信号由主设备发出,建立该信号之后,IIC返回空闲状态。如下为STOP时序图。
stop时序图
2.2.3 IIC应答信号(ACK) IIC总线上的所有数据都是以8位字节传送的,IIC通信时,发送器每发送一次数据,接收器都会反馈一个应答信号。 应答信号为低电平时,规定为有效应答(ACK);应答信号为高电平时,规定为非有效应答(NACK)。 反馈有效应答信号的要求:接收器在接收第9个脉冲前,将SDA线拉低,确保当SCL线为高电平时,SDA线输出稳定的低电平。 如果接收器是主设备,则当其收到从设备发出的最后一个字节时,会发送一个NACK信号,以通知从设备停止数据传送,并释放SDA线,以便主设备发送一个停止信号。如下为ACK和NACK时序图。
ack时序图
3. AT24C02模块 AT24C02是一款串行EEPROM(Electrically Erasable Programmable Read-Only Memory)芯片,由Atmel(现在是Microchip Technology)公司生产。它是AT24C系列芯片中的一员,具有2K位(256字节)的存储容量。 如下是AT24C02的性能特点。 (1)采用I2C(Inter-Integrated Circuit)总线接口,这是一种常用的串行通信协议,可以在多个设备之间进行数据传输。它支持标准模式(100 KHz)和快速模式 (400 KHz)的I2C通信速率。 (2)具有可擦写和可编程的功能,可以通过电源供电进行数据的读取和写入。它采用8位地址寻址,可以连接多个AT24C02芯片,使得系统能够扩展更大的存储容量。 (3)数据存储是非易失性的,即使在断电情况下,数据仍然可以保持。它还具有内部写保护功能,可以通过硬件或软件方式来保护存储的数据,防止误写或擦除。 (4)广泛应用于各种电子设备中,例如存储配置信息、校准数据、序列号、日志记录等。由于其容量适中、接口简单、低功耗等特点,它在嵌入式系统和小型电子设备中得到了广泛应用。总体而言,AT24C02芯片具有较小的存储容量、简单的接口、良好的可靠性和低功耗等特点,适用于许多嵌入式系统和小型电子设备中的数据存储需求。 如下为AT24C02的通信时序图。
at24c02模块通信时序图
4.硬件设计 本次设计使用APM32F103的PB6、PB7引脚进行GPIO模拟IIC,将AT24C02的SCL和SDA分别连接在APM32F103的PB6、PB7上,连接关系如图所示。
iic接线连接图
5.软件设计 本章主要介绍GPIO模拟IIC所实现的代码,以及APM32F103使用软件IIC与AT24C02通信。其工作流程图如下所示。
at24c02通信流程图
5.1 SDA_IN_OUT - //SDA设置为输入模式
- void SDA_IN(void)
- {
- GPIOB->CFGLOW &= 0X0FFFFFFF;
- GPIOB->CFGLOW |= (uint32_t)8<<28;
- }
- //SDA设置为输出模式
- void SDA_OUT(void)
- {
- GPIOB->CFGLOW &= 0X0FFFFFFF;
- GPIOB->CFGLOW |= (uint32_t)3<<28;
- }
参照APM32F103用户手册关于CFGLOW寄存器的说明,SDA_IN()函数将GPIOB中的CFGLOW寄存器的高4位配置成了“1000”,对应设置PB7引脚为输入模式;SDA_OUT()函数将GPIOB中的CFGLOW寄存器高4位配置成了“0011”,对应PB7引脚为推挽输出模式。
5.2 IIC_Init
- //PB6(SCL)、PB7(SDA)初始化
- void IIC_Init(void)
- {
- GPIO_Config_T gpioConfig;
- RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOB);
- gpioConfig.pin = IIC_PIN_SCL|IIC_PIN_SDA;
- gpioConfig.mode = GPIO_MODE_OUT_PP ; //推挽输出
- gpioConfig.speed = GPIO_SPEED_50MHz;
- GPIO_Config(GPIOB, &gpioConfig);
- GPIO_SetBit(GPIOB,IIC_PIN_SCL|IIC_PIN_SDA);
- }
IIC_Init()函数配置了GPIOB的时钟,将PB6(SCL)、PB7(SDA)配置成了推挽输出模式,由于IIC时序开始时为高电平,故将PB6、PB7默认置为高电平。
5.3 IIC_Start
- //IIC 开始时序
- void IIC_Start(void)
- {
- SDA_OUT(); //SDA输出
- IIC_SDA_SET;
- IIC_SCL_SET;
- Delay_us(4);
- IIC_SDA_RESET; //START:当CLK为高电平时,DATA从高电平变为低电平
- Delay_us(4);
- IIC_SCL_RESET; //钳住I2C总线,准备发送或接收数据
- }
根据IIC开始时序(START)图,当SCL线为稳定的高电平时,将SDA线拉低代表IIC时序的开始,故先将IIC_SDA_RESET,延时一段时间后,再将IIC_SCL_RESET,即可模拟IIC的START时序。
5.4 IIC_Stop
- //IIC 停止时序
- void IIC_Stop(void)
- {
- SDA_OUT(); //SDA线输出
- IIC_SCL_RESET;
- IIC_SDA_RESET; //STOP:当CLK为高电平时,DATA从低电平变为高电平
- Delay_us(4);
- IIC_SCL_SET;
- IIC_SDA_SET; //发送I2C总线结束信号
- Delay_us(4);
- }
根据IIC停止时序(STOP)图,当SCL线为稳定的高电平时,将SDA线拉高代表IIC时序的停止,故先将IIC_SCL_SET,再将 IIC_SDA_SET,即可模拟IIC的STOP时序。
5.5 IIC_Wait_Ack
|