day_1.51单片机EEPROM(IIC总线)

一、IIC串行总线的组成与原理。
1.多主机系统所需要的包括总线裁决和高低速器件同步功能的高性能总线。
2.两根双向信号线,一根是数据线SDA,一根是时钟线SCL.
3.IIC总线通过上拉电阻接正电源,当总线空闲时吗,两根线均为高电平,故连到总线上的任意器件输出低电平都会使得总线信号拉低,即各器件的SDA及SCL都是线“与”关系。(有低都为低,皆高则高)

二、IIC总线的数据传送
IIC总线上传送的数据信号是广义的,既包括地址信号,又包括真正的数据信号

  1. 数据位的有效性规定
    SCL时钟信号位高电平期间,数据线SDA上的数据必须保持稳定;
    SCL时钟信号为低电平期间,数据线SDA上的高低电平状体才允许变化(低电平才会数据传输);
  2. 起始信号:SCL线为高电平期间,SDA线由高向低变化;
  3. 终止信号:SCL线为高电平期间,SDA线由低到高变化;
  4. 起始信号、终止信号都是主机发出的,起始信号产生后,总线处于被占用状态;终止信号产生后,
    总线 处于空闲状态;
  5. 连接到IIC总线上的器件,若具有IIC总线的硬件接口,则很容易检测到起始和终止信号;
  6. 接收器件收到一个字节后,会做相应的动作,如中断等,可能无法立刻接收下一个字节,这时,该
    器件可以拉低SCL线,使主机处于等待状态。直到接收器件准备好接收下一个字节,再释放SCL线
    使之为高电平;

三、数据传送格式

  1. 字节传送与应答:每一个字节8位长度。数据传送时,先传送最高位(MSB),每一个传送的字节后面都必须跟随一位应答位(即一帧共9位)。
  2. 从机不对主机寻址信号应答时(如从机正在进行实时性的处理工作而无法接收总线上的数据),该
    从机数据线拉高,主机产生终止信号,终止数据传送。
    3.从机对主机应答,但在数据传送一段时间后无法继续接收更多的数据时,从机可以通过对无法接收的第
    一个数据字节的“非应答”通知主机,主机则发送终止信号结束传送。
    4.主机接收数据时,它收到最后一个数据字节后,必须向从机发出一个结束传送的信号,这个信号是由对从机的“非应答”来实现的。然后,从机释放SDA线,以允许主机产生终止信号。

四、数据传送过程:
主机产生起始信号,然后发送一个字节(包括从机地址(7位),和传送方向位R/T = 1/0,1表示主机收数据R,0表示发送数据T),然后从机应答(释放SCL线为高电平),继续数据传送;直到收到最后一
个字节,主机发送终止信号,结束传送。

1.主机向从机发送数据,数据传送方向在整个传送过程中不变:
-----S----------从机地址------ 0--------------A----------8位数据------ A------8位数据—A/非A ---------P
起始信号----7位地址—主标志---- 从机应答-------------------从应答-----------------应答------ 终止信号
2.主机在第一个字节后,立即从从机读数据
-----S----------从机地址------ 1--------------A----------8位数据------ A------8位数据—非A ---------P
起始信号----7位地址—主标志---- 从机应答-------------------从应答-----------------非应答------ 终止信号
3.当需要改变传送方向时,起始信号和从机地址都被重复产生一次,读写方向位正好相反。
-----S----------从机地址------ 0--------------A----------8位数据------ A
起始信号----7位地址—主标志---- 从机应答-------------------从应答
-----S----------从机地址------ 1--------------A----------------8位数据—非A ---------P
起始信号----7位地址—主标志---- 从机应答-------------------------应答------ 终止信号

