新闻中心

EEPW首页>嵌入式系统>设计应用> 51单片机 I2C AT24C02

51单片机 I2C AT24C02

作者: 时间:2016-11-25 来源:网络 收藏
I2C协议在项目开发中使用很常见,很多存储芯片使用I2C接口。由于51单片机没有I2C接口,这里使用IO口模拟I2C通讯协议,来完成I2C芯片驱动。使用的I2C芯片为AT24C02

原理图如下:

本文引用地址://m.amcfsurvey.com/article/201611/321316.htm



代码如下:

//程序功能:计时器每一秒向AT24C02保持数据,同时数码管显示,重启之后读取出数据接着计时,100S循环
//程序问题:无法写入
#include
#define uint unsigned int
#define uchar unsigned char
//变量定义
uint timer_flag;//用于判断定时器T0方式一是否计满1s
uchar shiwei,gewei;//数码管显示的十位与个位
uint number;
uchar time_date;//当前时间数据
//控制端口声明
sbit duanxuan=P2^6;//数码管段选端
sbit weixuan=P2^7;//数码管位选端
sbit AT24C02_SDA=P2^0;//AT24C02串行数据输入输出端口
sbit AT24C02_SCLK=P2^1;//时钟信号端口
//数码管显示数字段码定义
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
//相关函数声明
void delay_minute();//延时us级函数声明
void delay_xs(uint);//延时s级函数声明
void timer_init();//定时器T0方式一初始化函数声明
void AT24C02_init();//I^2C通讯总线初始化函数声明
void star();//I^2C通讯启动函数声明
void stop();//I^2C通讯停止函数声明
void response();//应答函数声明
void write_in_byte(uchar);//写入一个字节函数声明
uchar read_out_byte();//读出一个字节函数声明,函数放回到读出的值
//注意写入一个字节与写入数据的区别,前者是后者的一个子过程,读取同
void saveing(uchar,uchar);//向AT24C02保存数据函数声明
uchar load(uchar);//从AT24C02载入掉电之前的数据,函数放回到读出的值
void quwei(uchar);//显示数字取出各位与十位
void display(uchar);//数码管显示函数声明
//主函数
void main()
{
AT24C02_init();//AT24C02初始化
time_date=load(3);//开机首先载入AT24C02中的数据,这里读取的是第三位址的数据
if(time_date>100)//防止上一次保存的数据是100,这里计时是100循环的
{
time_date=1;
}
timer_init();//计时器T0方式一初始化
while(1)
{
display(time_date);//显示时间
if(timer_flag==1)//如果计满一秒,就保存时间数据
{
timer_flag=0;
saveing(3,time_date);//保存时间数据
}
}
}
//延时us级函数主体
void delay_minute()
{;;}
//延时s级函数主体
void delay_xs(uint s)
{
uint i,j;
for(i=s;i>0;i--)
{
for(j=110;j>0;j--)
{
}
}
}
//定时器T0方式一初始化函数主体
void timer_init()
{
//方式选择
TMOD=0x01;
//预装初值
TH0=(65536-46080)/256;
TL0=(65536-46080)%6;
//开中断
EA=1;
ET0=1;
//启动定时器
TR0=1;
}
//I^2C通讯总线初始化函数主体
void AT24C02_init()//两线均写1AT24C02数据有效规则,sclk为高电平且sda数据稳定,当sda发生有效数据变化时,sclk必须要是0
{
AT24C02_SDA=1;
delay_minute();
AT24C02_SCLK=1;
delay_minute();
}
//I^2C通讯启动函数主体
void star()//启动规则:SCLK-1,SDA下降沿
{
AT24C02_SDA=1;//一定要SDA首先为1,再是SCLK为1,否则会出现一个停止信号
delay_minute();
AT24C02_SCLK=1;
delay_minute();
AT24C02_SDA=0;
delay_minute();
}
//I^2C通讯停止函数主体
void stop()//停止规则:SCLK-1,SDA上升沿
{
AT24C02_SDA=0;//一定要SDA首先为0,再是SCLK为1,否则会出现一个启动信号
delay_minute();
AT24C02_SCLK=1;
delay_minute();
AT24C02_SDA=1;
delay_minute();
}
//应答函数主体
void response()//应答规则:SCLK-1,等待从机把SDA拉低
{
uint i;
AT24C02_SCLK=1;
delay_minute();
while(AT24C02_SDA==1&&i<255)//等待从机把SDA拉低,且超过一定时间没有应答,默认已经应答
{
i++;
}
AT24C02_SCLK=0;//应答之后,SCLK-0.防止数据误操作,因为SCLK-1,数据就是有效地
delay_minute();
}
//写入一个字节函数主体
void write_in_byte(uchar date)
{
uint i,buffer;//i用于循环发送每一位,buffer缓冲数据
buffer=date;
for(i=0;i<8;i++)
{
buffer=buffer<<1;//buffer左旋,高位就放入CY
AT24C02_SCLK=0;//有效发送规则:sclk-0变化数据,sclk-1数据稳定后有效
delay_minute();
AT24C02_SDA=CY;
delay_minute();
AT24C02_SCLK=1;
delay_minute();
}
AT24C02_SCLK=0;//不发送,一定是SCLK-0,SDA-1
delay_minute();
AT24C02_SDA=1;
delay_minute();
}
//读出一个字节函数主体
uchar read_out_byte()//读出规则:启动-控制字片选+写(为了写入要读取的地址)-应答-写入存储地址-应答-读取数据-应答-停止
{
uchar i,buffer_writting;
//--------------------------------------------------
//不能少的
AT24C02_SCLK=0;//方便SDA数据发生有效变化
delay_minute();
AT24C02_SDA=1;
delay_minute();
//--------------------------------------------------
for(i=0;i<8;i++)
{
AT24C02_SCLK=1;
delay_minute();
buffer_writting=(buffer_writting<<1)|AT24C02_SDA;//buffer_writting左旋之后与AT24C02_SDA的数据线与
delay_minute();
AT24C02_SCLK=0;
delay_minute();

}
return buffer_writting;
}
//向AT24C02保存数据函数主体
void saveing(uchar address,uchar time_date0)//写入字节规则:启动-控制字片选+写-应答-写入存储地址-应答-写入数据-应答-停止
{
star();//启动信号
write_in_byte(0xa0);
response();
write_in_byte(address);
response();
write_in_byte(time_date0);
response();
stop();
}
//从AT24C02载入掉电之前的数据函数主体
uchar load(uchar address)//读出规则:启动-控制字片选+写(为了写入要读取的地址)-应答-写入存储地址-应答-读取数据-应答-停止
{
uchar time_date_former;
star();
write_in_byte(0xa0);
response();
write_in_byte(address);
response();
time_date_former=read_out_byte();
stop();
return time_date_former;
}
//显示数字取出各位与十位函数主体
void quwei(uchar quwei_date)
{
shiwei=quwei_date/10;
gewei=quwei_date;
}
//数码管显示函数函数主体
void display(uchar display_date)
{
quwei(display_date);
//显示第一个数码管
duanxuan=1;
P0=table[shiwei];
duanxuan=0;
P0=0xff;
weixuan=1;
P0=0xfe;
weixuan=0;
delay_xs(2);
//显示第二的数码管
duanxuan=1;
P0=table[gewei];
duanxuan=0;
P0=0xff;
weixuan=1;
P0=0xfd;
weixuan=0;
delay_xs(2);
}
//T0定时器方式一中断服务程序
void T0_timer_no1()interrupt1
{
//预装初值
TH0=(65536-46080)/256;
TL0=(65536-46080)%6;
number++;
if(number==20)//20次计满就是1s
{
number=0;
time_date++;//时间累加
timer_flag=1;//计满一次就保存数据
if(time_date==100)//100s循环计时
{
time_date=0;
}
}
}
以上,结束。



关键词:51单片机I2CAT24C0

评论


技术专区

关闭