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

前言:

为了方便查看博客,特意申请了一个公众号,附上二维码,有兴趣的朋友可以关注,和我一起讨论学习,一起享受技术,一起成长。

在这里插入图片描述


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 <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显示写入和读出的数据,分别测试单字节和字符串。

这里写图片描述

  • 6
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值