I2C 协议 代码详解

I2C 协议

  最后代码已上传!!!!
  代码文章链接
   github 代码链接在该文章最后

I2C 简要介绍

I2C 总线(I2C bus,Inter-IC bus)是一个双向的两线连续总线,提供集成电路(ICs)之间的通信线路。I2C总线是一种串行扩展技 术,最早由 Philips 公司推出,广泛应用于电视,录像机和音频等设备。I2C总线的意思:“完成集成电路或功能单元之间信息交换的规范或协议”。Philips公司推出的 I2C 总线采用一条数据线(SDA),加一条时钟线(SCL)来完成数据的传输及外围器件的扩展;对各个节点的寻址是软寻址方式,节省了片选线,标准的寻址字节 SLAM 为7位,可以寻址127个单元。

1. 延时信号

static void i2c_Delay(void)
{
	uint8_t i;
	for (i = 0; i < 10; i++);
}

逻辑分析测试得出

​ 条件: CPU 主频 72MHZ ,MDK 编译, 1级优化

​ 循环次数 10 ,SCL 频率 = 205 KHZ

​ 循环次数 7 ,SCL 频率 = 347 KHZ, SCL 高电平时间 1.5us, SCL 低电平时间 2.87us

​ 循环次数 5 ,SCL 频率 = 421 KHZ ,SCL 高电平时间 1.25us, SCL 低电平时间 2.37us

2.起始信号

根据上方时序图可以知道

​ I2C 起始信号:当 SCL 高电平时,SDA 出现一个下跳沿表示 I2C 总线启动信号

​ 对应代码为:

void i2c_Start(void)
{
	OLED_I2C_SDA_1();			//SDA 总线置1
	OLED_I2C_SCL_1();			//SCL 总线置1
	i2c_Delay();				//延时信号
	OLED_I2C_SDA_0();			//置 0 
	i2c_Delay();
	OLED_I2C_SCL_0();			//SCL 置0
	i2c_Delay();
}

3. 停止信号

根据上方时序图可以知道

​ I2C 结束信号:当 SCL 高电平时,SDA 出现一个上跳沿表示 I2C 总线停止信号

​ 对应代码为:

void i2c_Stop(void)
{
	OLED_I2C_SDA_0();
	OLED_I2C_SCL_1();
	i2c_Delay();
	OLED_I2C_SDA_1();
}

4. 等待应答信号

根据上方时序图可以知道

​ I2C等待应答信号:当 SDA 高电平,SCL 也处在高电平,这时候 SDA 返回的数据, 1 代表无器件应答,0 代表正确应答。

​ 对应代码为:

uint8_t i2c_WaitAck(void)
{
	uint8_t re;

	OLED_I2C_SDA_1();	
	i2c_Delay();
	OLED_I2C_SCL_1();	
	i2c_Delay();
	if (OLED_I2C_SDA_READ())	//读取 SDA 口线状态
	{
		re = 1;					
	}
	else
	{
		re = 0;
	}
	OLED_I2C_SCL_0();			//拉低 SCL 总线
	i2c_Delay();
	return re;
}

5. 发送信号

根据上方时序图可以知道

​ 在SCL为高电平期间,发送数据,发送8次数据,数据为1,SDA被拉高,SDA被拉低,数据为0,SDA被拉低。

void i2c_SendByte(uint8_t _ucByte)
{
	uint8_t i; 							//先传输高位 bit7
	for (i = 0; i < 8; i++)
	{		
		if (_ucByte & 0x80)   			//判断 高位
		{
			OLED_I2C_SDA_1();			//设置 SDA 传输数据 
		}
		else
		{
			OLED_I2C_SDA_0();			
		}
		i2c_Delay();
		OLED_I2C_SCL_1();				//拉高 SCL ,发送数据
		i2c_Delay();	
		OLED_I2C_SCL_0();				//拉低 SCL ,改变 SDA 数据,左移 _ucByte ,再次判断 高位 bit6 等等
		if (i == 7)
		{
			 OLED_I2C_SDA_1(); 			//退出传输, SDA 置 1
		}
		_ucByte <<= 1;	
		i2c_Delay();
	}
}

6. 读取信号

uint8_t i2c_ReadByte(void)
{
	uint8_t i;
	uint8_t value;
	value = 0;          
	for (i = 0; i < 8; i++)
	{
		value <<= 1;					//左移 1 位
		OLED_I2C_SCL_1();				// SCL 置 1 
		i2c_Delay();
		if (OLED_I2C_SDA_READ())		//读取 SDA 口数据
		{
			value++;                    //每次都左移一位,value++,就等于 |          
		}
		OLED_I2C_SCL_0();				//SCL 置 0 ,改变 SDA 数据
		i2c_Delay();
	}
	return value;						//返回读取到的数据
}

SCL 置 1,SDA数据稳定,SCL 置 0,可以改变 SDA数据

最后

 第一次尝试编写博客,若是有什么建议,欢迎批评指出。

后续会逐步分块更新,并会在最后一篇文章上传源代码。

  最后一篇文章已更新,代码在该篇文章最后

  一文带你了解 MQTT 协议 代码在该文章最后

 若是该文章对你有作用或是觉得文章写得还行,帮忙点点赞,三连!

  • 33
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
在Linux操作系统下,I2C是一种常见的通信协议,用于连接主机与各种外部设备,如传感器、扩展模块等。在编写Linux下的I2C代码时,需要使用Linux提供的I2C子系统,它包含了各种函数和结构体,用于管理和操作I2C总线。 首先,我们需要创建一个I2C设备的句柄,可以使用函数`open()`打开对应的设备文件,如`/dev/i2c-0`。如果成功打开设备文件,就可以使用`ioctl()`函数进行各种设置和控制操作。例如,通过`I2C_SLAVE`命令可以指定要与之通信的从设备的地址。 接下来,我们可以使用`i2c_smbus_*()`系列函数来进行I2C通信。这些函数封装了一些常用的I2C操作,如读写字节、读取寄存器等。对于特定的I2C设备,可能还需要使用其他特定的函数进行访问。 在使用`i2c_smbus_*()`函数进行通信时,需要注意传入的参数。例如,读操作需要指定要读取的字节个数,写操作需要指定要写入的数据。同时,还要注意处理函数的返回值,以便判断操作是否成功。 另外,可以使用`close()`关闭I2C设备的句柄,释放资源。 需要注意的是,编写Linux下的I2C代码需要有一定的编程基础和对Linux系统的了解。还需要查阅相关的资料,了解具体的设备地址、寄存器映射关系,以及所需的操作命令和数据格式等。 总之,编写Linux下的I2C代码需要熟悉Linux系统提供的I2C子系统和相关函数,同时还需要了解具体的设备和通信协议的细节。只有掌握了这些知识,才能有效地进行I2C通信,并与外部设备进行数据交互。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

丿轩雪灬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值