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

2019-04-15 13:11发布

1.硬件连接

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

2.AT24C02读写时序说明:

(1)写数据描述:
通过IIC几种信号的组合,可以向AT24C02指定单元地址写一字节的数据。 这里写图片描述 可以看出,写顺序为:起始,写器件地址,应答,写单元地址,应答,写数据,应答,终止。
(2)读数据描述
这里写图片描述 从AT24C02任意单元地址读取数据,可以看出读写顺序为:起始,写器件地址(下一个字节为写),应答,写单元地址,应答,起始,写器件地址(下一个字节为读取),读取数据,终止。

3.例程实现

(1)延时
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--); }
(2)IIC模拟
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 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显示写入和读出的数据,分别测试单字节和字符串。 这里写图片描述