身价过亿的灵仙子说你IIC没写完也发?


在这里插入图片描述

小码农很硬气说没写完发咋了,你咬我啊

I2C协议的简单应用

I2C协议总体概述

I2C 总线,是飞利浦推出的一种串行总线,是具备多主机系统所需的包括总线仲裁、高低速兼容的高性能同步

I2C总线的硬件,是由一根数据线SDA,一根时钟线SCL构成。(由于有时钟线才有同步功能)不同的器件,都是并联接在这两条线上。通过不同的硬件地址来识别通信对象。

image-20211122145113275

I2C总线必须都接上拉电阻接到电源VCC ,电阻大小要根据设备实际测量。总线空闲时候SDA和SCL都是高电平。当其中一个设备拉低总线,整条线就全是低电平,器件与器件之间是“与”逻辑关系。

image-20211123101613426

I2C总线可能会有多个主机进行互相控制多个从机,多个主机通信就会出现仲裁的情况。我们51 单片机主要是单主机通信 多主机仲裁我们不概述

I2C协议,是在同一根SDA线上进行双向通信,属于半双工类。I2C协议首先是发送从机硬件地址,然后发送命令,再发送数据/寄存器编号或者读取数据。I2C协议可以多字节连续读写数据

I2C协议规则

I2C协议的数据有效性

规定,必须是在SCL的低电平期间,才能改变SDA的电平状态。SCL高电平期间SDA线必须是稳定的,否则会错误的识别成起始信号或者停止信号。

image-20211123143241408

I2C协议的起始信号、停止信号

SCL高电平期间SDA下降沿是起始信号,之后就是总线忙碌,比如发送设备唯一地址

SCL高电平期间SDA上升沿是终止信号。之后是总线的空闲

起始信号和终止信号,都是主机发送

image-20211123145912135

I2C协议的通讯格式

I2C协议,起始信号之后,可以连续传输多个字节。然后以停止信号结束这一帧数据的传输。第一字节是 7位硬件地址 + 1位传输方向控制位。地址是根据硬件配置的,比如AT24C02的地址是4位固定 +3位接地,可以挂8个相同的AT24C02芯片。只有地址匹配的设备,才会处理总线上的数据

image-20211123151456148

I2C协议,每个字节必须是8 + ACK位。字节是先传输高位后传输低位。标准 I2C协议是每位4微秒以上。但是有些器件是兼容各种速度的。
应答信号是接收端接收数据后,把 A SDA 拉低。告诉发送端已经接收完毕。
非应答信号是接收端未能拉低,或者单片机读取数据的最后一个字节不需要应答。

image-20211123152241688

I2C协议的数据读写三种方式

I2C 协议单向发送数据

比如显示设备,一般情况下我们只需要写入数据,传输过程如下

image-20211123153814649

①首先是起始信号 S
②然后是发送 7 位从机地址+传输方向位,0写。
③SCL 拉高,判断 ACK ,再拉低 SCL 。
④发送第 1个字节,一般情况下都是指令,或者寄存器地址。
⑤SCL拉高,判断 ACK ,再拉低 SCL 。
⑥发送第2个字节,一般情况下都是数据。
⑦SCL拉高,判断 ACK ,再拉低 SCL 。
⑧可以继续传输数据,或者停止。

I2协议发送地址后立即读取数据

比如传感器设备,一般情况下我们只需要读出数据,传输过程如下:

image-20211123155049282

①首先是起始信号 S
②然后是发送 7 位从机地址+传输方向位,1 读。
③SCL 拉高,判断 ACK ,再拉低 SCL 。
④读取第 1 个字节,一般情况下都是指令,或者寄存器地址。
⑤发送应答 ACK
⑥读取第 2个字节,一般情况下都是数据。
⑦发送应答 ACK ,或者不应答 NACK 。
⑧可以继续传输数据,或者停止。

I2协议先指定寄存器地址,再读取该寄存器的数据

比如存储芯片,一般情况下我们要先制定存储地址,再读取数据。传输过程如下:

image-20211123161904716

①首先是起始信号 S
②然后是发送7位从机地址+传输方向位,0 写。
③SCL 拉高,判断 ACK ,再拉低 SCL 。
④写数据,一般是写某个寄存器地址或者指令。
⑤SCL 拉高,判断 ACK ,再拉低 SCL 。
⑥ 再次起始信号 S
⑦然后是发送 7 位从机地址+传输方向位,1 读。
⑧SCL 拉高,判断 ACK ,再拉低 SCL 。
⑨写数据,一般是写某个寄存器地址或者指令。
⑩读取字节,一般情况下都是数据。
11.发送应答 ACK ,或者不应答 NACK 。
12 .可以继续传输数据,或者停止

image-20211123162554713

