其他分享
首页 > 其他分享> > I2c总线

I2c总线

作者:互联网

(1)I2c总线具有掉电保存数据的功能,可以保存一百年的时间。由于单片机没有I2c的硬件接口,所以用软件来模拟。
(2)原理:
I2C总线只有两根双向信号线。一根是数据线SDA,另一根是时钟线SCL。
在这里插入图片描述
一、数据位的有效性规定
I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
在这里插入图片描述
二、起始和终止信号
SCL线为高电平期间,SDA线由高电平向低电平的变化表示起始信号;SCL线为高电平期间,SDA线由低电平向高电平的变化表示终止信号。在这里插入图片描述
三、数据传送格式
(1)字节传送与应答
每一个字节必须保证是8位长度。数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)。
在这里插入图片描述
(2)数据帧格式
I2C总线上传送的数据信号是广义的,既包括地址信号,又包括真正的数据信号。
在起始信号后必须传送一个从机的地址(7位),第8位是数据的传送方向位(R/T),用“0”表示主机发送数据(T),“1”表示主机接收数据(R)。每次数据传送总是由主机产生的终止信号结束。但是,若主机希望继续占用总线进行新的数据传送,则可以不产生终止信号,马上再次发出起始信号对另一从机进行寻址。
在总线的一次数据传送过程中,可以有以下几种组合方式:
a、主机向从机发送数据,数据传送方向在整个传送过程中不变:
在这里插入图片描述
注:有阴影部分表示数据由主机向从机传送,无阴影部分则表示数据由从机向主机传送。
A表示应答, A非表示非应答(高电平)。S表示起始信号,P表示终止信号。。
b、主机在第一个字节后,立即从从机读数据
在这里插入图片描述 c、在传送过程中,当需要改变传送方向时,起始信号和从机地址都被重复产生一次,但两次读/写方向位正好反相。
在这里插入图片描述
总线数据传送的模拟
一、典型信号模拟
为了保证数据传送的可靠性,标准的I2C总线的数据传送有严格的时序要求。I2C总线的起始信号、终止信号、发送“0”及发送“1”的模拟时序 :

在这里插入图片描述在这里插入图片描述

在这里插入图片描述在这里插入图片描述
(3)源代码:按键K1实现保存,K2实现查看上次保存的数据,K3实现加一的功能,K4实现清零功能。用数码管显示。

/*主程序*/
#include<reg52.h>
#include<I2c.h>
typedef unsigned int u16;
typedef unsigned char u8;
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;//数码管位选

sbit K1=P3^1;
sbit K2=P3^0;
sbit K3=P3^2;
sbit K4=P3^3;	 //定义按键端口
char num=0;
u8 disp[4];      //定义数组用来处理数据
u8 code smgduan[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
void delay(u16 i)
{
	while(i--);
}
void Keypros()
{
	if(K1==0)
	{
		delay(1000);
		if(K1==0)
		{
			At24c02Write(1,num);	//1表示第一个地址,num表示数据。24c02写入数据
		}
		while(!K1);
	}
	if(K2==0)
	{
		delay(1000);
		if(K2==0)
		{
			num=At24c02Read(1);	//将24c02中的数据读出来
		}
		while(!K2);
	}
	if(K3==0)
	{
		delay(1000);
		if(K3==0)
		{
			num++;                //加一功能
			if(num>255)
			{
				num=0;
			}	
		}
		while(!K3);
	}
	if(K4==0)
	{
		delay(1000);  //消抖处理
		if(K4==0)
		{
			num=0;		 //数据清零
		}
		while(!K4);
	}
}
void datapros()
{
	disp[0]=smgduan[num/1000];//千位数据
	disp[1]=smgduan[num%1000/100];//百位数据
	disp[2]=smgduan[num%1000%100/10];//十位数据
	disp[3]=smgduan[num%1000%100%10];//个位数据
}
void DigDisplay()//数据处理函数
{
	u8 i;
	for(i=0;i<4;i++)
	{
		switch(i)
		{
			case(0):LSA=1;LSB=1;LSC=0; break;//显示第0位
			case(1):LSA=0;LSB=1;LSC=0; break;//显示第1位
			case(2):LSA=1;LSB=0;LSC=0; break;//显示第2位
			case(3):LSA=0;LSB=0;LSC=0; break;
		}
		P0=disp[i];//接收数据
		delay(100);
		P0=0x00;
	}
}
void main()
{
	while(1)
	{
		Keypros();
		datapros();
		DigDisplay();
	}
}
/*初始化,模拟I2c硬件结口*/
#include<I2c.h>
void Delay10us()//延时10us
{
	unsigned char a,b;
	for(b=1;b>0;b--)
		for(a=2;a>0;a--);
}
void I2cStart()//I2c起始信号
{
	SDA=1;
	Delay10us();
	SCL=1;
	Delay10us();
	SDA=0;
	Delay10us();
	SCL=0;
	Delay10us();
}
void I2cStop()//I2c停止信号
{
	SDA=0;
	Delay10us();
	SCL=1;
	Delay10us();
	SDA=1;	    
	Delay10us();
}
unsigned char I2cSendByte(unsigned char dat)//I2c发送数据
{
	unsigned char a=0,b=0;
	for(a=0;a<8;a++)
	{
		SDA=dat>>7;
		dat=dat<<1;
		Delay10us();
		SCL=1;
		Delay10us();
		SCL=0;
		Delay10us();
	}
	SDA=1;
	Delay10us();
	SCL=1;
	while(SDA)
	{
		b++;
		if(b>200)
		{
			SCL=0;
			Delay10us();
			return 0;
		}
	}
	SCL=0;
	Delay10us();
	return 1;
}
unsigned char I2cReadByte()//I2c读取数据
{
	unsigned char a=0,dat=0;
	SDA=1;
	Delay10us();
	for(a=0;a<8;a++)
	{
		SCL=1;
		Delay10us();
		dat<<=1;
		dat=dat|SDA;
		Delay10us();
		SCL=0;
		Delay10us();
	}
	return dat;
}
void At24c02Write(unsigned char addr,unsigned char dat)//24c02写数据
{
	I2cStart();
	I2cSendByte(0xa0);
	I2cSendByte(addr);	
	I2cSendByte(dat);
	I2cStop();
}
unsigned char At24c02Read(unsigned char addr)//24c02读取数据
{
	unsigned char num;
	I2cStart();
	I2cSendByte(0xa0);
	I2cSendByte(addr);
	I2cStart();
	I2cSendByte(0xa1);
	num=I2cReadByte();
	I2cStop();
	return num;	
}	

标签:传送,Delay10us,总线,unsigned,char,num,I2c,数据
来源: https://blog.csdn.net/m0_46484797/article/details/113177272