0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看威廉希尔官方网站 视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于单片机的I2C总线与AT24C01实验 I2C总线通信原理讲解

CHANBAEK 来源:RYMCU 作者:RYMCU 2023-07-27 16:51 次阅读

概述

单片机应用系统中,串行通信总线威廉希尔官方网站 是非常重要的通信手段。常用的串行总线通信方式包括异步串行通信 UARTI2C(Inter IC BUS)、单总线(One WIRE BUS)以及 SPI 总线(Serial Peripheral Interface BUS)等。单片机的串口通信为 UART 的一种,DS18B20 的通信方式为单总线。采用 I2C 总线通信方式的常用器件包括 E2PROM 存储器件 AT24C01 以及 AD/DA 器件 PCF8951,这章内容主要讲解 I2C 总线通信工作原理并结合 AT24C01 进行应用试验。

13.1 I2C 总线通信原理

I2C(Inter-Integrated Circuit)总线是由 PHILIP S 公司开发的两线式串行通信总线,由于连接主机以及外围设备。两根数据线一个为时钟线 SCL,另一根为数据线 SDA,可实现数据的发送或接收。通常将 I2C 通信速率分为:低速模式 100Kbit/s、快速模式 400Kbit/s 以及高速模式 3.4Mbit/s,I2C 器件为向下兼容模式,一般所用 I2C 器件均支持低速模式。I2C 通信器件典型电路如下图所示:
图片

如上图所示,在 I2C 总线上挂载多个外围器件,总线与电源之间配置了上拉电阻,使所有器件之间形成了“线与”的逻辑关系,任何一个器件将总线拉低,总线将保持低电平,因此任意一个器件都可以当成主设备或者从设备。

I2C 通信最底层的时序操作包含四种类型的信号,所用基于 I2C 总线的外围器件都是在这五种底层信号的基础上进行数据的读写,这五种信号分别是:

1) 起始信号;
2. 停止信号;
3. 写字节信号;
4. 读字节并发送应答信号;
5. 读字节并发送非应答信号。

13.1.1 I2C 通信起始、停止信号

起始信号,功能为通知 I2C 器件可以开始进行数据操作,操作时序为:当 SCL 为高电平时,SDA 由高电平向低电平跳变。停止信号,功能为通知 I2C 器件数据操作已结束,操作时序为:当 SCL 为高电平时,SDA 由低电平向高电平跳变。时序如下图所示:
图片
I2C 起始信号、停止信号时序 C 语言函数如下所示:

void Delay_I2C(void) 
{//延时函数,设置传输速率
	_nop_();
	_nop_();
	_nop_();
	_nop_();
}
//总线起始信号
void Start_I2C(void)
{
	//SCL高电平期间,拉低SDA
	SCL_I2C = 0;
	SDA_I2C = 1;//在SCL低电平期间先将SDA拉高,为起始信号做准备
	Delay_I2C();
	SCL_I2C = 1;
	Delay_I2C();		
	SDA_I2C = 0;//拉低SDA,发送起始信号
	Delay_I2C();	
	SCL_I2C = 0;
}
//总线停止信号
void Stop_I2C(void)
{
	//SCL高电平期间,拉高SDA
	SCL_I2C = 0;
	SDA_I2C = 0;//在SCL低电平期间先将SDA拉低,为停止信号做准备
	Delay_I2C();
	SCL_I2C = 1;
	Delay_I2C();		
	SDA_I2C = 1;//拉高SDA,发送停止信号
	Delay_I2C();	
	SCL_I2C = 0;	
}

13.1.2 I2C 写字节信号

I2C 写字节信号,功能为向总线写入 1 字节的数据,操作时序下图所示:
图片

