IIC模拟通信实例(基于51单片机)

在本文中,主要描述了IIC通信协议与读写24c02(EEPROM)的具体实例,并将P1口连接8个LED小灯,将从24c02里面读取出来的数据赋值给P1口,使小灯的亮灭情况根据读取的数据发生相应的改变。

目录

1. IIC简介
2. IIC通信时序
3. EEPROM简介
4. 程序实例
5. 仿真结果

IIC简介

IIC(Inter-Integrated Circuit)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备(特别是外部存储器件)。

IIC 主要由两条信号线线来完成通信过程:
SDA——数据线
SCL——时钟线

一条IIC总线上能挂载多个IIC器件

当总线空闲时,两根线均为高电平。连到总线上的任一器件输出的低电平,都将使总线的信号变低,即各器件的SDA及SCL都是线“与”关系

每个接到IIC总线上的器件都有唯一地址,可避免接收混乱,不知道读哪一个器件的情况。
在这里插入图片描述

IIC通信时序

在这里插入图片描述

空闲状态:SCL线与SDA线均处于高电平状态,等待起始信号
起始信号:SCL线为高电平期间,SDA线由高电平向低电平的变化表示起始信号
终止信号:SCL线为高电平期间,SDA线由低电平向高电平的变化表示终止信号
在这里插入图片描述
数据传输:IIC总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
在这里插入图片描述

数据传送格式
每一个字节必须保证是8位长度。数据传送时,先传送最高位,每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)。
应答位:返回0,表示成功应答。应答不成功,返回1。
在这里插入图片描述
IIC时序要求
在这里插入图片描述

EEPROM简介

EEPROM(Electrically Erasable Programmable Read Only Memory),电可擦除可编程只读存储器,是一种掉电之后数据不会丢失的存储芯片。
EEPROM里面用的芯片是24c0x系列芯片,它能够存储数据的大小为:
24C01:128字节(128×8位)
24C02:256字节(256×8位)
24C04:512字节(512×8位)
24C08:1K字节(1K×8位)
24C16:2K字节(2K×8位)

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

引脚说明

引脚 功能
SCL 时钟线
SDA 数据线
A0、A1、A2 可编程器件地址
WP 写保护

为什么说A0、A1、A2三位共同来构成24c0x的器件地址呢?
从数据手册来看,高4位是1010,低4位是A0、A1、A2、R/W,传7位有效地址,R/W决定读还是写。
如果将A0=A1=A2=0,那么地址为:0101 0000=0x50。
所以改变A0~A3的高低电平值,可以改变器件的地址。
在这里插入图片描述
读写操作

  1. 发送起始信号
  2. 写器件地址
  3. 应答
  4. 数据地址
  5. 应答
  6. 写数据
  7. 应答
  8. 结束信号

在这里插入图片描述

  1. 起始信号
  2. 写器件地址
  3. 应答
  4. 写数据地址
  5. 应答
  6. 起始信号
  7. 写数据地址加读写位
  8. 读出数据
  9. 直接停止,没有应答

在这里插入图片描述

程序实例

现在对着时序图来写IIC通信程序(仔细对应时序看程序)
在这里插入图片描述

#include <reg52.h>
#include <intrins.h>

sbit SCL = P2^0;
sbit SDA = P2^1;


void IIC_Delay()		//前图中大于4us或4.7us的延时
{
	_nop_();_nop_();_nop_();
	_nop_();_nop_();_nop_();
}

void IIC_Init()			//将两根线拉高,进入初始状态,等待开始信号
{
	SDA = 1;
	SCL = 1;
}

void IIC_Start()		//起始信号,SCL为高时,SDA由高变低
{
	SCL = 1;
	SDA = 1;
	IIC_Delay();
	SDA = 0;
	IIC_Delay();
	SCL = 0;
	IIC_Delay();
}

void IIC_Stop()			//结束信号,SCL为高时,SDA由低变高
{
	SCL = 0;
	SDA = 0;
	IIC_Delay();
	SCL = 1;
	IIC_Delay();
	SDA = 1;
	IIC_Delay();
}

void IIC_ACK()			//应答信号
{
   unsigned char i=0;
   SCL = 1;			//SCL为高时,接收应答
   IIC_Delay();
   while((SDA==1)&&(i<255))		//过了一段时间SDA仍为高,就是非应答信号;否则,SDA=0,返回应答信号
   	  i++;
   SCL = 0;			//应答后拉低时钟线,等待结束信号
   IIC_Delay();
}

void IIC_Write_Byte(unsigned char j)		//写一个字节,从高位到低位发送
{
	unsigned char i,temp;
	temp = j;
	SCL = 0;		//数据只在SCL为低时允许改变
	IIC_Delay();
	for(i=0;i<8;i++)
	{
		temp <<= 1;		//temp = temp << 1,从高到低依次移出
		SDA = CY;		//CY为PSW状态寄存器中的最高位,1000 0000<<1,CY=1;0000 0001>>1,CY=1.CY就是移出来的那一位
		IIC_Delay();
		SCL = 1;		//等待SDA数据稳定
		IIC_Delay();
		SCL = 0;		//等待下一次发送
		IIC_Delay();
	}
	SDA = 1;	
	IIC_Delay();
}

unsigned char IIC_Read_Byte()		//读一个字节,从低位到高位读
{
	unsigned char i,j,k=0;
	SCL = 0;		//拉低时钟线,等待数据变化
	IIC_Delay();
	for(i=0;i<8;i++)
	{
		SCL = 1;		//在这个时刻已经获取到了SDA的一位数据
		IIC_Delay();
		if(SDA == 1)
			j = 1;
		else 
			j = 0;
		k = (k<<1) | j;			//k依次往右移,最低位每次接受新的SDA 变化
		SCL = 0;		//等待下一次数据变化
	}
	return(k);		//返回读到的字节数据
}

void delay(unsigned int m)			//做一个稍长一点的延时
{	unsigned int n;
  	for(n=0;n<m;n++);
}


void main()
{
	int a;		//将读到的数据送给a,通过a给P1口
	IIC_Init();		//IIC初始化
	IIC_Start();	//IIC起始信号
	IIC_Write_Byte(0xa0);	//写器件地址
	IIC_ACK();		//应答
	IIC_Write_Byte(0x00);		//写字节地址,24c02是256字节,不要超过最大地址
	IIC_ACK();
	IIC_Write_Byte(0x55);		//写数据
	IIC_ACK();
	IIC_Stop();
	
	delay(2000);
	IIC_Start();		
	IIC_Write_Byte(0xa0);		//写器件地址
	IIC_ACK();
	IIC_Write_Byte(0x00);		//数据地址
	IIC_ACK();
	IIC_Start();
	IIC_Write_Byte(0xa1);		//7位地址位,加上最低位读写位,允许读
	IIC_ACK();
	a = IIC_Read_Byte();
	IIC_Stop();
	P1 = ~a;		//让P1口的LED按写入的数据亮
	while(1);
	
}


在这里插入图片描述
最后,今天五四青年节,借鲁迅先生的一段话与大家共勉。

愿中国青年都摆脱冷气,只是向上走,不必听自暴自弃者流的话。能做事的做事,能发声的发声。有一分热,发一分光。就令萤火一般,也可以在黑暗里发一点光,不必等候炬火。 ——鲁迅 《热风·随感录四十一》

奔涌吧,后浪!

猜你喜欢

转载自blog.csdn.net/lqj11/article/details/105913128