五、总线的寻址
IIC总线协议规定:采用7位的寻址字节(起始信号后的第一个字节)
1.寻址字节D7~D0(高到低),D7 ~D1为从机地址位,D0为数据传送方向位。1收,0发。
2.主机发送地址时,总线上的每个从机都将这7位地址码与自己的地址进行比较,相同则认为自己正被主机寻址,根据R/T位将自己确定为发送器或者接收器。
3.从机的地址由固定部分和可编程部分组成,在一个系统中可编程部分决定了可接入总线该类器件的最大数目。(例:某从机7位寻址位4位固定,3位为可编程位,这时仅能寻址8个相同器件。)

六、串行EEPROM的扩展。
1.AT24C02 256字节。芯片地址的固定部分为1010,A2,A1,A0引脚接高低电平后得到确定的3位编码,形成的7位编码即为其地址。
2.单片机写操作时,首先发送7位地址码和写方向位“0”(共8位,即一个字节),发送完后释放SDA线并在SCL线上产生第9个时钟信号。被选中的存储器件在确定是自己的地址后,在SDA线上产生一个应答信号作为响应,单片机收到应答后就可以传送数据了。
3.传送数据时,单片机首先发送的一个字节被写入器件的存储区的首地址,收到存储器器件的应答后,单片机就逐个发送各个数据字节,但每发送一个字节后都要等待应答。
4.AT24C系列芯片内地址在接收到每一个数据字节后地址自加1,在芯片的“一次装载字节数”(不同芯片字节数不同),在限度内,只需要输入首地址,装载字节数超过芯片的"一次装载字节数”时,数据地址将“上卷”,前面的数据将被覆盖。
5.写入N个数据:
-----S----------器件地址------ 0-----------A------写入芯片首地址-- A。。8位数据-------A -------------P
起始信号----7位地址—主标志-- 从机应答-------------------从应答-。。。---------应答-------- 终止信号
6.读出过程
-----S----------器件地址------ 0-----------A------读出芯片首地址-- A
起始信号----7位地址—主标志-- 从机应答-------------------从应答
器件地址----1----------A-----DATE1----A—.---非A-----------P
7位地址—读方位—应答----数据-----应答–。--应答–终止信号

7.移位操作
①左移时最低位补0,最高位移入PSW的CY位;
②右移时最高位保持原数,最低位移除。

七、AT24CXX存储器工作原理(AT24C02)
CAT24WC01/02/04/08/16 1K/2K/4K/8K/16K/

1.特点:
①与400KHz IIC总线兼容;
②1.8V到6.0V工作电压;
③低功耗CMOS技术;
④写保护功能当WP位高电平时进入写保护状态;
⑤页写缓冲器;
⑥自定时擦写周期;
⑦100万次编程/擦除周期;
⑧保存数据100年;
⑨8脚DIP SOIC或TSSOP封装;
⑩温度范围商业级和工业级;
2.管脚说明:
①1 ~ 3(A0~A2),对于02/32/64,作为硬件地址,可同时级联8个器件;04使用A2、A1做硬件地址,可同时级联4个;08使用A2做硬件地址,可级联2个;16未使用器件地址引脚,总线上只能接一个。不做地址引脚,则悬空,可接地;
②5,SDA 串行地址和数据输入输出,接上拉电阻典型值为10KΩ;
③6,SCL串行时钟输入,SCL同步数据传输,上升沿数据写入,下降沿数据读出;
④7,WP 写保护,WP 引脚提供硬件数据保护,接地,正常读写,接VCC,只读。
⑤4,GND;
⑥8,VCC;

八、AT24C02驱动程序编写
1.在根目录创建 i2c.c 、 i2c.h 两个文件;
2.右击source group,添加文件到group;添加i2c.c文件;
3.编写头文件,在i2c.h 中写

    #ifndef   _I2C_H
	#define   _I2C_H
	#include<reg52.h>	
	
	sbit SCL=P2^1;
	sbit SDA=P2^0;
	
	#endif

4.在i2c.c中写

#include<i2c.h>//可使用该头文件中的东西
//可以写很多函数供主函数调用,需要在主函数包含i2c.h头文件。