在写入数据的过程中,数据顺序为从高位到低位,最先写入的数据为 bit7,依次到 bit0 共 8 位数据。如果接收器件收到了上述 1 字节的数据,会在 SCL 的第 9 个周期的高电平期间将 SDA 拉低为“0”,这个第 9 位数据称为应答位 ACK,作用为通知主机已经收到了 1 字节的数据。因此,在主机程序中通过 ACK 位判断 1 字节数据是否写入成功。在写数据的过程中要求,数据在 SCL 高电平期间要保持 SDA 数据稳定,在 SCL 低电平期间,SDA 可由高电平变为低电平或者低电平变为高电平,如下图所示。
图片
I2C 写字节信号 C 语言函数代码如下图所示:

//I2C写入字节dat,返回应答信号
bit Wr_I2C(unsigned char dat)
{
	bit ack; //存储应答位
	unsigned char mask;	//探测字节内某一位值的掩码变量

	for(mask=0x80;mask!=0;mask >>=1)//从高位依次到低位
	{
		if((mask & dat)==0) SDA_I2C=0;
		else                SDA_I2C=1;

		Delay_I2C();
		SCL_I2C = 1;
		Delay_I2C();		
		SCL_I2C = 0;  //完成一位的传送
	}

	SDA_I2C=1;	//主机释放总线
	Delay_I2C();
	SCL_I2C = 1;
	ack = SDA_I2C;//获取应答位
	Delay_I2C();
	SCL_I2C = 0;

	return ack; //返回0写入成功,返回1写入失败
}

13.1.3 I2C 读字节并发送应答信号

I2C 读字节并发送应答信号时序与图 13-4 基本相同,只不过 bit7-bit0 由 I2C 从器件给出,在 SCL 高电平期间主机将数据读取,第 9 位应答信号 ACK 由主机给出,ACK 为“0”表示主机后续还要继续读取数据,为“1”时主机不再读取后续数据,可以结束通信。C 语言函数如下图所示:

//I2C读操作,并发送应答信号
unsigned char RdACK_I2C(void)
{
	unsigned char mask;	//探测字节内某一位值的掩码变量
	unsigned char dat;

	 SDA_I2C=1;//确保主机释放SDA
	for(mask=0x80;mask!=0;mask >>=1)//从高位依次到低位
	{
		Delay_I2C();	
		SCL_I2C = 1;
		if(SDA_I2C==0) dat &= ~mask;//为0时,dat对应位清零
		else           dat |=  mask;//否则置1
		 Delay_I2C();
		 SCL_I2C = 0;
	 }
	SDA_I2C=0;	 //8位数据传送完后,拉低SDA发送应答信号
	Delay_I2C();
	SCL_I2C = 1;
	Delay_I2C();
	SCL_I2C = 0;

	return dat;
}

13.1.4 I2C 读字节并发送非应答信号

与读字节并发送应答信号相同,唯一的区别为主机发出非应答信号,即 ACK=1,主机不再读取后续数据,可以结束通信。C 语言函数如下图所示:

//I2C读操作,并发送非应答信号
unsigned char RdNAK_I2C(void)
{
	unsigned char mask;	//探测字节内某一位值的掩码变量
	unsigned char dat;

	 SDA_I2C=1;//确保主机释放SDA
	for(mask=0x80;mask!=0;mask >>=1)//从高位依次到低位
	{
		Delay_I2C();	
		SCL_I2C = 1;
		if(SDA_I2C==0) dat &= ~mask;//为0时,dat对应位清零
		else           dat |=  mask;//否则置1
		 Delay_I2C();
		 SCL_I2C = 0;
	 }
	SDA_I2C=1;	  //8位数据传送完后,拉高SDA发送非应答信号
	Delay_I2C();
	SCL_I2C = 1;
	Delay_I2C();
	SCL_I2C = 0;

	return dat;
}

将上述 5 个底层 I2C 总线操作函数放到文件“Drive_I2C.c”以及“Drive_I2C.h”。

“Drive_I2C.h”完整代码如下:

#ifndef __I2C_H__
#define __I2C_H__

extern void Start_I2C(void); //起始信号
extern void Stop_I2C(void);	 //停止信号
extern unsigned char RdACK_I2C(void); //读字节并发送应答信号
extern unsigned char RdNAK_I2C(void); //读字节并发送非应答信号
extern bit Wr_I2C(unsigned char dat); //读字节信号

