【嵌入式Linux内核驱动】IIC子系统 | 硬件原理 | 应用编程 | 内核驱动 | 总体框架

本文详细介绍了I2C协议的基础知识,包括协议特性、硬件连接方式、总线仲裁原理、时序图及其实现代码,同时还涵盖了写数据和读数据的操作,并讨论了I2C能挂载的设备数量、地址冲突解决和通讯速度等面试常见问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 硬件原理

1.1 IIC 基础

IIC协议简介—学习笔记_iic标准协议_越吃越胖的黄的博客-优快云博客

I2C(Inter-Integrated Circuit)是一种串行通信协议,用于连接微控制器、传感器、存储器和其他外设。

I2C使用两条线(SDA和SCL)进行通信,可以连接多个设备,每个设备都有一个唯一的地址。I2C总线上的设备可以充当主设备或从设备。主设备负责发起通信,从设备负责响应通信请求。

I2C协议具有以下特点:

  1. 两根线
  2. 同步、半双工
  3. 带应答
  4. 一主多从、多主多从

1.2 硬件连接

要能手撕出来

image-20230403191048720

仲裁:SDA线的仲裁也是建立在总线具有线“与”逻辑功能(线与逻辑,即两个以上的输出端直接互连就可以实现“AND”的逻辑功能。两个一出一,一个一出零、没有一出零)的原理上的。节点在发送1位数据后,比较总线上所呈现的数据与自己发送的是否一致。是,继续发送;否则,进行比较,输出低电平进行发送,输出高电平退出。SDA线的仲裁可以保证I2C总线系统在多个主节点同时企图控制总线时通信正常进行并且数据不丢失。总线系统通过仲裁只允许一个主节点可以继续占据总线。

1.3 时序

要能手撕出来

时序总结:

image-20230405220920577

总线空闲状态 SCL和SDA均为高电平,接上拉电阻。
起始信号(START) 在SCL保持高电平期间,SDA由高电平被拉低。由主控器发出。
数据位传送(DATA) 在SCL保持高电平期间,SDA上的电平保持稳定,低电平为数据0、高电平为数据1。用法:主控器和被控器都可发出。
应答信号(ACK) 在SCL保持高电平期间,SDA保持低电平。IIC总线上所有数据都是以8位字节传送的,发送器每发送一个字节,就在第9个时钟脉冲期间释放SDA(高电平),由接收器反馈一个ACK。
非应答信号(NACK) 在SCL保持高电平期间,SDA保持高电平。如果接收器是主控器,则它在收到最后一个字节后,发送一个NACK,通知被控器结束数据发送,并释放SDA(高电平),以便主控器发送一个STOP。
停止信号(STOP) 在SCL保持高电平时间,SDA由低电平被释放(拉高)。由主控器发出。

各时序部分的代码(要能手撕出来):

起始信号

void IIC_Start(void)
{
   
	SDA_H;						//拉高SDA线
	SCL_H;						//拉高SCL线
	DelayUs(iicInfo.speed);		//延时,速度控制
	
	SDA_L;						//当SCL线为高时,SDA线一个下降沿代表开始信号
	DelayUs(iicInfo.speed);		//延时,速度控制
	SCL_L;						//钳住SCL线,以便发送数据
}  

停止信号

void IIC_Stop(void)
{
   
	SDA_L;						//拉低SDA线
	SCL_L;						//拉低SCL先
	DelayUs(iicInfo.speed);		//延时,速度控制
	
	SCL_H;						//拉高SCL线
	SDA_H;						//拉高SDA线,当SCL线为高时,SDA线一个上升沿代表停止信号
	DelayUs(iicInfo.speed);
}

应答信号

//产生ACK应答,读取从机一字节数据后还要接着读的时候使用
//SCL在SDA一直为低电平期间完成低高电平转换
void IIC_Ack(void)
{
   	
	SCL_L;						//拉低SCL线
	SDA_L;						//拉低SDA线<----
	DelayUs(iicInfo.speed);
	SCL_H;						//拉高SCL线
	DelayUs(iicInfo.speed);
	SCL_L;						//拉低SCL线
}
//不产生ACK应答,读取从机一字节数据后不读了的时候使用    
//SCL在SDA一直为高电平期间完成低高电平转换
void IIC_NAck(void)
{
   
	SCL_L;						//拉低SCL线
	SDA_H;						//拉高SDA线<----
	DelayUs(iicInfo.speed);
	SCL_H;						//拉高SCL线
	DelayUs(iicInfo.speed);
	SCL_L;						//拉低SCL线
}
//等待ACK应答    
//发送完一个字节后(释放SDA)的下一个时钟高电平时期,读取SDA电平,0为收到应答
_Bool IIC_WaitAck(unsigned int timeOut)
{
   
	SDA_H;DelayUs(iicInfo.speed);			//拉高SDA线
	SCL_H;DelayUs(iicInfo.speed);			//拉高SCL线
	
	while(SDA_R)							//如果读到SDA线为1,则等待。应答信号应是0
	{
   
		if(--timeOut)
		{
   
			printf("WaitAck TimeOut\r\n");
			IIC_Stop();						//超时未收到应答,则停止总线			
			return IIC_Err;					//返回失败
		}		
		DelayUs(iicInfo.speed);
	}	
	SCL_L;									//拉低SCL线,以便继续收发数据	
	return IIC_OK;							//返回成功	
}

发送数据

void IIC_Send(unsigned 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值