IIC 总线协议

IIC 简介

​ IIC 总线是Philips (飞利浦)公司在八十年代初推出的一种串行、半双工总线主要用于近距离、低俗的芯片之间的通信;IIC 总线有两根双向的信号线,一根数据线SDA 用于收发数据,一根时钟线SCL 用于通信双方时钟的同步;IIC 总线硬件结构简单,成本较低,因此在各个领域得到了广泛的应用。
在这里插入图片描述

IIC 总线的特点

IIC 总线是一种多主机总线,连接在IIC 总线上的器件分为主机和从机。主机有权发起和结束一次通信,而从机只能被主机呼叫当总线上有多个主机同时启用总线时,IIC 也具备冲突检测仲裁的功能来防止错误产生每个连接到IIC 总线上的器件都有一个唯一的地址(7bit),且每个器件都可以作为主机也可以作为从机(同一时刻只能有一个主机),总线上的器件增加和删除不影响其他器件正常工作;IIC 总线在通信时总线上发送数据的器件为发送器,接收数据的器件为接收器。

IIC 总线的通信过程

宏观上,IIC 总线通信的流程:

  1. 主机发送起始信号启用总线;
  2. 主机发送一个字节数据指明从机地址和后续字节的传送方向;
  3. 被寻址的从机发送应答信号回应主机;
  4. 发送器发送一个字节数据;
  5. 接收器发送应答信号回应发送器;
  6. 循环4、5步骤;
  7. 通信完成后主机发送停止信号释放总线;

例如:下图中,单片机A 发送了起始信号,所有的设备包括单片机B 都可以接收到该起始信号。那么从此刻起,总线就被单片机A 占用了。

接下来单片机A发送一个字节的数据,这个字节里面包含了从机的地址(假设为日历时钟的地址),日历时钟就能知道主机要与自己进行通信。
在这里插入图片描述
该字节的一共有8bit,前7bit 用于指明地址,最后一个1bit 用于指明通信的方向(读写位),即主机给从机发数据,还是从机给主机发数据。

如下图所示:R/W 为“0”表示主机(发送器)发数据给从机(接收器),为“1”表从机(发送器)发数据给主机(接收器)。
在这里插入图片描述
从机(日历时钟)接收到该字节后,需要向主机回复一个应答信号,这样主机才能确定从机已经接收到了前面发送的那个字节。

确认好主从机之后,主从机就可以通过总线进行数据传输了。

通信结束后,主机会向总线上发送一个停止信号,其它设备就可以知道总线已经被释放。这样其它设备就可以启用总线了,而从机接收到该信号,也能知道主机已经结束通信。

IIC 总线寻址方式

IIC 总线上传送的数据是广义的,即包括地址,又包括真正的数据;

主机在发送起始信号后必须先发送一个字节的数据,该数据的高7位为从机地址,最低位表示后续字节的传送方向,“0” 表示主机发送数据,“1” 表示主机接收数据;

总线上所有的从机接收到该字节数据后都将这7位地址与字节的地址进行比较,如果相同,则认为自己被主机寻址,然后再根据第8位将自己定位发送器或接收器。
在这里插入图片描述

IIC 总线的时序

起始信号和停止信号

在这里插入图片描述
起始信号:SCL 为高电平时,SDA 由高变低表示起始信号

停止信号:SCL 为高电平时,SDA 由低变高表示停止信号

起始信号和停止信号都是由主机发出,起始信号产生后总线处于占用状态;停止信号产生后总线处于空闲状态。

字节传送与应答

在这里插入图片描述
IIC总线通信时,每个字节的宽度为8位长度,数据传送时,先传送最高位,后传送低位。发送器发送完一个字节数据后,接收器必须发送1位的应答来回应发送器,即一帧共有9位。
在这里插入图片描述
当发送器发送完一个字节后,接收器需要进行应答,如上图的SDA的第九个时钟处,当SDA为低电平时表示接收器应答,为高电平时表示接收器非应答。

同步信号

​ IIC 总线在进行数据传送时,时钟线SCL 为低电平期间发送器向数据发送一位数据,在此期间数据线上的信号允许发送变化,时钟线SCL 为高电平期间接收器从数据线上读取一位数据,在此期间数据线上的信号不允许发送变化,必须保持稳定。
在这里插入图片描述
SCL 为低电平,发送器发送数据的时期;SCL 为高电平,接收器接收数据的时期;

典型的IIC 时序

主机向从机发数据:

在这里插入图片描述
过程:

  1. 主机发送一个起始信号;

  2. 主机紧接着发送一个从机地址,并且读写位为0;

  3. 从机进行应答;

  4. 接着主机发数据,从机应答,重复该过程。直到主机不打算再发数据,或者从机不打算再接收数据;

  5. 若主机不打算发送数据,则会在发送完最后一个字节后,发送一个停止位;

    若从机不打算接收数据,则会在接收到最后一个字节后不进行响应,稍后由主机发送停止位进行结束。

从机向主机发数据:

在这里插入图片描述
过程:

  1. 主机发送一个起始信号;
  2. 主机紧接着发送一个从机地址,并且读写位为1;
  3. 从机进行应答;
  4. 接着从机发数据,主机应答,重复该过程。直到主机不打算再接收数据;
  5. 主机则会在接收到最后一个字节后不进行响应,并发送停止位进行结束;

主机先向从机发,从机再向主机发:

在这里插入图片描述
过程:

  1. 主机发送一个起始信号;
  2. 主机紧接着发送一个从机地址,并且读写位为0;
  3. 从机进行应答;
  4. 接着主机发数据,从机应答,重复该过程。直到数据传输完成;
  5. 主机重新发送一个起始信号;
  6. 主机紧接着再发送一个从机地址,并且读写位为1;
  7. 从机进行应答;
  8. 接着从机发数据,主机应答,重复该过程。直到数据传输完成;
  9. 主机发送停止信号,结束通信;

注意:阴影部分表示数据由主机向从机传送,无阴影部分表示从机向主机传送;A表示应答,nA表示非应答,S表示起始位,P表示停止位;

IIC 总线的代码实现

初始化

void IIC_init()       //IIC初始化
{
       SCL = 1;		// 首先把时钟线拉高
       delay_us(4);	// 延时函数
       SDA = 1;		// 在SCL为高的情况下把SDA拉高
       delay_us(4); // 延时函数
}

起始信号

在这里插入图片描述

// 产生IIC起始信号
// 1.先拉高SDA,再拉高SCL,空闲状态
// 2.拉低SDA
void IIC_Start()         //启动信号
{
       SDA = 1;		// 确保SDA线为高电平
       delay_us(5);
       SCL = 1;		// 确保SCL高电平
       delay_us(5);
       SDA = 0;		// 在SCL为高时拉低SDA线,即为起始信号
       delay_us(5);
       SCL = 0;		// 钳住I2C总线,准备发送或接收数据 
}

停止信号

在这里插入图片描述

//产生IIC停止信号
// 1.先拉低SDA,再拉低SCL
// 2.拉高SCL
// 3.拉高SDA
// 4.停止接收数据
void IIC_Stop(void)
{
	IIC_SCL = 0;
	IIC_SDA = 0;    // STOP:当SCL高时,数据由低变高
	IIC_SCL = 1; 	// SCL先拉高
    delay_us(5);	// 延迟大于4us
	IIC_SDA = 1;    // SDA再拉高,发送I2C总线结束信号
	delay_us(5);	// 延迟大于4.7us							   	
}

应答信号

在这里插入图片描述
接收器实现:

// 主机产生应答信号ACK
// 1.先拉低SCL,再拉低SDA
// 2.拉高SCL
// 3.拉低SCL## 标题
void I2C_Ack(void)
{
    IIC_SCL = 0;   	// 先拉低SCL,使得SDA数据可以发生改变
    IIC_SDA = 0;   
    delay_us(2);
    IIC_SCL = 1;
    delay_us(5);	// 延迟大于4us
    IIC_SCL = 0;
}

// 主机不产生应答信号NACK
// 1.先拉低SCL,再拉高SDA
// 2.拉高SCL
// 3.拉低SCL
void I2C_NAck(void)
{
    IIC_SCL = 0;	// 先拉低SCL,使得SDA数据可以发生改变
    IIC_SDA = 1;	// 拉高SDA,不产生应答信号
    delay_us(2);
    IIC_SCL = 1;
    delay_us(5);	// 延迟大于4us
    IIC_SCL = 0;
}

发送器实现:

// 等待应答信号到来
// @return	1,接收应答失败
//			0,接收应答成功
char IIC_Wait_Ack(void)
{
	u8 ucErrTime=0;
	 
	IIC_SDA = 1; delay_us(1);	   
	IIC_SCL = 1; delay_us(1);	 
	while(IIC_SDA) {
		ucErrTime++;
		if(ucErrTime > 250) {
			IIC_Stop();
			return 1;
		}
	}
	IIC_SCL = 0;	// 时钟输出0 	   
	return 0;  
} 

原文与参考:

IIC原理超详细讲解—值得一看_Z小旋的博客-CSDN博客_iic

IIC 5种嵌入式经典通信总线协议精讲_哔哩哔哩_bilibili

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 首先,你需要明确I2C总线协议的功能要求,并确定技术细节。其次,使用C语言编写I2C总线协议,可以使用标准的I2C库函数,以及特定于处理器的I2C驱动程序。最后,使用模拟或调试工具来验证I2C总线协议的正确性。 ### 回答2: I²C(Inter-Integrated Circuit)总线协议是一种用于在集成电路之间进行通信的串行总线协议。下面是使用C语言编写I²C总线协议的步骤: 首先,我们需要定义I²C总线的相关参数,包括时钟频率、数据位数和I²C地址等。可以使用宏定义或者全局变量来定义这些参数。 接下来,我们需要实现I²C总线的初始化函数,用于初始化I²C控制器和相关硬件。在初始化函数中,我们需要配置相关引脚的输入输出模式、上下拉电阻等。 然后,我们需要实现发送数据的函数。发送数据的过程包括发送起始位、I²C地址、数据、应答等步骤。通常情况下,我们可以使用位运算来控制每个步骤的时序和数据传输。 接着,我们需要实现接收数据的函数。接收数据的过程与发送类似,只是在发送结束后需要切换为接收模式,并且在接收数据时需要发送应答或非应答信号。 最后,我们可以实现其他辅助函数,例如读写寄存器、发送和接收多个字节的数据等。 在编写以上函数时,我们需要参考相关的I²C总线协议规范和硬件手册,以确保代码的正确性和可靠性。另外,为了提高代码的可读性和可维护性,可以使用适当的注释和模块化设计。 需要注意的是,具体的代码实现可能因硬件平台和具体需求而有所不同。以上只是基本的编写步骤和思路,实际编写过程中还需根据实际情况进行相应的优化和调整。 编写I²C总线协议的代码是一项复杂而精细的任务,需要对硬件和通信协议有深入的理解。因此,在实际应用中建议使用已经存在的I²C库或者驱动程序进行开发,以减少开发时间和复杂度。 ### 回答3: I2C(Inter-Integrated Circuit)总线协议是一种用于连接低速外设的串行通信协议,通过两根传输线SCL(时钟线)和SDA(数据线)进行通信。以下是使用C语言编写I2C总线协议的示例代码。 ```c #include <stdio.h> #include <stdint.h> #define I2C_ACK 0 #define I2C_NACK 1 // 初始化I2C总线 void i2c_init() { // TODO: 设置SCL和SDA引脚和配置相关寄存器 } // 发送一个起始信号 void i2c_start() { // TODO: 设置SDA和SCL引脚状态,产生起始信号 } // 发送一个停止信号 void i2c_stop() { // TODO: 设置SDA和SCL引脚状态,产生停止信号 } // 等待应答信号 int i2c_wait_ack() { // TODO: 读取SDA引脚状态,判断是否接收到应答信号 // 如果接收到应答信号,返回 I2C_ACK // 如果没有接收到应答信号,返回 I2C_NACK } // 发送一个字节 void i2c_write_byte(uint8_t data) { // TODO: 依次发送数据的每一位,同时检测应答信号 } // 读取一个字节 uint8_t i2c_read_byte() { // TODO: 依次读取数据的每一位,同时发送应答信号 // 返回读取的字节数据 } int main() { i2c_init(); // 初始化I2C总线 // 示例: 使用I2C总线向某个设备写入数据 i2c_start(); // 发送起始信号 i2c_write_byte(0xA0); // 发送设备地址和写入标志 i2c_wait_ack(); // 等待应答信号 i2c_write_byte(0x01); // 发送数据 i2c_wait_ack(); // 等待应答信号 i2c_write_byte(0x23); // 发送数据 i2c_wait_ack(); // 等待应答信号 i2c_stop(); // 发送停止信号 // 示例: 使用I2C总线从某个设备读取数据 i2c_start(); // 发送起始信号 i2c_write_byte(0xA1); // 发送设备地址和读取标志 i2c_wait_ack(); // 等待应答信号 uint8_t data = i2c_read_byte(); // 读取数据 i2c_send_ack(I2C_NACK); // 发送非应答信号 i2c_stop(); // 发送停止信号 printf("读取的数据是 %d\n", data); return 0; } ``` 以上示例是一个简单的I2C总线协议的实现。具体的操作需要根据硬件平台和具体的I2C总线驱动进行相应的设置和配置。可以根据实际需求对上述代码进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值