#endif

“Drive_I2C.c”完整代码如下:

#include< reg52.h >
#include< intrins.h >


sbit SCL_I2C = P2^0;//总线管脚定义
sbit SDA_I2C = P2^1;

void Delay_I2C(void) 
{//延时函数,设置传输速率
	_nop_();
	_nop_();
	_nop_();
	_nop_();
}
//总线起始信号
void Start_I2C(void)
{
	//SCL高电平期间,拉低SDA
	SCL_I2C = 0;
	SDA_I2C = 1;//在SCL低电平期间先将SDA拉高,为起始信号做准备
	Delay_I2C();
	SCL_I2C = 1;
	Delay_I2C();		
	SDA_I2C = 0;//拉低SDA,发送起始信号
	Delay_I2C();	
	SCL_I2C = 0;
}
//总线停止信号
void Stop_I2C(void)
{
	//SCL高电平期间,拉高SDA
	SCL_I2C = 0;
	SDA_I2C = 0;//在SCL低电平期间先将SDA拉低,为停止信号做准备
	Delay_I2C();
	SCL_I2C = 1;
	Delay_I2C();		
	SDA_I2C = 1;//拉高SDA,发送停止信号
	Delay_I2C();	
	SCL_I2C = 0;	
}
//I2C写入字节dat,返回应答信号
bit Wr_I2C(unsigned char dat)
{
	bit ack; //存储应答位
	unsigned char mask;	//探测字节内某一位值的掩码变量

	for(mask=0x80;mask!=0;mask >>=1)//从高位依次到低位
	{
		if((mask & dat)==0) SDA_I2C=0;
		else                SDA_I2C=1;

		Delay_I2C();
		SCL_I2C = 1;
		Delay_I2C();		
		SCL_I2C = 0;  //完成一位的传送
	}

	SDA_I2C=1;	//主机释放总线
	Delay_I2C();
	SCL_I2C = 1;
	ack = SDA_I2C;//获取应答位
	Delay_I2C();
	SCL_I2C = 0;

	return ack; //返回0写入成功,返回1写入失败
}

//I2C读操作,并发送非应答信号
unsigned char RdNAK_I2C(void)
{
	unsigned char mask;	//探测字节内某一位值的掩码变量
	unsigned char dat;

	 SDA_I2C=1;//确保主机释放SDA
	for(mask=0x80;mask!=0;mask >>=1)//从高位依次到低位
	{
		Delay_I2C();	
		SCL_I2C = 1;
		if(SDA_I2C==0) dat &= ~mask;//为0时,dat对应位清零
		else           dat |=  mask;//否则置1
		 Delay_I2C();
		 SCL_I2C = 0;
	 }
	SDA_I2C=1;	  //8位数据传送完后,拉高SDA发送非应答信号
	Delay_I2C();
	SCL_I2C = 1;
	Delay_I2C();
	SCL_I2C = 0;

	return dat;
}

//I2C读操作,并发送应答信号
unsigned char RdACK_I2C(void)
{
	unsigned char mask;	//探测字节内某一位值的掩码变量
	unsigned char dat;

	 SDA_I2C=1;//确保主机释放SDA
	for(mask=0x80;mask!=0;mask >>=1)//从高位依次到低位
	{
		Delay_I2C();	
		SCL_I2C = 1;
		if(SDA_I2C==0) dat &= ~mask;//为0时,dat对应位清零
		else           dat |=  mask;//否则置1
		 Delay_I2C();
		 SCL_I2C = 0;
	 }
	SDA_I2C=0;	 //8位数据传送完后,拉低SDA发送应答信号
	Delay_I2C();
	SCL_I2C = 1;
	Delay_I2C();
	SCL_I2C = 0;

	return dat;
}

13.1.5 I2C 一次通信时序

