蓝桥杯单片机IIC驱动程序学习

AT24C02提供2024位的连续的可擦除的可编程的只读的存储器(即我们所说的EEPROM了,实质是一个断电数据不丢失的存储器),有共256字节的内部存储空间,就也是说有256个内部存储空间的地址,地址长度有8位。
在这里插入图片描述
IIC总线只有2根信号线,一根是数据线SDA,一根是时钟线SCL。SDA和SCL均为双向信号线,通过上拉电阻接正电源。当总线空闲时,两根线都是高电平。连接到总线上的任一器件,输出低电平,都将使总线的信号变低。
连接总线的器件输出级必须是集电极或漏极开路,以形成线“与”功能。
每个具有IIC接口的设备都有一个唯一的地址,也叫做设备地址。

数据位的有效性定义
IIC总线在进行数据传送时,时钟信号SCL为高电平期间,数据线SDA上的数据必须保持稳定。只有在时钟信号为低电平期间,数据线上的数据才允许变化。
在这里插入图片描述
IIC总线数据传输规范
在数据的传输过程中,必须确认数据传送的开始和结束。在IIC总线规范中,规定了起始信号和停止信号。
起始信号:当时钟线SCL为高电平时,数据线SDA由高变低。
停止信号:当时钟线SCL为高电平时,数据线SDA由低变高。
在这里插入图片描述
在这里插入图片描述
在起始信号以后,IIC总线就被认为是处于忙状态,直到停止信号以后的几个时钟周期,IIC总线才被认为重新处于空闲状态。 在起始信号之后,必须是器件的控制字节,也即是设备地址,其中高4位是器件的类型识别符(EEPROM的识别符为1010),接着3位是片选信号,最后1位是读写控制位,读操作为1,写操作为0。

对于EEPROM器件来说,如果片选信号为000,则:
读操作的设备地址为:0xA1。
写操作的设备地址为:0xA0。
IIC总线每次传送的数据字节不限,每一个字节必须是8位。数据传送时,必须先送最高位(MSB),每个数据字节后面都有一个确认位,也就是应答(ACK)
IIC总线协议规定,每传送一个字节数据后,都要有一个应答信号,以确定数据传送是否被对方收到。应答信号由接收方在数据开始后的第9个时钟周期发送,在SCL为高电平期间,接收方将SDA拉为低电平产生应答,用来结束一个字节的传输。也就是说,一帧完整的数据共有9位。

#include <STC15F2K60S2.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit SCL = P2^0;
sbit SDA = P2^1;

uchar code tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF};
uchar yi,er,san,si,wu ,liu,qi,ba;

void Delay1ms(uint z);	
void display1(uchar yi,uchar er);
void display2(uchar san,uchar si);
void display3(uchar wu,uchar liu);
void display4(uchar qi,uchar ba);
void allinit();
void  iicstart();
void iicstop();
void writebyte(uchar dat);
uchar iicreadbyte();
void iicdelay(uchar m);
uchar ack();
void iicwrite(uchar add,uchar dat);
uchar iicread(uchar add);



void main()
{
	uchar num;
	allinit();
	yi=11;er=11;san=11;si=11;wu=11;liu=0;qi=0;ba=0;
	//iicwrite(0x00,0);//初始化 写入的地址  要写的字节 只在第一次写入0,烧录之后注释在进行第二次烧录
	num=iicread(0x00);
	iicwrite(0x00,num+1);//+1之后再存入原来地址
	while(1)
	{
		liu=num/100;qi=num%100/10;ba=num%10;
		display1(yi,er);
		display2(san,si);
		display3(wu,liu);
		display4(qi,ba);
	}
	
}



void  iicstart()//开启iic,总线启动条件
{
			SDA=1;
			_nop_();
			SCL=1;
			_nop_();
			SDA=0;
			_nop_();
			SCL=0;
			_nop_();
}
void iicstop()//关闭iic,总线停止条件
{
			SDA=0;
			_nop_();
			SCL=1;
			_nop_();
			SDA=1;
			_nop_();

}
void writebyte(uchar dat)//写字节操作
{
	uchar i;
	for(i=0;i<8;i++)
	{
	  SCL=0;//时钟线为0可以进行数据线操作
		SDA=dat&0x80;//进行写操作
		
		SCL=1;
		dat<<=1;	
	}
	  SCL=0;
}

