您的位置:首页 > 其它

学习笔记——51通过IO口模拟IIC实现AT24C02的读写

2017-08-29 22:55 696 查看

1.硬件连接



AT24C02是一个2K位串行CMOS E2PROM, 内部含有256个8位字节,CATALYST公司的先进CMOS技术实质上减少了器件的功耗。AT24C02有一个8字节页写缓冲器。该器件通过IIC总线接口进行操作,有一个专门的写保护功能。在单片机上的应用广泛, 可以实现掉电数据不丢失功能。

2.AT24C02读写时序说明:

[b](1)写数据描述:[/b]

通过IIC几种信号的组合,可以向AT24C02指定单元地址写一字节的数据。



可以看出,写顺序为:起始,写器件地址,应答,写单元地址,应答,写数据,应答,终止。

[b](2)读数据描述[/b]



从AT24C02任意单元地址读取数据,可以看出读写顺序为:起始,写器件地址(下一个字节为写),应答,写单元地址,应答,起始,写器件地址(下一个字节为读取),读取数据,终止。

3.例程实现

[b](1)延时[/b]

delay.h:

#ifndef _DELAY_H
#define _DELAY_H

#include "stc51.h"

void delay_us(uchar t);
void delay_ms(uint t);

#endif


#include "delay.h"
#include "stc51.h"
//Function:延时1us
//Input:延时的微秒数
//Output:无
//Return:无
//Others:无
void delay_us(uchar t)
{
while(t--);
}

//Function:延时1us
//Input:延时的毫秒数
//Output:无
//Return:无
//Others:无
void delay_ms(uint t)
{
uint x,y;
for(x=t;x>0;x--)
for(y=110;y>0;y--);
}


[b](2)IIC模拟[/b]

iic.h:

#ifndef _IIC_H
#define _IIC_H

#include "stc51.h"

/*IIC管脚定义*/
sbit IIC_SDA = P3^0;
sbit IIC_SCL = P3^1;

void IO_Init();
void IIC_Start();
void IIC_Stop();
void IIC_Ack();
void IIC_NAck();
void IIC_Write_Byte(uchar txd);
uchar IIC_Read_Byte();

#endif


iic.c:

#include "delay.h"
#include "iic.h"
#include "stc51.h"

//Function:初始化IO口
//Description:GPIO初始化为高,通知器件总线空闲
//Input:无
//Output:无
//Return:无
//Others:无
void IO_Init()
{
IIC_SCL = 1;
delay_us(5);
IIC_SDA = 1;
delay_us(5);
}

//Function:启动IIC传输
//Description:IIC_SCL为高时,IIC_SDA由高到低
//Input:无
//Output:无
//Return:无
//Others:无
void IIC_Start()
{
IIC_SDA = 1;
IIC_SCL = 1;
delay_us(5);
IIC_SDA = 0;
delay_us(5);
IIC_SCL = 0;
}

//Function:停止IIC传输
//Description:IIC_SCL为高时,IIC_SDA由低到高
//Input:无
//Output:无
//Return:无
//Others:无
void IIC_Stop()
{
IIC_SCL = 0;
IIC_SDA = 0;
delay_us(5);
IIC_SCL = 1;
IIC_SDA = 1;
delay_us(5);
}

//Function:产生应答信号
//Description:IIC_SCL为高时,IIC_SDA被拉低并保持一定时间的低电平
//Input:无
//Output:无
//Return:无
//Others:无
void IIC_Ack()
{
uchar i;

IIC_SCL = 1;//在scl为高电平期间等待应答
delay_ms(2);
while((IIC_SDA == 1) && i < 250)//若为应答0即退出,从机向主机发送应答信号
i++;//通过i自增等待一段时间
IIC_SCL = 0;//得到应答,拉低时钟
delay_ms(2);
}

//Function:产生非应答信号
//Description:IIC_SCL为高时,IIC_SDA为高
//Input:无
//Output:无
//Return:无
//Others:无
void IIC_NAck()
{
IIC_SCL = 1;
delay_ms(2);
IIC_SDA = 1;
IIC_SCL = 0;
delay_ms(2);
}

//Function:I2C写一个字节数据,返回ACK或者NACK
//Description:从高位开始依次传输
//Input:写的字节
//Output:无
//Return:无
//Others:无
void IIC_Write_Byte(uchar txd)
{
uchar len;

for (len=0;len<8;len++)
{
IIC_SCL = 0;//只有在IIC_SCL为低电平时,才允许IIC_SDA上的数据变化
delay_us(5);
if(txd & 0x80)
IIC_SDA = 1;
else
IIC_SDA = 0;
delay_us(5);
IIC_SCL = 1;//在IIC_SCL为高电平时,不允许IIC_SDA上的数据变化,使数据稳定
txd <<= 1;
delay_us(10);
IIC_SCL = 0;
delay_us(5);
}
IIC_SDA = 1;//释放总线
IIC_SCL = 1;
delay_us(5);
}