所有基于 I2C 总线通信设备都是以上面 5 条最底层操作为基础的,完成一次完整的 I2C 通信时序如下图所示:
图片

如图所示,一次完整的 I2C 总线通信至少包含起始信号 、一次字节读或写,或者多次读或写,以及停止信号。在起始信号与停止信号之间读或写的具体内容与 I2C 器件本身的上层通信协议有关。接下来我们将讲解基于 I2C 总线通信威廉希尔官方网站 的 E2PROM 存储器 AT24C01 的上层通信协议以及具体使用实例。

13.2 E2PROM 存储器 AT24C01 应用

AT24C01 是 Atmel 公司生产的一款 E2PROM 数据存储器,容量为 128 字节,具有掉电不丢失的功能。在单片机中也有存储器,一种为数据存储器 RAM,一种为程序存储器,在掉电的情况下 RAM 内的数据会丢失,而程序存储器一般不支持在线编程。然而在很多应用场合我们希望把运行过程中重要的数据存储下来,而在掉电的情况下数据不丢失。AT24C01 能满足这样的要求,它与单片之间通过 I2C 总线通信实现信息的交换。
图片

下面介绍一下芯片管脚,A0~A2 为地址输入引脚,SDA、SCL 为 I2C 总线接口,VCC,GND 分别为电源和地,WP 为写保护管脚,当 WP 接高电平时,禁止外部对它进行写数据,只能读取它的数据。如上图所示,将 WP 接地,单片机即可对它进行读也可以写。

13.2.1 AT24C01 单字节写通信

AT24C01 写字节如下图所示:
图片

如上图所示,AT24C01 的写字节时序步骤如下:

1)起始信号;
2. 写器件地址;
3. 写存储地址;
4. 写存储数据;
5. 停止信号。

当 I2C 总线上挂载多个从器件时,单片机通过器件地址来区别器件,那在我们开发板上的 AT24C01 的器件地址是多少呢?AT24C01 器件地址如下所示:
图片
如上图所示,地址的高 4 位为“1010”固定值,即 0x5,后四位分别由 A2-A0、R/W 决定,在 RY-51 开发板上将器件的 A2-A0 都接地,如原理图所示,因此为“000”,最后一位为读写方向位,当 R/W=0 时,表示我们接下来写数据,当 R/W=1 时,表示我们接下来要读数据。很显然我们这里是要写数据,因此 R/W=0。合并起来,要写的地址为 0x50。第 3 步为写存储器地址,AT24C01 总共有 128 字节的存储器,它的地址分别为 0x00~0x80,因此可以选择任一地址存入数据。第 4 步为写存储数据,即为你写存储的 8 位数据。总结上述,往 AT24C01 写入一个字节数据函数如下所示:

//往AT24C01地址addr写入单字节数据dat
void WrByte_AT24C01(unsigned char addr,unsigned char dat)
{
	Start_I2C();
	Wr_I2C(0x50< < 1);//通知地址50的器件,接下来写操作
	Wr_I2C(addr);  	//写入要操作的地址addr
	Wr_I2C(dat);		//向addr写入数据dat
	Stop_I2C();
}

13.2.2 AT24C01 单字节读通信

随机读取 AT24C01 单字节通信如下图所示:
图片
随机读取单字节数据通信协议如上图所示,步骤如下:

1) 起始信号
2. 写器件地址,方向为写;
3. 写存储器地址 addr;
4. 起始信号;
5. 写器件地址,方向为读;
6. 读单字节数据,并发送非应答信号
7. 停止信号。

第 1 步至第 3 步为告诉 AT24C01 我将从地址 addr 处读取数据,第 4 步到第 6 步为读取存储器地址 addr 处的数据,并告诉 AT24C01 后面不再继续读数据了,第 7 步结束本次通信。具体函数代码如下图所示:

//读取AT24C01存储地址addr处的数据
unsigned char RdByte_AT24C01(unsigned char addr)
{
	unsigned char dat;	

	Start_I2C();
	Wr_I2C(0x50< < 1);//通知地址50的器件,接下来写操作
	Wr_I2C(addr); //写入要操作的地址addr
	Start_I2C();
	Wr_I2C((0x50< < 1)|0x01);//通知地址50的器件,接下来读操作
	dat = RdNAK_I2C();//从地址addr读出数据,读出数据后不应答E2Prom
	Stop_I2C();

	return dat;
}

到这里我们便完成了对 AT24C01 单字节的读、写通信函数,按照惯例我们将函数封装到“Drive_AT 24C01.c”、“Drive_AT 24C01.h”,如下。

Drive_AT 24C01.h 代码:

#ifndef __AT24C01_H__
#define __AT24C02_H__

extern void WrByte_AT24C01(unsigned char addr,unsigned char dat);//写单字节
extern unsigned char RdByte_AT24C01(unsigned char addr); //读单字节
extern void WrStr_AT24C01(unsigned char *str,unsigned char addr,unsigned char len);//写多字节
extern void RdStr_AT24C01(unsigned char *str,unsigned char addr,unsigned char len);//读多字节

#endif

Drive_AT 24C01.c 代码:

#include< reg52.h >
#include"Drive_I2C.h"

//往AT24C01地址addr写入单字节数据dat
void WrByte_AT24C01(unsigned char addr,unsigned char dat)
{
	Start_I2C();
	Wr_I2C(0x50< < 1);//通知地址50的器件,接下来写操作
	Wr_I2C(addr);  	//写入要操作的地址addr
	Wr_I2C(dat);		//向addr写入数据dat
	Stop_I2C();
}
//读取AT24C01存储地址addr处的数据
unsigned char RdByte_AT24C01(unsigned char addr)
{
	unsigned char dat;	

	Start_I2C();
	Wr_I2C(0x50< < 1);//通知地址50的器件,接下来写操作
	Wr_I2C(addr); //写入要操作的地址addr
	Start_I2C();
	Wr_I2C((0x50< < 1)|0x01);//通知地址50的器件,接下来读操作
	dat = RdNAK_I2C();//从地址addr读出数据,读出数据后不应答E2Prom
	Stop_I2C();

	return dat;
}
//多字节写
void WrStr_AT24C01(unsigned char *str,unsigned char addr,unsigned char len)
{
	while(len > 0)//检测上一次是否完成所以数据写操作
	{	
		while(1)
		{//循环检测器件应答信号
			Start_I2C();
			if(0 == Wr_I2C(0x50< < 1)) break;//收到应答,跳出循环
			Stop_I2C();//没收到应答,发送停止信号,继续循环检测
		}
		Wr_I2C(addr); //写入要操作的初始地址addr
		
		while(len > 0)
		{
			Wr_I2C(*str++);//写入一个字节,并将字符串指针指向下一个字符
			len--;//字符数减1
			addr++;//存储地址加1	
			if(0 == (addr & 0x07))//检测是否到达了下一页的起始地址,
				break;			//即上一个字节已经写到页的最后边界了
				           		//跳出停止继续写,每页的起始地址后3位为0
								//因此判断addr后3为是否为0即可	   
		}
		Stop_I2C();	
	}			
}
//多字节读
void RdStr_AT24C01(unsigned char *str,unsigned char addr,unsigned char len)
{
	while(1)
	{//循环检测器件应答信号
		Start_I2C();
		if(0 == Wr_I2C(0x50< < 1)) break;//收到应答,跳出循环
		Stop_I2C();//没收到应答,发送停止信号,继续循环检测
	}
	Wr_I2C(addr); //写入要操作的初始地址addr
    Start_I2C();//再次发送起始信号
	Wr_I2C((0x50< < 1)|0x01);//通知地址50的器件,接下来读操作
	while(len > 1)
	{
		*str++ = RdACK_I2C();//读字节并应答
		len--;
	}
	*str = RdNAK_I2C();//最后一个字节,读字节并非应答
	Stop_I2C();		
}
//寻址AT24C01
bit Addressing_AT24C01(unsigned char addr)
{
	bit ack;

	Start_I2C();
	ack =  Wr_I2C(addr< < 1);
	Stop_I2C();

	return ack;
}

