网站首页 全球最实用的IT互联网站!

人工智能P2P分享Wind搜索发布信息网站地图标签大全

当前位置:诺佳网 > 电子/半导体 > 控制/MCU >

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

时间:2023-07-27 16:51

人气:

作者:admin

标签:

导读:在单片机应用系统中,串行通信总线技术是非常重要的通信手段。常用的串行总线通信方式包括异步串行通信 UART、I2C(Inter IC BUS)、单总线(One WIRE BUS)以及 SPI 总线(Serial Peripheral Inte...

概述

在单片机应用系统中,串行通信总线技术是非常重要的通信手段。常用的串行总线通信方式包括异步串行通信 UART、I2C(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芯片的使用。

温馨提示:以上内容整理于网络,仅供参考,如果对您有帮助,留下您的阅读感言吧!
相关阅读
本类排行
相关标签
本类推荐

CPU | 内存 | 硬盘 | 显卡 | 显示器 | 主板 | 电源 | 键鼠 | 网站地图

Copyright © 2025-2035 诺佳网 版权所有 备案号:赣ICP备2025066733号
本站资料均来源互联网收集整理,作品版权归作者所有,如果侵犯了您的版权,请跟我们联系。

关注微信