uchar iicreadbyte()//读字节操作
{
	uchar dat;
	uchar i;
	for(i=0;i<8;i++)
	{
		SCL=1;
		dat<<=1;
		if(SDA)
		{
			dat|=0x01;//进行读操作 
		}
	   SCL=0;
	}
	return dat;

}


void iicdelay(uchar m)//延迟,防止读取时间不够
{
do
{
  _nop_();
}
while(m--);

}

uchar ack()//等待eeprom应答
{
  SCL=1;
	iicdelay(5);
	if(SDA==1)//释放总线
	{
	  SCL=0;
		iicstop();
		return 0;//读取或写入数据成功,SDA返回0
	}
	else
	{
	  SCL=0;
		return 1;
	}
	
}



void iicwrite(uchar add,uchar dat)
{
	iicstart();
	writebyte(0xa0);//0xa0,告知单片机进行写操作
	ack();
	writebyte(add);//写入地址add
	ack();
	writebyte(dat);//写入数据dat
	ack();
	iicstop();
	
}


uchar iicread(uchar add)
{
	uchar temp;
	iicstart();
	writebyte(0xa0);////0xa0,告知单片机设备地址并进行写操作
	ack();//等待响应
	writebyte(add);//数据地址
	ack();
	iicstop();
	
	
	iicstart();
	writebyte(0xa1);//0xa1,告知单片机设备地址并进行读操作
	ack();
	temp=iicreadbyte();//每位读取字节
	iicstop();
	return temp;

}



void Delay1ms(uint z)		//@12.000MHz
{
	unsigned char i, j;
  uint k;
	for(k=z;k>0;k--)
	{
	i = 12;
	j = 169;
	do
	{
		while (--j);
	} while (--i);
	
	}
	
}

void display1(uchar yi, uchar er)
{
	 //开位选
		P2=0XC0;
		P0=0X01;
		//开段选
		P2=0XFF;
		P0=tab[yi];
		Delay1ms(1);
	
		//开位选
		P2=0XC0;
		P0=0X02;
		//开段选
		P2=0XFF;
		P0=tab[er];
		Delay1ms(1);		
}

void display2( uchar san,uchar si)
{
	 //开位选
		P2=0XC0;
		P0=0X04;
		//开段选
		P2=0XFF;
		P0=tab[san];
		Delay1ms(1);
	
		//开位选
		P2=0XC0;
		P0=0X08;
		//开段选
		P2=0XFF;
		P0=tab[si];
		Delay1ms(1);		
}

void display3(uchar wu, uchar liu)
{
	 //开位选
		P2=0XC0;
		P0=0X10;
		//开段选
		P2=0XFF;
		P0=tab[wu];
		Delay1ms(1);
	
		//开位选
		P2=0XC0;
		P0=0X20;
		//开段选
		P2=0XFF;
		P0=tab[liu];
		Delay1ms(1);		
}

void display4(uchar qi, uchar ba)
{
	 //开位选
		P2=0XC0;
		P0=0X40;
		//开段选
		P2=0XFF;
		P0=tab[qi];
		Delay1ms(1);
	
		//开位选
		P2=0XC0;
		P0=0X80;
		//开段选
		P2=0XFF;
		P0=tab[ba];
		Delay1ms(1);		
}



void allinit()
{
	P2=0X80;P0=0XFF;//关led
	
	P2=0XC0;P0=0XFF;
	P2=0XFF;P0=0XFF;//关数码管
	
	P2=0XA0;P0=0X00;//蜂鸣器,继电器

}


PCF8951 与EEPROM操作基本一致,仅仅地址不同
写入为0X90
读取为0X91
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_42244181/article/details/86920064