如上所示,所有的代码都是以 I2C 通信的 5 个底层函数为基础的,因此我们需要将“Drive_I2C.h”文件包含到代码中。

13.2.3 AT24C01 单字节读写应用

下面我们建立一个工程,写一个实例来展示单片机对 AT24C01 的读写应用。应用的功能为首先往 AT24C01 存储器地址 0x08 处写入数据 110,然后从该处把数据读出来显示在 1602 液晶上,以此来验证读写操作的正确性,主文件“MainAT24C01.c”代码如下所示:

#include < reg52.h >
#include"Drive_AT24C01.h" //包含AT24C01头文件
#include"Drive_1602.h"

#define uchar unsigned char
#define  uint unsigned int

sbit DU = P2^7;//数码管段选、位选引脚定义
sbit WE = P2^6;	
uchar str[10]=0;
void main()
{
	uchar dat=0;
	Init_1602();
	P0 = 0xff;//关闭所有数码
	WE = 1;
	WE = 0;

	//往AT24C01存储器地址0x08处写入数字110
	WrByte_AT24C01(0x08,110);
	Disp_1602_str(1,2,"AT24C02 test!");
	//读取AT24C01存储器地址0x08处的数据
	dat = RdByte_AT24C01(0x08);

	str[0]=dat/100+'0';
	str[1]=dat%100/10+'0';
	str[2]=dat%10+'0';
	//将数据显示在1602的第2行第6列处
	Disp_1602_str(2,6,str);

	while(1);
}

将工程编译后,下载到开发板验证功能的正确性。

AT24C01 对写时序有一个特殊的要求,当完成一次数据通信后,需要延迟 tWR 才能开始下一次起始信号如下图所示,tWR 为 AT24C01 内部处理数据时间,查询 AT24C01 数据手册可知为 10ms。因此,我们在主程序代码第 19 行与第 22 行之间插入了第 20 行代码达到延时的目的,我们可以将第 20 行代码挪到后面测试一下效果。
图片

13.2.4 AT24C01 多字节写通信

根据上面的介绍,大家很容易发现每隔 10ms 才能进行一次正常的写数据操作是非常浪费时间的,尤其是在进行多个字节写操作的时候。AT24C01 提供了另外一种多字节的写模式,为页操作模式。首先介绍一下 AT24C01 的内部存储器的分页结构。AT24C01 总共有 128 个字节的存储空间,总共分为 16 页,每一页总有 8 各字节。第一页的地址范围为 0x00~0x07,依次往下均分为 16 页。页操作模式通信时序如下图所示:

图片

如上如所示,首先发送起始信号、写器件地址、写起始地址,紧接着写入多个字节,写完一个字节,器件内部会将地址自动加 1,最后结束信号。这里需要注意的是,连续写的多个字节必须在同一页内,不能进行跨页连续读写,因此一次通信周期内最多可以写入 8 个字节的数据。如果我们需要写的数据很多,而一页写不下怎么办?首先,启动页写通信,在写的过程中判断是否要写到页的边界了,当到达页边界后停止该次页写通信,再重新发起页写通信将剩余的数据写入,这样便实现了任意个字节的写入,具体函数如下图所示。其中,str 为需要写入的字符串,addr 为写入 AT24C01 的起始地址,len 为写入字符个数。多字节写数据代码如下:

//多字节写
void WrStr_AT24C01(unsigned char *str,unsigned char addr,unsigned char len)
{
	while(len > 0)//检测上一次是否完成所以数据写操作
	{	
		while(1)
		{//循环检测器件应答信号
			Start_I2C();
			if(0 == Wr_I2C(0x50< < 1)) break;//收到应答,跳出循环
			Stop_I2C();//没收到应答,发送停止信号,继续循环检测
		}
		Wr_I2C(addr); //写入要操作的初始地址addr
		
		while(len > 0)
		{
			Wr_I2C(*str++);//写入一个字节,并将字符串指针指向下一个字符
			len--;//字符数减1
			addr++;//存储地址加1	
			if(0 == (addr & 0x07))//检测是否到达了下一页的起始地址,
				break;			//即上一个字节已经写到页的最后边界了
				           		//跳出停止继续写,每页的起始地址后3位为0
								//因此判断addr后3为是否为0即可	   
		}
		Stop_I2C();	
	}			
}

13.2.5 AT24C01 多字节读通信

多字节读时序如下图所示,与单字节类似,只是在第一个数据紧接着着读取多个数据,这里要注意的是只有最后一个字节的数据发送非应答信号,前面的数据均发送应答信号,这个也很好理解,应为我们都到最后一个字节时要告诉 AT24C01 我们不再继续读数据了,因此发送非应答信号。

图片
多字节读取函数代码如下图所示:

//多字节读
void RdStr_AT24C01(unsigned char *str,unsigned char addr,unsigned char len)
{
	while(1)
	{//循环检测器件应答信号
		Start_I2C();
		if(0 == Wr_I2C(0x50< < 1)) break;//收到应答,跳出循环
		Stop_I2C();//没收到应答,发送停止信号,继续循环检测
	}
	Wr_I2C(addr); //写入要操作的初始地址addr
    Start_I2C();//再次发送起始信号
	Wr_I2C((0x50< < 1)|0x01);//通知地址50的器件,接下来读操作
	while(len > 1)
	{
		*str++ = RdACK_I2C();//读字节并应答
		len--;
	}
	*str = RdNAK_I2C();//最后一个字节,读字节并非应答
	Stop_I2C();		
}

将上述的多字节写、多字节读取函数添加到驱动文件“Drive_AT 24C01.c”、“Drive_AT 24C01.h”中,后续应用中只需要将文件添加到项目中,调用相关的函数就可以了。

13.2.6 AT24C01 多字节读写应用

本小节实现 AT24C01 多字节的读写应用,先向 AT24C01 连续写入多字节数据,然后将数据读出显示在 1602 液晶显示模块上,验证读写的正确性。主程序代码如下所示:

#include < reg52.h >
#include"Drive_AT24C01.h" //包含AT24C01头文件
#include"Drive_1602.h"

#define uchar unsigned char
#define  uint unsigned int

sbit DU = P2^7;//数码管段选、位选引脚定义
sbit WE = P2^6;	

uchar str1[]="AT24c01 Wr Str!";
uchar str2[20];

void main()
{
	uchar dat=0;
	P0 = 0;//关闭所有数码管
	WE = 1;
	WE = 0;

	Init_1602();//1602初始化

	WrStr_AT24C01(str1,0x05,16);//写入16个字节
	RdStr_AT24C01(str2,0x05,16);//读取16个字节

	Disp_1602_str(1,1,str2); //将数据从第一行第一列开始显示

	while(1);
}

如代码所示,从地址 0x05 开始写入 16 个字节的数据,由于 AT24C01 为 8 个字节为一页,因此本次为横跨了 3 页的写操作,有效的验证的多字节的写操作。

13.3 本章小结

本章详细介绍了I2C总线的通信原理,以及驱动函数的编写,AT24C01芯片的使用。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 单片机
    +关注

    关注

    6036

    文章

    44556

    浏览量

    634966
  • uart
    +关注

    关注

    22

    文章

    1235

    浏览量

    101377
  • I2C总线
    +关注

    关注

    8

    文章

    390

    浏览量

    60923
  • 总线通信
    +关注

    关注

    0

    文章

    49

    浏览量

    11830
  • AT24C01
    +关注

    关注

    0

    文章

    3

    浏览量

    5252
