Proteus仿真之IIC通信(AT24C02)

1.IIC通信简介:IIC是一种利用时钟线SCL和数据线SDA进行数据传输的通信协议。IIC的时序图如下所示:

Proteus仿真之IIC通信(AT24C02)_第1张图片

我们需要看懂时序图中开始信号、数据传输、应答信号和停止信号。

开始信号:SCL为高电平时,SDA出现下降沿信号。

数据传输:SCL为低电平时,SDA进行电平转换(对应着数据的二进制表示0/1),然后给SCL一个高电平信号,告诉它开始读数据,读取的数据即为SDA引脚的电平状态。

应答信号:SCL为高电平期间,将SDA线拉低,产生应答信号。主机每传输一个字节的数据后,从机都需要传输一个应答信号,来向主机汇报是否收到了该字节。

停止信号:在SCL为高电平期间,SDA产生一个上升沿信号。

此外,在SCL和SDA电平变换之后,引脚的电平状态需要保持不变一段时间,这个时间是非常短的,并且,产生不同的信号时这个保持不变的时间是不同的,通常可有延时实习(需要精确延时)。具体的信息可以自行查看IIC的数据手册。

主机发送起始信号后,会发出寻址信号。器件的地址信号一般是两种:10位和8位。此处介绍一下8位的地址信号:高7位为地址信号。最后一位R/W为读写选择信号,为0时表示主机接下来对从机进行写操作,为1时表示主机接下来对从机进行读操作。

因为IIC只有SCL和SDA线,同一时刻只能往一个方向传输数据,所以IIC是半双工通信。

2.仿真模块主要有:AT89C52、LCD1602(LM016L)、24C02C和排阻(RESPACK-8)。电路图如下:

Proteus仿真之IIC通信(AT24C02)_第2张图片

 仿真代码:

#include 
#include 

#define unchar unsigned char
#define uint unsigned int
	
unchar code dis_table[] = "0123456789";
	
sbit button = P1^2;		//定义按键
sbit lcden = P2^2;		//定义lcd的E端口
sbit lcdrw = P2^1;		//定义lcd的rw端口
sbit lcdrs = P2^0;		//定义lcd的rs端口
sbit SCL = P3^0;			//定义SCL时钟线端口
sbit SDA = P3^1;			//定义SDA数据线端口

//IIC延时函数,延时必须精确,否则无法准确传输
void Delay()
{
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
}

void DelayMs(uint ms)
{
	uint i;
	while(ms--)
	{
		for(i = 110;i > 0;i--)
		{
			;
		}
	}
}

//往LCD1602中写命令
void Write_Com(unchar com)
{
	lcdrs = 0;				//lcdrs为低电平时,选择指令寄存器
	P0 = com;
	DelayMs(5);
	lcden = 1;
	DelayMs(5);
	lcden = 0;
}

//往LCD1602中写数据
void Write_data(unchar date)
{
	lcdrs = 1;				//lcdrs为高电平时,选择数据寄存器
	P0 = date;
	DelayMs(5);
	lcden = 1;				//当lcden由高电平变为低电平时,LCD1602开始执行命令
	DelayMs(5);
	lcden = 0;
}

//LCD1602的初始化函数
void init()
{
	lcdrw = 0;				//lcdrw高电平时为读操作,低电平时为写操作 
	lcden = 0;
	Write_Com(0x38);
	Write_Com(0x0c);
	Write_Com(0x06);
	Write_Com(0x01);
}

//IIC初始化函数
void IIC_init()
{
	SCL = 1;
	Delay();
	SDA = 1;
	Delay();
}

//IIC起始信号函数
void IIC_start()
{
	//当SCL信号为高电平期间,SDA出现下降沿时,就是起始信号
	SDA = 1;
	Delay();
	SCL = 1;
	Delay();
	SDA = 0;
	Delay();
}

//IIC应答信号函数
void IIC_respons()
{
	//在SCL高电平期间,讲SDA线拉低,产生应答信号,表明数据传输成功
	unchar i = 0;
	SCL = 1;
	Delay();
	while(SDA == 1 && (i < 255))
	{
		i ++;
	}
	SCL = 0;
	Delay();
}

//定义停止信号函数
void IIC_stop()
{
	//当SCL在高电平时,SDA产生一个上升沿信号为停止信号
	SDA = 0;
	Delay();
	SCL = 1;
	Delay();
	SDA = 1;
	Delay();
}

//写一个字节函数
void IIC_writebyte(unchar date)
{
	unchar i,temp;
	temp = date;
	for(i = 0;i < 8;i++)
	{
		temp = temp << 1;	//溢出的一位自动保存到寄存器CY中
		SCL = 0;
		Delay();
		SDA = CY;
		Delay();
		SCL = 1;
		Delay();
	}
	SCL = 0;
	Delay();
	SCL = 1;
	Delay();
}

//IIC读一个字节函数
unchar IIC_readbyte()
{
	unchar i,Data;
	SCL = 0;
	Delay();
	SDA = 1;
	for(i = 0;i < 8;i++)
	{
		SCL = 1;
		Delay();
		SDA = 1;
		Data = (Data << 1) | SDA;
		SCL = 0;
		Delay();
	}
	Delay();
	return Data;
}

//往AT24C02的地址中写数据
void Write_add(unchar date,unchar address)
{
	IIC_start();
	IIC_writebyte(0xa0);
	IIC_respons();
	IIC_writebyte(address);
	IIC_respons();
	IIC_writebyte(date);
	IIC_respons();
	IIC_stop();
}

//从AT24C02的地址中读数据
unchar Read_add(unchar address)
{
	unchar date;
	IIC_start();
	IIC_writebyte(0xa0);		//AT24C02的地址为0xa0时是写入
	IIC_respons();
	IIC_writebyte(address);
	IIC_respons();
	IIC_start();
	IIC_writebyte(0xa1);		//AT24C02的地址为0xa1时是读
	IIC_respons();
	date = IIC_readbyte();	//将数据读取到date中
	IIC_stop();							//停止信号
	return date;
}

//显示数字函数
void display(unchar date)
{
	Write_Com(0x80);
	Write_data(dis_table[date/100]);						//显示百位
	Write_data(dis_table[date%100/10]);					//显示十位
	Write_data(dis_table[date%10]);							//显示个位
}

void main()
{
	unchar num,NUM;
	init();
	IIC_init();
	
	while(1)
	{
		if(button == 0)
		{
			DelayMs(10);
			if(button == 0)
			{
				num = Read_add(0x00);
				num ++;
				Write_add(num,0x00);	//将num写入到0x00地址处
			}
			while(button == 0)
			{
				;
			}
		}
		NUM = Read_add(0x00);			//将0x00处的数据读取出来
		display(NUM);
	}
}

3.运行结果:

Proteus仿真之IIC通信(AT24C02)_第3张图片

4.总结:IIC在数据传输时,需要在SCL高电平期间使SDA保持稳定,读取数据;在SCL为低电平期间,SDA才能进行高低电平转换。 IIC最主要的是SCL和SDA,通过SCL和SDA组合,完成不同的功能。当然,如何使用这些组合功能需要读懂IIC的数据手册。

本文中只是简单介绍了IIC的基本原理和使用方法,读者如需要进一步理解IIC可查看其数据手册。本文中使用是软件模拟IIC通信,使用软件模拟IIC通信的好处之一是方便移植。同样的IIC代码,移植其他的开发板上只需要修改一下引脚即可。

你可能感兴趣的:(Proteus仿真,proteus,IIC通信,AT24C02)