void Delay10us(void)   //误差 0us
{
    unsigned char a,b;
    for(b=1;b>0;b--)
        for(a=2;a>0;a--);
}
void I2cStart()//起始信号程序
{	
	SDA=1;
	Delay10us();
	SCL=1;
	Delay10us();
	SDA=0;
	Delay10us();
	SCL=0;
	Delay10us();
} //起始信号
void I2cStop()//终止信号程序
{	
	SDA=0;
	Delay10us();
	SCL=1;
	Delay10us();
	SDA=1;
	Delay10us();
}//终止信号
unsigned char I2cSendByte(unsigned char dat)//数据发送函数
{
	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()//读数据函数
{
	unsigned char a=0;dat=0;
	for(a=0;a<8;a++)
	{
	SCL=1;
	Delay10us();
	dat<<1;
	dat |=SDA;
	Delay10us();
	SCL=0;
	Delay10us()}
	return dat;
}

void At24c02Write(unsigned char add,unsigned char dat)//写数据
{	
	I2cStart();//起始信号
	I2cScendByte(0xa0);//发送器件地址根据A0~A2引脚的接法确定1010 000   0代表写数据
	I2cScendByte(add);//发送存储地址
	I2cScendByte(dat);//写入的数据
	I2cStop();//停止信号
}
unsigned char At24c02Read(unsigend char  addr)//读取数据
{
	unsigned char  num;
	I2cStart();//起始信号
	I2cSendByte(0xa0);//器件地址
	I2cSendByte(addr);//读出首地址
	I2cStart();
	I2cScendByte(0xa1);//器件地址+1
	num=I2cReadByte();
	I2cStop();
	return unm;//返回读取的数据	
}

5.在主函数:

#include<reg51.h>
#include<i2c.h>


typedef unsigned char u8;
typedef unsigned int u16;


sbit k1=P3^1;//定义按键
sbit k2=P3^0
sbit k3=P3^2;
sbit k4=P3^3;

sbit LSA=P2^2;//38译码器3个引脚
sbit LSA=P2^3;
sbit LSA=P2^4;
u8 code  display[4];//存放处理过后的每一位数码管显示的数字
u8 code smgduan[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x70,0x7f,0x6f};//0~9数码管段选
void delay(u16 i)
{	
	while(i--);
}

void keypress()//按键函数
{	
	if(k1==0)   //按键功能:把num的值写入At24c02
	{
		delay(1000);
		if(k1==0)
		{
			At2402Write(1,num);//1是首地址,num是写入的数据
		}
		while(!k1);
	}
	if(k2==0//按键2的作用是从At24c02中读出数据
	{
		delay(1000);//消抖
		if(k2==0)
		{
			num=At24c02Read(1);
		}
		while(!k2);
	}
	if (k3==0) //功能:num自加,到256就 清零
	{
		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 date_change()//数码管显示多位数处理函数
{
	display[0]=smgduan[num/1000];//得到千位
	display[1]=smgduan[num%1000/100];//得到百位
	display[2]=smgduan[num%1000%100/10];//得到十位
	display[3]=smgduan[num%1000%100%10];//得到个位
}
void Seg_Display()
{
	u8 i;
	for(i=0;i<4;i++)
	{
		switch(i)
		{
			case 0: LSA=0;LSB=0;LSC=0;break;//显示数码管第0位
			case 1: LSA=1;LSB=0;LSC=0;break;//显示数码管第1位
			case 2: LSA=0;LSB=1;LSC=0;break;//显示数码管第2位
			case 3: LSA=1;LSB=1;LSC=0;break;//显示数码管第3位
		}
		P0=display[3-i];//发送段码
		delay(100);
		P0=0X00;//消抖
	}
}
void main()
{
	while(1)
	{
		keypress();
		date_change()Seg_Display()}
	
}

《普中单片机学习笔记》
不要用windows自带的浏览器编辑文章,因为复制代码会崩溃,上面90%的代码都是一个一个敲得。

猜你喜欢

转载自blog.csdn.net/jun8086/article/details/104294274
今日推荐