收藏 人收藏

    评论

    相关推荐

    i2c总线ppt(I2C总线器件应用)

    I2C总线器件应用第一节 I2C总线器件应用概述I2C总线工作原理
    发表于 08-13 17:34 0次下载

    亿恒C166 系列单片机I2C 总线的软件模拟

    亿恒C166 系列单片机I2C 总线的软件模拟
    发表于 05-14 16:11 6次下载

    基于I2C总线的单主多从单片机之间的通信

    介绍了作者所设计的基于I2C 总线的测试系统的结构及I2C 总线通信协议的特点,给出了I2C
    发表于 12-19 17:06 108次下载

    什么是i2c总线

    什么是i2c总线  下载请点击: i2c总线协议中文版 
    发表于 11-05 09:26 2921次阅读

    I2C总线单片机C语言实现及其应用

    I2C总线单片机C语言实现及其应用 本文介绍了I2C总线的概念、接口特性和传输时序,提出了一
    发表于 10-17 08:36 2972次阅读
    <b class='flag-5'>I2C</b><b class='flag-5'>总线</b>的<b class='flag-5'>单片机</b><b class='flag-5'>C</b>语言实现及其应用

    PIC单片机I2C 24LC02 C读写程序

    PIC单片机I2C 24LC02 C读写程序 1   I2C总线特点 &
    发表于 10-30 08:27 5395次阅读

    AVR单片机I2C总线实验

     AVR单片机I2C总线实验。 1、用24C02记录CPU启动次数,并在PB口上显示出来。 
    发表于 06-30 11:27 2058次阅读

    基于CPLD的I2C总线接口设计

    在电路设计中,I2C总线是比较常用的两线式串行通信方式,大多数的CPU都擅长于并口操作,不具备直接操作I2C总线接口的能力。为了使不具备
    发表于 02-12 16:11 95次下载
    基于CPLD的<b class='flag-5'>I2C</b><b class='flag-5'>总线</b>接口设计

    i2c

    单片机i2c总线操作;单片机i2c总线操作;单片机
    发表于 05-17 11:09 35次下载

    基于I2C总线的单主多从通信

    基于I2C总线的单主多从单片机之间的通信
    发表于 08-30 16:03 13次下载
    基于<b class='flag-5'>I2C</b><b class='flag-5'>总线</b>的单主多从<b class='flag-5'>通信</b>

    80C51单片机模拟I2C总线的主机程序分享

    I2C总线协议程序 在使用的过程中一定要注意时序、时间的问题。 i2c.c /* I2C.c 标准80C51
    发表于 12-05 15:39 3435次阅读
    80<b class='flag-5'>C</b>51<b class='flag-5'>单片机</b>模拟<b class='flag-5'>I2C</b><b class='flag-5'>总线</b>的主机程序分享

    基于MCS-51单片机I2C总线接口电路的设计

    单片机控制系统中,广泛使用I2C器件。如果单片机自带I2C总线接口,则所有I2C器件对应连接到
    发表于 10-15 16:13 3407次阅读
    基于MCS-51<b class='flag-5'>单片机</b><b class='flag-5'>I2C</b><b class='flag-5'>总线</b>接口电路的设计

    使用单片机实现I2C总线实验文件免费下载

    本文档的主要内容详细介绍的是使用单片机实现I2C总线实验文件免费下载。
    发表于 03-24 11:11 7次下载

    I2C总线的基本通信总结

    在电子设计开发中I2C大家已经很熟悉了,每一种电子产品小到电子开关,大到卫星通信都会利用的I2C总线。据统计I2C在电子产品中占据了93%的
    的头像 发表于 08-26 14:08 1.8w次阅读
    <b class='flag-5'>I2C</b><b class='flag-5'>总线</b>的基本<b class='flag-5'>通信</b>总结

    51单片机——I2C总线

    本文主要介绍I2C总线协议时序图,并介绍I2C总线的数据传送格式,最后介绍了I2C总线存储器
    发表于 11-23 16:22 13次下载
    51<b class='flag-5'>单片机</b>——<b class='flag-5'>I2C</b><b class='flag-5'>总线</b>