代码思路分析

image-20211125103906990

IIC初始化

//IIC初始化
void IIC_Init()
{
	P2M1 &= 0x3f;
	P2M0 &= 0x3f;    //配置P2.6,P2.7为标准输入输出口
	SDA_GPIO = 1; 
	SCL_GPIO = 1;    //默认情况下数据和时钟都是高电平
}

IIC开始信号

//IIC起始信号
void IIC_Start()
{
	SDA_GPIO = 1;   //开始数据是高电平
	SCL_GPIO = 1;   //开始时钟是高电平 
	IIC_Delay();    //延时一小会
	SDA_GPIO = 0;   //数据脚拉成低电平
	IIC_Delay();    //然后再延时一小会
	SCL_GPIO = 0;   //再把时钟线拉成低电平
	IIC_Delay();    //然后再延时一小会
}

IIC停止信号

//IIC停止信号
void IIC_Stop()
{
	SCL_GPIO = 1;   //时钟线拉成高电平
	SDA_GPIO = 0;   //数据线保持低电平
	IIC_Delay();    //然后再延时一小会
	SDA_GPIO = 0;   //数据线拉高
	IIC_Delay();    //然后再延时一小会
}

以下不解读了,直接说我不想解读了,没时间

#include "all.h"

//IIC微秒级别延时
void IIC_Delay()
{
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
}

//IIC初始化
void IIC_Init()
{
	P2M1 &= 0x3f;
	P2M0 &= 0x3f;    //配置P2.6,P2.7为标准输入输出口
	SDA_GPIO = 1; 
	SCL_GPIO = 1;    //默认情况下数据和时钟都是高电平
}
//IIC起始信号
void IIC_Start()
{
	SDA_GPIO = 1;   //开始数据是高电平
	SCL_GPIO = 1;   //开始时钟是高电平 
	IIC_Delay();    //延时一小会
	SDA_GPIO = 0;   //数据脚拉成低电平
	IIC_Delay();    //然后再延时一小会
	SCL_GPIO = 0;   //再把时钟线拉成低电平
	IIC_Delay();    //然后再延时一小会
}

//IIC停止信号
void IIC_Stop()
{
	SDA_GPIO = 0;   //数据线保持低电平
	SCL_GPIO = 1;   //时钟线拉成高电平
	IIC_Delay();    //然后再延时一小会
	SDA_GPIO = 0;   //数据线拉高
	IIC_Delay();    //然后再延时一小会
}

//IIC写入一个字节    向总线发送一个字节
void IIC_Write_Byte(u8 IIC_Byte)
{
	u8 i = 0;//8个数据位
	SCL_GPIO = 0;   //时钟线保持低电平
	SDA_GPIO = 1;   //数据线拉到高电平
	for(i = 0;i<8;i++)
	{
		//先发高位
		SDA_GPIO = (bit)(IIC_Byte & 0x80)
		//高位发完后再移位
		IIC_Byte = IIC_Byte << 1;
		SCL_GPIO = 1;   //时钟线拉到高电平
		IIC_Delay();    //再延时一小会
		SCL_GPIO = 0;   //时钟线拉到低电平
		IIC_Delay();    //然后再延时一小会
	}
}

//IIC读取字节
u8 IIC_Read_Byte()
{
	u8 i = 0;
	u8 value = 0;
	SCL_GPIO = 0;   //时钟线保持低电平
	SDA_GPIO = 1;   //数据线拉到高电平
	for(i = 0;i<8;i++)
	{
		value = (value<<1)|SDA_GPIO;
		SCL_GPIO = 1;   //时钟线拉到高电平
		IIC_Delay();    //再延时一小会
		SCL_GPIO = 0;   //时钟线拉到低电平
		IIC_Delay();    //然后再延时一小会
	}
	return value;
}
//IIC读应答
u8 IIC_Read_Ack()
{
	//应答变量
	u8 Ack = 1;
	u8 i = 0;
	SCL_GPIO = 1;   //时钟线拉到高电平
	IIC_Delay();    //再延时一小会
	while(Ack && i<5)
	{
		Ack = SDA_GPIO;
		i++;
	}
	SCL_GPIO = 0;   //时钟线拉到低电平
	return Ack;
}
//IIC写应答
//单片机发送应答给从机
void IIC_Read_Ack(u8 ack) 
{
	SDA_GPIO = ack;	
	IIC_Delay();    //再延时一小会
	SCL_GPIO = 1;   //时钟线拉到高电平
	IIC_Delay();    //再延时一小会
	SCL_GPIO = 0;   //时钟线拉到低电平
	IIC_Delay();    //再延时一小会
	SDA_GPIO = 1;   //数据线再拉成高电平
	IIC_Delay();    //再延时一小会
}

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>