I2C总线只有两根双向信号线。一根是数据线SDA,另一根是时钟线SCL。
I2C总线通过上拉电阻接正电源。当总线空闲时,两根线均为高电平。连到总线上的任一器件输出的低电平,都将使总线的信号变低,即各器件的SDA及SCL都是线“与”关系。
2.png
每个接到I2C总线上的器件都有唯一的地址。主机与其它器件间的数据传送可以是由主机发送数据到其它器件,这时主机即为发送器。由总线上接收数据的器件则为接收器。
起始和终止信号
SCL线为高电平期间,SDA线由高电平向低电平的变化表示起始信号;SCL线为高电平期间,SDA线由低电平向高电平的变化表示终止信号。
起始和终止信号都是由主机发出的,在起始信号产生后,总线就处于被占用的状态;在终止信号产生后,总线就处于空闲状态。
接收器件收到一个完整的数据字节后,有可能需要完成一些其它工作,如处理内部中断服务等,可能无法立刻接收下一个字节,这时接收器件可以将SCL线拉成低电平,从而使主机处于等待状态。直到接收器件准备好接收下一个字节时,再释放SCL线使之为高电平,从而使数据传送可以继续进行。
3.png
4.png
AT24CXX存储器工作原理
- 与400KHz I2C总线兼容
- 1.8到6.0伏工作电压范围
- 低功耗CMOS技术
- 写保护功能当WP为高电平时进入写保护状态
- 页写缓冲器
- 自定时擦写周期
- 100万次编程/擦除周期
- 可保存数据100年
- 8脚DIP SOIC或TSSOP封装
- 温度范围商业级和工业级
5.png
6.png
总线时序
7.png
8.png
9.png
代码:
实现:
k1:数码管数据存储到at24c01中
k2:显示at24c01中存储数据
k3:数码管数据加一
k4:数码管显示数据清零
main.c
#include "reg52.h"
#include "i2c.h"
typedef unsigned char u8;
typedef unsigned int u16;
sbit k1=P3^1;
sbit k2=P3^0;
sbit k3=P3^2;
sbit k4=P3^3;
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;
u8 code smgduan[]={
0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71
};
u8 num=0,disp[4];
void delayus(u16 i)
{
while(i--);
}
void keyPros()
{
if(k1==0)
{
delayus(1000);
if(k1==0)
{
at24c02Write(1,num); //写入地址1
}
while(!k1);
}
if(k2==0)
{
delayus(1000);
if(k2==0)
{
num=at24c02Read(1);
}
while(!k2);
}
if(k3==0)
{
delayus(1000);
if(k3==0)
{
num++;
if (num >255) num=0;
}
while(!k3);
}
if(k4==0)
{
delayus(1000);
if(k4==0)
{
num=0;
}
while(!k4);
}
}
void dataPros()
{
disp[0]=smgduan[num/1000];
disp[1]=smgduan[num%1000/100];
disp[2]=smgduan[num%100/10];
disp[3]=smgduan[num%10];
}
void smgDisplay()
{
u8 i;
for(i=0;i<4;i++)
{
switch(i)
{
case(0): LSC=0;LSB=0;LSA=0;break;
case(1): LSC=0;LSB=0;LSA=1;break;
case(2): LSC=0;LSB=1;LSA=0;break;
case(3): LSC=0;LSB=1;LSA=1;break;
}
P0=disp[3-i];
delayus(100);
P0=0x00;
}
}
void main()
{
while(1)
{
keyPros();
dataPros();
smgDisplay();
}
}
i2c.c
#include "i2c.h"
void delay10us(void) //误差 0us
{
unsigned char a,b;
for(b=1;b>0;b--)
for(a=2;a>0;a--);
}
void i2cStart()
{
SDA=1;
delay10us();
SCL=1;
delay10us();
SDA=0;
delay10us();
SCL=0;
delay10us();
}
void i2cStop()
{
SDA=0;
delay10us();
SCL=1;
delay10us();
SDA=1;
delay10us();
}
unsigned char i2cSendByte(unsigned char dat)
{
unsigned char a=0,b;
for(a=0;a<8;a++)
{
SDA=dat>>7;
dat=dat<<1;
delay10us();
SCL=1; //保持高电平
delay10us();
SCL=0;
delay10us();
}
SDA=1;
delay10us();
SCL=1;
while(SDA)
{
b++;
if(b>200)
{
SCL=0;
delay10us();
return 0;
}
}
SCL=0;
delay10us();
return 1;
}
unsigned char i2cReadByte()
{
unsigned char a=0,dat=0;
SDA=1; //使SDA保持空闲状态
delay10us();
for(a=0;a<8;a++)
{
SCL=1;
delay10us();
dat<<=1;
dat |=SDA;
delay10us();
SCL=0;
delay10us();
}
return dat;
}
void at24c02Write(unsigned char addr,unsigned char dat)
{
i2cStart();
i2cSendByte(0xa0);
i2cSendByte(addr);
i2cSendByte(dat);
i2cStop();
}
unsigned char at24c02Read(unsigned char addr)
{
unsigned char num;
i2cStart();
i2cSendByte(0xa0);
i2cSendByte(addr);
i2cStart();
i2cSendByte(0xa1);
num=i2cReadByte();
i2cStop();
return num;
}
i2c.h
#ifndef _I2C_H
#define _I2C_H
#include "reg52.h"
sbit SCL=P2^1;
sbit SDA=P2^0;
void at24c02Write(unsigned char addr,unsigned char dat);
unsigned char at24c02Read(unsigned char addr);
#endif
来源:CSDN
作者:acktomas
链接:https://blog.csdn.net/acktomas/article/details/104259078