//Function:I2C读一个字节数据,返回ACK或者NACK
//Description:从高到低,依次接收
//Input:是否应答
//Output:无
//Return:接收的数据
//Others:无
uchar IIC_Read_Byte(/*uchar ack*/)
{
uchar len,dat = 0;

IIC_SDA = 1;//准备读取数据
for(len=0;len<8;len++)
{

IIC_SCL = 0;
delay_us(5);
IIC_SCL = 1;//不允许IIC_SDA变化
delay_us(5);
dat <<= 1;
dat |= IIC_SDA; //读数据
delay_us(5);
IIC_SCL = 0;//允许IIC_SDA变化等待下一位数据的到来
delay_us(5);
}

return dat;
}


(3)AT24C02实现:

at24c02.h:

#ifndef _AT24C02_H
#define _AT24C02_H

#include "stc51.h"

#define IIC_WADDR   0XA0
#define IIC_RADDR   0XA1

void AT24C02_Init(void);

void At24c02_Write_Byte(uchar addr,uchar dat);
uchar At24c02_Read_Byte(uchar addr);

void At24c02_Serial_Write(uchar Writeaddr,uchar *Str,uchar Len);
void At24c02_Serial_Read(uchar Readaddr,uchar *Str,uchar Len);

#endif


at24c02.c:

#include "iic.h"
#include "delay.h"
#include "at24c02.h"
#include "stc51.h"

//Function:初始化AT24C02
//Description:IO口属于空闲,准备开始通信
//Input:无
//Output:无
//Return:无
//Others:无
void AT24C02_Init(void)
{
IO_Init();
}

//Function:写一个字节
//Description:向AT24C02的任意地址写入一个字节数据
//Input:写入的地址和数据
//Output:无
//Return:无
//Others:无
void At24c02_Write_Byte(uchar addr,uchar dat)
{
IIC_Start();    //启动
IIC_Write_Byte(IIC_WADDR);  //发送从设备地址
IIC_Ack();  //等待从设备的响应
IIC_Write_Byte(addr);   //发出芯片内地址
IIC_Ack();  //等待从设备的响应
IIC_Write_Byte(dat);    //发送数据
IIC_Ack();  //等待从设备的响应
IIC_Stop(); //停止
delay_ms(10);    // 写入周期
}

//Function:指定地址读一个字节
//Description:向AT24C02的指定地址读出一个字节数据
//Input:读地址
//Output:无
//Return:读到的数据
//Others:无
uchar At24c02_Read_Byte(uchar addr)
{
uchar dat;

IIC_Start();
IIC_Write_Byte(IIC_WADDR);//发送发送从设备地址 写操作
IIC_Ack();
IIC_Write_Byte(addr);//发送芯片内地址
IIC_Ack();
IIC_Start();
IIC_Write_Byte(IIC_RADDR);//发送发送从设备地址 读操作
IIC_Ack();
dat = IIC_Read_Byte();//获取数据
IIC_Stop();

return dat;
}

//Function:任意地址写入一串数据
//Description:向AT24C02写入一串数据
//Input:写地址,写数据,数据长度
//Output:无
//Return:无
//Others:无
void At24c02_Serial_Write(uchar Writeaddr,uchar *Str,uchar Len)
{
while(Len--)
{
At24c02_Write_Byte(Writeaddr,*Str);
Writeaddr++;
Str++;
}
}

//Function:指定地址读出一串数据
//Description:向AT24C02读出一串数据
//Input:读地址,读数据,数据长度
//Output:无
//Return:无
//Others:无
void At24c02_Serial_Read(uchar Readaddr,uchar *Str,uchar Len)
{
while(Len)
{
*Str++ = At24c02_Read_Byte(Readaddr++);
Len--;
}
}


stc51.h:

#ifndef _STC51_H
#define _STC51_H

#include <reg52.h>

typedef unsigned char   uchar;
typedef unsigned int    uint;

#endif


主函数main.c:

#include "iic.h"
#include "at24c02.h"
#include "stc51.h"
#include "Lcd_4line.h"
#include "key.h"
#include "delay.h"

//要写入到24c02的字符串数组
const uchar TEXT_Buffer[]={"STC51"};
uchar TEXT_Buffer1[]={"00000"};//数组一定初始化

#define SIZE sizeof(TEXT_Buffer)

void main()
{
uchar dat = 8;
uchar Text = 6 + '0';
uchar val;

Lcd_1602_init();
AT24C02_Init();
while(1)
{
lcd_onestring(0,0,Text);
At24c02_Write_Byte(10,dat);
val = At24c02_Read_Byte(10);
val = val + '0';
lcd_onestring(1,0,val);

lcd_string(0,7,5,TEXT_Buffer);
At24c02_Serial_Write(10,TEXT_Buffer,5);
At24c02_Serial_Read(10,TEXT_Buffer1,5);
lcd_string(1,7,5,TEXT_Buffer1);
}
}


4.实验现象

通过LCD1602显示写入和读出的数据,分别测试单字节和字符串。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: