IIC
- Inter IC Bus
- 由数据线SDA和时钟线SCL构成,采用漏记开路结构和总线连接,因此SCL和SDA均需接上拉电阻,总线在空闲状态为高电平,任一器件输出低电平都可拉低总线。
- IIC在数据传输时,时钟信号为高电平期间,数据线上的数据必须保持稳定。
信号
- 发送启动信号,在SCL高电平期间,SDA出现下降沿。
- 发送寻址信号,7位地址寻址时,高7位为地址位,最低位为方向位,0表示主机对从机进行写操作,1表示主机对从机进行读操作。主机发送地址时,总线上的从机都根据7位地址码与自己的地址进行比较,相同即认为自己正被主机寻址,根据R/W确定自己为发送器或者接收器。
| 位序号 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|
| :----: | :----: | :----: | :----: | :----: | :----: | :----: | :----: | :R/W: |
- 应答信号,应答信号由接收设备产生,在SCL信号为高电平期间,接收设备将SDA拉为低电平,表示数据传输正确,产生应答。
- 停止信号,在SCL为高电平期间,SDA出现上升沿。
延时
void delay() //延时4-5us
{;;}
void delay1ms(uint z)
{
uint x,y;
for(x=z;x>0;x--)
{
for(y=110;y>0;y--);
}
}
初始化
//总线初始化
void init() //总线在初始状态下保持高电平
{
SCL=1;
delay();
SDA=1;
delay();
}
启动信号
//启动信号
void start() //SCL在高电平期间,SDA出现下降沿
{
SDA=1;
delay();
SCL=1;
delay();
SDA=0;
delay();
}
应答信号
//应答信号
void respon() //SCL为高电平期间,SDA被从设备拉低
{
uchar i=0;
SCL=1;
delay();
while((SDA==1)&&(i<255))
{
i++;
}
SCL=0;
delay();
}
停止信号
//停止信号
void stop() //SCL在高电平期间,SDA出现上升沿信号
{
SDA=0;
delay();
SCL=1;
delay();
SDA=1;
delay();
}
写一个字节
//写一个字节
void write_byte(uchar date)
{
uchar i,temp;
temp=date;
for(i=0;i<8;i++)
{
temp=temp<<1; //temp左移一位,最高位移入寄存器PSW的CY位,赋值给SDA
SCL=0; //IIC在进行数据传送时,SCL为高电平期间,SDA需保持稳定,因此拉低SCL
delay();
SDA=CY;
delay();
SCL=1;
delay();
}
SCL=0;
delay();
SDA=1;
delay();
}
读一个字节
//读一个字节
uchar read_byte()
{
uchar i,k;
SCL=0;
delay();
SDA=1;
for(i=0;i<8;i++)
{
SCL=1;
delay();
k=(k<<1)|SDA;
SCL=0;
delay();
}
delay();
return k;
}
EEPROM-AT24C02

- WP:写保护输入端,用于硬件数据保护,当其为低电平时,可以对整个存储器进行正常的读写操作,当其为高电平时,存储器具有写保护功能,读操作不受影响。
//例程:
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
bit write=0; //写24C02的标志
sbit SDA=P2^0;
sbit SCL=P2^1;
sbit dula=P2^6;
sbit wela=P2^7;
uchar sec,tcnt;
unsigned char code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71,
};
void delay() //延时4-5us
{;;}
void delay1ms(uint z)
{
uint x,y;
for(x=z;x>0;x--)
{
for(y=110;y>0;y--);
}
}
//总线初始化
void init() //总线在初始状态下保持高电平
{
SCL=1;
delay();
SDA=1;
delay();
}
//启动信号
void start() //SCL在高电平期间,SDA出现下降沿
{
SDA=1;
delay();
SCL=1;
delay();
SDA=0;
delay();
}
//应答信号
void respon() //SCL为高电平期间,SDA被从设备拉低
{
uchar i=0;
SCL=1;
delay();
while((SDA==1)&&(i<255))
{
i++;
}
SCL=0;
delay();
}
//停止信号
void stop() //SCL在高电平期间,SDA出现上升沿信号
{
SDA=0;
delay();
SCL=1;
delay();
SDA=1;
delay();
}
//写一个字节
void write_byte(uchar date)
{
uchar i,temp;
temp=date;
for(i=0;i<8;i++)
{
temp=temp<<1; //temp左移一位,最高位移入寄存器PSW的CY位,赋值给SDA
SCL=0; //IIC在进行数据传送时,SCL为高电平期间,SDA需保持稳定,因此拉低SCL
delay();
SDA=CY;
delay();
SCL=1;
delay();
}
SCL=0;
delay();
SDA=1;
delay();
}
//读一个字节
uchar read_byte()
{
uchar i,k;
SCL=0;
delay();
SDA=1;
for(i=0;i<8;i++)
{
SCL=1;
delay();
k=(k<<1)|SDA;
SCL=0;
delay();
}
delay();
return k;
}
void write_add(uchar address,uchar date)
{
start();
write_byte(0xa0); //1010 0000 AT24C02的芯片地址1010 A2 A1 A0 R/W
respon();
write_byte(address); //器件内部地址
respon();
write_byte(date); //数据
respon();
stop();
}
uchar read_add(uchar address)
{
uchar date;
start();
write_byte(0xa0);
respon();
write_byte(address);
respon();
start();
write_byte(0xa1);
respon();
date=read_byte();
stop();
return date;
}
void display(uchar bai_c,uchar sh_c) //显示程序
{
wela=0;
dula=0; //关闭段选锁存器
wela=1; //选中位选锁存器
P0=0x7e; //0111 1110 第一位数码管使能
wela=0; //关闭位选锁存
P0=0xff;
dula=1; //打开段选锁存器
P0=table[bai_c]; //显示第一位数据
dula=0; //关闭段选锁存器
delay1ms(5);
wela=1; //选中位选锁存器
P0=0x7d; //0111 1101 第二位数码管使能
wela=0; //关闭位选锁存
P0=0xff;
dula=1; //打开段选锁存器
P0=table[sh_c]; //显示第二位数据
dula=0; //关闭段选锁存器
delay1ms(5);
}
void main()
{
init(); //初始化,拉高IIC总线
sec=read_add(2); //读出保存的数据赋值给sec
if(sec>100) //防止读出数据为3位造成两位数码管显示乱码
{
sec=0;
}
TMOD=0x01; //0000 0001 定时器T0,工作方式1:16为定时器/计数器
ET0=1; //中断允许寄存器IE 定时器/计数器0中断允许位
EA=1; //中断允许寄存器IE 全局中断打开
TH0=(65536-45872)/256;
TL0=(65536-45872)%256; //50ms中断一次
TR0=1; //定时器控制寄存器TCON 启动定时器1
while(1)
{
display(sec/10,sec%10);
if(write==1) //判断计时器是否计时1s
{
write=0; //清0
write_add(2,sec); //在24C02的地址2写入数据sec
}
}
}
void t0() interrupt 1
{
TH0=(65536-45872)/256;
TL0=(65536-45872)%256;
tcnt++; //0.05sx20=1s
if(tcnt==20) //1s写一次24C02
{
tcnt=0; //清0
sec++; //每隔1s,sec加1,定时1s
write=1; //写24C02
if(sec==100) //到100s后归零
{
sec=0;
}
}
}