在本文中,主要描述了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的高低电平值,可以改变器件的地址。
读写操作:
写:
- 发送起始信号
- 写器件地址
- 应答
- 数据地址
- 应答
- 写数据
- 应答
- 结束信号
读:
- 起始信号
- 写器件地址
- 应答
- 写数据地址
- 应答
- 起始信号
- 写数据地址加读写位
- 读出数据
- 直接停止,没有应答
程序实例
现在对着时序图来写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);
}
最后,今天五四青年节,借鲁迅先生的一段话与大家共勉。
愿中国青年都摆脱冷气,只是向上走,不必听自暴自弃者流的话。能做事的做事,能发声的发声。有一分热,发一分光。就令萤火一般,也可以在黑暗里发一点光,不必等候炬火。 ——鲁迅 《热风·随感录四十一》
奔涌吧,后浪!