色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

基于單片機(jī)的I2C總線與AT24C01實(shí)驗(yàn) I2C總線通信原理講解

CHANBAEK ? 來(lái)源:RYMCU ? 作者:RYMCU ? 2023-07-27 16:51 ? 次閱讀

概述

單片機(jī)應(yīng)用系統(tǒng)中,串行通信總線技術(shù)是非常重要的通信手段。常用的串行總線通信方式包括異步串行通信 UARTI2C(Inter IC BUS)、單總線(One WIRE BUS)以及 SPI 總線(Serial Peripheral Interface BUS)等。單片機(jī)的串口通信為 UART 的一種,DS18B20 的通信方式為單總線。采用 I2C 總線通信方式的常用器件包括 E2PROM 存儲(chǔ)器件 AT24C01 以及 AD/DA 器件 PCF8951,這章內(nèi)容主要講解 I2C 總線通信工作原理并結(jié)合 AT24C01 進(jìn)行應(yīng)用試驗(yàn)。

13.1 I2C 總線通信原理

I2C(Inter-Integrated Circuit)總線是由 PHILIP S 公司開(kāi)發(fā)的兩線式串行通信總線,由于連接主機(jī)以及外圍設(shè)備。兩根數(shù)據(jù)線一個(gè)為時(shí)鐘線 SCL,另一根為數(shù)據(jù)線 SDA,可實(shí)現(xiàn)數(shù)據(jù)的發(fā)送或接收。通常將 I2C 通信速率分為:低速模式 100Kbit/s、快速模式 400Kbit/s 以及高速模式 3.4Mbit/s,I2C 器件為向下兼容模式,一般所用 I2C 器件均支持低速模式。I2C 通信器件典型電路如下圖所示:
圖片

如上圖所示,在 I2C 總線上掛載多個(gè)外圍器件,總線與電源之間配置了上拉電阻,使所有器件之間形成了“線與”的邏輯關(guān)系,任何一個(gè)器件將總線拉低,總線將保持低電平,因此任意一個(gè)器件都可以當(dāng)成主設(shè)備或者從設(shè)備。

I2C 通信最底層的時(shí)序操作包含四種類(lèi)型的信號(hào),所用基于 I2C 總線的外圍器件都是在這五種底層信號(hào)的基礎(chǔ)上進(jìn)行數(shù)據(jù)的讀寫(xiě),這五種信號(hào)分別是:

1) 起始信號(hào);
2. 停止信號(hào);
3. 寫(xiě)字節(jié)信號(hào);
4. 讀字節(jié)并發(fā)送應(yīng)答信號(hào);
5. 讀字節(jié)并發(fā)送非應(yīng)答信號(hào)。

13.1.1 I2C 通信起始、停止信號(hào)

起始信號(hào),功能為通知 I2C 器件可以開(kāi)始進(jìn)行數(shù)據(jù)操作,操作時(shí)序?yàn)椋寒?dāng) SCL 為高電平時(shí),SDA 由高電平向低電平跳變。停止信號(hào),功能為通知 I2C 器件數(shù)據(jù)操作已結(jié)束,操作時(shí)序?yàn)椋寒?dāng) SCL 為高電平時(shí),SDA 由低電平向高電平跳變。時(shí)序如下圖所示:
圖片
I2C 起始信號(hào)、停止信號(hào)時(shí)序 C 語(yǔ)言函數(shù)如下所示:

void Delay_I2C(void) 
{//延時(shí)函數(shù),設(shè)置傳輸速率
	_nop_();
	_nop_();
	_nop_();
	_nop_();
}
//總線起始信號(hào)
void Start_I2C(void)
{
	//SCL高電平期間,拉低SDA
	SCL_I2C = 0;
	SDA_I2C = 1;//在SCL低電平期間先將SDA拉高,為起始信號(hào)做準(zhǔn)備
	Delay_I2C();
	SCL_I2C = 1;
	Delay_I2C();		
	SDA_I2C = 0;//拉低SDA,發(fā)送起始信號(hào)
	Delay_I2C();	
	SCL_I2C = 0;
}
//總線停止信號(hào)
void Stop_I2C(void)
{
	//SCL高電平期間,拉高SDA
	SCL_I2C = 0;
	SDA_I2C = 0;//在SCL低電平期間先將SDA拉低,為停止信號(hào)做準(zhǔn)備
	Delay_I2C();
	SCL_I2C = 1;
	Delay_I2C();		
	SDA_I2C = 1;//拉高SDA,發(fā)送停止信號(hào)
	Delay_I2C();	
	SCL_I2C = 0;	
}

13.1.2 I2C 寫(xiě)字節(jié)信號(hào)

I2C 寫(xiě)字節(jié)信號(hào),功能為向總線寫(xiě)入 1 字節(jié)的數(shù)據(jù),操作時(shí)序下圖所示:
圖片

在寫(xiě)入數(shù)據(jù)的過(guò)程中,數(shù)據(jù)順序?yàn)閺母呶坏降臀唬钕葘?xiě)入的數(shù)據(jù)為 bit7,依次到 bit0 共 8 位數(shù)據(jù)。如果接收器件收到了上述 1 字節(jié)的數(shù)據(jù),會(huì)在 SCL 的第 9 個(gè)周期的高電平期間將 SDA 拉低為“0”,這個(gè)第 9 位數(shù)據(jù)稱(chēng)為應(yīng)答位 ACK,作用為通知主機(jī)已經(jīng)收到了 1 字節(jié)的數(shù)據(jù)。因此,在主機(jī)程序中通過(guò) ACK 位判斷 1 字節(jié)數(shù)據(jù)是否寫(xiě)入成功。在寫(xiě)數(shù)據(jù)的過(guò)程中要求,數(shù)據(jù)在 SCL 高電平期間要保持 SDA 數(shù)據(jù)穩(wěn)定,在 SCL 低電平期間,SDA 可由高電平變?yōu)榈碗娖交蛘叩碗娖阶優(yōu)楦唠娖剑缦聢D所示。
圖片
I2C 寫(xiě)字節(jié)信號(hào) C 語(yǔ)言函數(shù)代碼如下圖所示:

//I2C寫(xiě)入字節(jié)dat,返回應(yīng)答信號(hào)
bit Wr_I2C(unsigned char dat)
{
	bit ack; //存儲(chǔ)應(yīng)答位
	unsigned char mask;	//探測(cè)字節(jié)內(nèi)某一位值的掩碼變量

	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;	//主機(jī)釋放總線
	Delay_I2C();
	SCL_I2C = 1;
	ack = SDA_I2C;//獲取應(yīng)答位
	Delay_I2C();
	SCL_I2C = 0;

	return ack; //返回0寫(xiě)入成功,返回1寫(xiě)入失敗
}

13.1.3 I2C 讀字節(jié)并發(fā)送應(yīng)答信號(hào)

I2C 讀字節(jié)并發(fā)送應(yīng)答信號(hào)時(shí)序與圖 13-4 基本相同,只不過(guò) bit7-bit0 由 I2C 從器件給出,在 SCL 高電平期間主機(jī)將數(shù)據(jù)讀取,第 9 位應(yīng)答信號(hào) ACK 由主機(jī)給出,ACK 為“0”表示主機(jī)后續(xù)還要繼續(xù)讀取數(shù)據(jù),為“1”時(shí)主機(jī)不再讀取后續(xù)數(shù)據(jù),可以結(jié)束通信。C 語(yǔ)言函數(shù)如下圖所示:

//I2C讀操作,并發(fā)送應(yīng)答信號(hào)
unsigned char RdACK_I2C(void)
{
	unsigned char mask;	//探測(cè)字節(jié)內(nèi)某一位值的掩碼變量
	unsigned char dat;

	 SDA_I2C=1;//確保主機(jī)釋放SDA
	for(mask=0x80;mask!=0;mask >>=1)//從高位依次到低位
	{
		Delay_I2C();	
		SCL_I2C = 1;
		if(SDA_I2C==0) dat &= ~mask;//為0時(shí),dat對(duì)應(yīng)位清零
		else           dat |=  mask;//否則置1
		 Delay_I2C();
		 SCL_I2C = 0;
	 }
	SDA_I2C=0;	 //8位數(shù)據(jù)傳送完后,拉低SDA發(fā)送應(yīng)答信號(hào)
	Delay_I2C();
	SCL_I2C = 1;
	Delay_I2C();
	SCL_I2C = 0;

	return dat;
}

13.1.4 I2C 讀字節(jié)并發(fā)送非應(yīng)答信號(hào)

與讀字節(jié)并發(fā)送應(yīng)答信號(hào)相同,唯一的區(qū)別為主機(jī)發(fā)出非應(yīng)答信號(hào),即 ACK=1,主機(jī)不再讀取后續(xù)數(shù)據(jù),可以結(jié)束通信。C 語(yǔ)言函數(shù)如下圖所示:

//I2C讀操作,并發(fā)送非應(yīng)答信號(hào)
unsigned char RdNAK_I2C(void)
{
	unsigned char mask;	//探測(cè)字節(jié)內(nèi)某一位值的掩碼變量
	unsigned char dat;

	 SDA_I2C=1;//確保主機(jī)釋放SDA
	for(mask=0x80;mask!=0;mask >>=1)//從高位依次到低位
	{
		Delay_I2C();	
		SCL_I2C = 1;
		if(SDA_I2C==0) dat &= ~mask;//為0時(shí),dat對(duì)應(yīng)位清零
		else           dat |=  mask;//否則置1
		 Delay_I2C();
		 SCL_I2C = 0;
	 }
	SDA_I2C=1;	  //8位數(shù)據(jù)傳送完后,拉高SDA發(fā)送非應(yīng)答信號(hào)
	Delay_I2C();
	SCL_I2C = 1;
	Delay_I2C();
	SCL_I2C = 0;

	return dat;
}

將上述 5 個(gè)底層 I2C 總線操作函數(shù)放到文件“Drive_I2C.c”以及“Drive_I2C.h”。

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

#ifndef __I2C_H__
#define __I2C_H__

extern void Start_I2C(void); //起始信號(hào)
extern void Stop_I2C(void);	 //停止信號(hào)
extern unsigned char RdACK_I2C(void); //讀字節(jié)并發(fā)送應(yīng)答信號(hào)
extern unsigned char RdNAK_I2C(void); //讀字節(jié)并發(fā)送非應(yīng)答信號(hào)
extern bit Wr_I2C(unsigned char dat); //讀字節(jié)信號(hào)

#endif

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

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


sbit SCL_I2C = P2^0;//總線管腳定義
sbit SDA_I2C = P2^1;

void Delay_I2C(void) 
{//延時(shí)函數(shù),設(shè)置傳輸速率
	_nop_();
	_nop_();
	_nop_();
	_nop_();
}
//總線起始信號(hào)
void Start_I2C(void)
{
	//SCL高電平期間,拉低SDA
	SCL_I2C = 0;
	SDA_I2C = 1;//在SCL低電平期間先將SDA拉高,為起始信號(hào)做準(zhǔn)備
	Delay_I2C();
	SCL_I2C = 1;
	Delay_I2C();		
	SDA_I2C = 0;//拉低SDA,發(fā)送起始信號(hào)
	Delay_I2C();	
	SCL_I2C = 0;
}
//總線停止信號(hào)
void Stop_I2C(void)
{
	//SCL高電平期間,拉高SDA
	SCL_I2C = 0;
	SDA_I2C = 0;//在SCL低電平期間先將SDA拉低,為停止信號(hào)做準(zhǔn)備
	Delay_I2C();
	SCL_I2C = 1;
	Delay_I2C();		
	SDA_I2C = 1;//拉高SDA,發(fā)送停止信號(hào)
	Delay_I2C();	
	SCL_I2C = 0;	
}
//I2C寫(xiě)入字節(jié)dat,返回應(yīng)答信號(hào)
bit Wr_I2C(unsigned char dat)
{
	bit ack; //存儲(chǔ)應(yīng)答位
	unsigned char mask;	//探測(cè)字節(jié)內(nèi)某一位值的掩碼變量

	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;	//主機(jī)釋放總線
	Delay_I2C();
	SCL_I2C = 1;
	ack = SDA_I2C;//獲取應(yīng)答位
	Delay_I2C();
	SCL_I2C = 0;

	return ack; //返回0寫(xiě)入成功,返回1寫(xiě)入失敗
}

//I2C讀操作,并發(fā)送非應(yīng)答信號(hào)
unsigned char RdNAK_I2C(void)
{
	unsigned char mask;	//探測(cè)字節(jié)內(nèi)某一位值的掩碼變量
	unsigned char dat;

	 SDA_I2C=1;//確保主機(jī)釋放SDA
	for(mask=0x80;mask!=0;mask >>=1)//從高位依次到低位
	{
		Delay_I2C();	
		SCL_I2C = 1;
		if(SDA_I2C==0) dat &= ~mask;//為0時(shí),dat對(duì)應(yīng)位清零
		else           dat |=  mask;//否則置1
		 Delay_I2C();
		 SCL_I2C = 0;
	 }
	SDA_I2C=1;	  //8位數(shù)據(jù)傳送完后,拉高SDA發(fā)送非應(yīng)答信號(hào)
	Delay_I2C();
	SCL_I2C = 1;
	Delay_I2C();
	SCL_I2C = 0;

	return dat;
}

//I2C讀操作,并發(fā)送應(yīng)答信號(hào)
unsigned char RdACK_I2C(void)
{
	unsigned char mask;	//探測(cè)字節(jié)內(nèi)某一位值的掩碼變量
	unsigned char dat;

	 SDA_I2C=1;//確保主機(jī)釋放SDA
	for(mask=0x80;mask!=0;mask >>=1)//從高位依次到低位
	{
		Delay_I2C();	
		SCL_I2C = 1;
		if(SDA_I2C==0) dat &= ~mask;//為0時(shí),dat對(duì)應(yīng)位清零
		else           dat |=  mask;//否則置1
		 Delay_I2C();
		 SCL_I2C = 0;
	 }
	SDA_I2C=0;	 //8位數(shù)據(jù)傳送完后,拉低SDA發(fā)送應(yīng)答信號(hào)
	Delay_I2C();
	SCL_I2C = 1;
	Delay_I2C();
	SCL_I2C = 0;

	return dat;
}

13.1.5 I2C 一次通信時(shí)序

所有基于 I2C 總線通信設(shè)備都是以上面 5 條最底層操作為基礎(chǔ)的,完成一次完整的 I2C 通信時(shí)序如下圖所示:
圖片

如圖所示,一次完整的 I2C 總線通信至少包含起始信號(hào) 、一次字節(jié)讀或?qū)懀蛘叨啻巫x或?qū)懀约巴V剐盘?hào)。在起始信號(hào)與停止信號(hào)之間讀或?qū)懙木唧w內(nèi)容與 I2C 器件本身的上層通信協(xié)議有關(guān)。接下來(lái)我們將講解基于 I2C 總線通信技術(shù)的 E2PROM 存儲(chǔ)器 AT24C01 的上層通信協(xié)議以及具體使用實(shí)例。

13.2 E2PROM 存儲(chǔ)器 AT24C01 應(yīng)用

AT24C01 是 Atmel 公司生產(chǎn)的一款 E2PROM 數(shù)據(jù)存儲(chǔ)器,容量為 128 字節(jié),具有掉電不丟失的功能。在單片機(jī)中也有存儲(chǔ)器,一種為數(shù)據(jù)存儲(chǔ)器 RAM,一種為程序存儲(chǔ)器,在掉電的情況下 RAM 內(nèi)的數(shù)據(jù)會(huì)丟失,而程序存儲(chǔ)器一般不支持在線編程。然而在很多應(yīng)用場(chǎng)合我們希望把運(yùn)行過(guò)程中重要的數(shù)據(jù)存儲(chǔ)下來(lái),而在掉電的情況下數(shù)據(jù)不丟失。AT24C01 能滿(mǎn)足這樣的要求,它與單片之間通過(guò) I2C 總線通信實(shí)現(xiàn)信息的交換。
圖片

下面介紹一下芯片管腳,A0~A2 為地址輸入引腳,SDA、SCL 為 I2C 總線接口,VCC,GND 分別為電源和地,WP 為寫(xiě)保護(hù)管腳,當(dāng) WP 接高電平時(shí),禁止外部對(duì)它進(jìn)行寫(xiě)數(shù)據(jù),只能讀取它的數(shù)據(jù)。如上圖所示,將 WP 接地,單片機(jī)即可對(duì)它進(jìn)行讀也可以寫(xiě)。

13.2.1 AT24C01 單字節(jié)寫(xiě)通信

AT24C01 寫(xiě)字節(jié)如下圖所示:
圖片

如上圖所示,AT24C01 的寫(xiě)字節(jié)時(shí)序步驟如下:

1)起始信號(hào);
2. 寫(xiě)器件地址;
3. 寫(xiě)存儲(chǔ)地址;
4. 寫(xiě)存儲(chǔ)數(shù)據(jù);
5. 停止信號(hào)。

當(dāng) I2C 總線上掛載多個(gè)從器件時(shí),單片機(jī)通過(guò)器件地址來(lái)區(qū)別器件,那在我們開(kāi)發(fā)板上的 AT24C01 的器件地址是多少呢?AT24C01 器件地址如下所示:
圖片
如上圖所示,地址的高 4 位為“1010”固定值,即 0x5,后四位分別由 A2-A0、R/W 決定,在 RY-51 開(kāi)發(fā)板上將器件的 A2-A0 都接地,如原理圖所示,因此為“000”,最后一位為讀寫(xiě)方向位,當(dāng) R/W=0 時(shí),表示我們接下來(lái)寫(xiě)數(shù)據(jù),當(dāng) R/W=1 時(shí),表示我們接下來(lái)要讀數(shù)據(jù)。很顯然我們這里是要寫(xiě)數(shù)據(jù),因此 R/W=0。合并起來(lái),要寫(xiě)的地址為 0x50。第 3 步為寫(xiě)存儲(chǔ)器地址,AT24C01 總共有 128 字節(jié)的存儲(chǔ)器,它的地址分別為 0x00~0x80,因此可以選擇任一地址存入數(shù)據(jù)。第 4 步為寫(xiě)存儲(chǔ)數(shù)據(jù),即為你寫(xiě)存儲(chǔ)的 8 位數(shù)據(jù)。總結(jié)上述,往 AT24C01 寫(xiě)入一個(gè)字節(jié)數(shù)據(jù)函數(shù)如下所示:

//往AT24C01地址addr寫(xiě)入單字節(jié)數(shù)據(jù)dat
void WrByte_AT24C01(unsigned char addr,unsigned char dat)
{
	Start_I2C();
	Wr_I2C(0x50< 1);//通知地址50的器件,接下來(lái)寫(xiě)操作
	Wr_I2C(addr);  	//寫(xiě)入要操作的地址addr
	Wr_I2C(dat);		//向addr寫(xiě)入數(shù)據(jù)dat
	Stop_I2C();
}

13.2.2 AT24C01 單字節(jié)讀通信

隨機(jī)讀取 AT24C01 單字節(jié)通信如下圖所示:
圖片
隨機(jī)讀取單字節(jié)數(shù)據(jù)通信協(xié)議如上圖所示,步驟如下:

1) 起始信號(hào)
2. 寫(xiě)器件地址,方向?yàn)閷?xiě);
3. 寫(xiě)存儲(chǔ)器地址 addr;
4. 起始信號(hào);
5. 寫(xiě)器件地址,方向?yàn)樽x;
6. 讀單字節(jié)數(shù)據(jù),并發(fā)送非應(yīng)答信號(hào)
7. 停止信號(hào)。

第 1 步至第 3 步為告訴 AT24C01 我將從地址 addr 處讀取數(shù)據(jù),第 4 步到第 6 步為讀取存儲(chǔ)器地址 addr 處的數(shù)據(jù),并告訴 AT24C01 后面不再繼續(xù)讀數(shù)據(jù)了,第 7 步結(jié)束本次通信。具體函數(shù)代碼如下圖所示:

//讀取AT24C01存儲(chǔ)地址addr處的數(shù)據(jù)
unsigned char RdByte_AT24C01(unsigned char addr)
{
	unsigned char dat;	

	Start_I2C();
	Wr_I2C(0x50< 1);//通知地址50的器件,接下來(lái)寫(xiě)操作
	Wr_I2C(addr); //寫(xiě)入要操作的地址addr
	Start_I2C();
	Wr_I2C((0x50< 1)|0x01);//通知地址50的器件,接下來(lái)讀操作
	dat = RdNAK_I2C();//從地址addr讀出數(shù)據(jù),讀出數(shù)據(jù)后不應(yīng)答E2Prom
	Stop_I2C();

	return dat;
}

到這里我們便完成了對(duì) AT24C01 單字節(jié)的讀、寫(xiě)通信函數(shù),按照慣例我們將函數(shù)封裝到“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);//寫(xiě)單字節(jié)
extern unsigned char RdByte_AT24C01(unsigned char addr); //讀單字節(jié)
extern void WrStr_AT24C01(unsigned char *str,unsigned char addr,unsigned char len);//寫(xiě)多字節(jié)
extern void RdStr_AT24C01(unsigned char *str,unsigned char addr,unsigned char len);//讀多字節(jié)

#endif

Drive_AT 24C01.c 代碼:

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

//往AT24C01地址addr寫(xiě)入單字節(jié)數(shù)據(jù)dat
void WrByte_AT24C01(unsigned char addr,unsigned char dat)
{
	Start_I2C();
	Wr_I2C(0x50< 1);//通知地址50的器件,接下來(lái)寫(xiě)操作
	Wr_I2C(addr);  	//寫(xiě)入要操作的地址addr
	Wr_I2C(dat);		//向addr寫(xiě)入數(shù)據(jù)dat
	Stop_I2C();
}
//讀取AT24C01存儲(chǔ)地址addr處的數(shù)據(jù)
unsigned char RdByte_AT24C01(unsigned char addr)
{
	unsigned char dat;	

	Start_I2C();
	Wr_I2C(0x50< 1);//通知地址50的器件,接下來(lái)寫(xiě)操作
	Wr_I2C(addr); //寫(xiě)入要操作的地址addr
	Start_I2C();
	Wr_I2C((0x50< 1)|0x01);//通知地址50的器件,接下來(lái)讀操作
	dat = RdNAK_I2C();//從地址addr讀出數(shù)據(jù),讀出數(shù)據(jù)后不應(yīng)答E2Prom
	Stop_I2C();

	return dat;
}
//多字節(jié)寫(xiě)
void WrStr_AT24C01(unsigned char *str,unsigned char addr,unsigned char len)
{
	while(len > 0)//檢測(cè)上一次是否完成所以數(shù)據(jù)寫(xiě)操作
	{	
		while(1)
		{//循環(huán)檢測(cè)器件應(yīng)答信號(hào)
			Start_I2C();
			if(0 == Wr_I2C(0x50< 1)) break;//收到應(yīng)答,跳出循環(huán)
			Stop_I2C();//沒(méi)收到應(yīng)答,發(fā)送停止信號(hào),繼續(xù)循環(huán)檢測(cè)
		}
		Wr_I2C(addr); //寫(xiě)入要操作的初始地址addr
		
		while(len > 0)
		{
			Wr_I2C(*str++);//寫(xiě)入一個(gè)字節(jié),并將字符串指針指向下一個(gè)字符
			len--;//字符數(shù)減1
			addr++;//存儲(chǔ)地址加1	
			if(0 == (addr & 0x07))//檢測(cè)是否到達(dá)了下一頁(yè)的起始地址,
				break;			//即上一個(gè)字節(jié)已經(jīng)寫(xiě)到頁(yè)的最后邊界了
				           		//跳出停止繼續(xù)寫(xiě),每頁(yè)的起始地址后3位為0
								//因此判斷addr后3為是否為0即可	   
		}
		Stop_I2C();	
	}			
}
//多字節(jié)讀
void RdStr_AT24C01(unsigned char *str,unsigned char addr,unsigned char len)
{
	while(1)
	{//循環(huán)檢測(cè)器件應(yīng)答信號(hào)
		Start_I2C();
		if(0 == Wr_I2C(0x50< 1)) break;//收到應(yīng)答,跳出循環(huán)
		Stop_I2C();//沒(méi)收到應(yīng)答,發(fā)送停止信號(hào),繼續(xù)循環(huán)檢測(cè)
	}
	Wr_I2C(addr); //寫(xiě)入要操作的初始地址addr
    Start_I2C();//再次發(fā)送起始信號(hào)
	Wr_I2C((0x50< 1)|0x01);//通知地址50的器件,接下來(lái)讀操作
	while(len > 1)
	{
		*str++ = RdACK_I2C();//讀字節(jié)并應(yīng)答
		len--;
	}
	*str = RdNAK_I2C();//最后一個(gè)字節(jié),讀字節(jié)并非應(yīng)答
	Stop_I2C();		
}
//尋址AT24C01
bit Addressing_AT24C01(unsigned char addr)
{
	bit ack;

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

	return ack;
}

如上所示,所有的代碼都是以 I2C 通信的 5 個(gè)底層函數(shù)為基礎(chǔ)的,因此我們需要將“Drive_I2C.h”文件包含到代碼中。

13.2.3 AT24C01 單字節(jié)讀寫(xiě)應(yīng)用

下面我們建立一個(gè)工程,寫(xiě)一個(gè)實(shí)例來(lái)展示單片機(jī)對(duì) AT24C01 的讀寫(xiě)應(yīng)用。應(yīng)用的功能為首先往 AT24C01 存儲(chǔ)器地址 0x08 處寫(xiě)入數(shù)據(jù) 110,然后從該處把數(shù)據(jù)讀出來(lái)顯示在 1602 液晶上,以此來(lái)驗(yàn)證讀寫(xiě)操作的正確性,主文件“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;//數(shù)碼管段選、位選引腳定義
sbit WE = P2^6;	
uchar str[10]=0;
void main()
{
	uchar dat=0;
	Init_1602();
	P0 = 0xff;//關(guān)閉所有數(shù)碼
	WE = 1;
	WE = 0;

	//往AT24C01存儲(chǔ)器地址0x08處寫(xiě)入數(shù)字110
	WrByte_AT24C01(0x08,110);
	Disp_1602_str(1,2,"AT24C02 test!");
	//讀取AT24C01存儲(chǔ)器地址0x08處的數(shù)據(jù)
	dat = RdByte_AT24C01(0x08);

	str[0]=dat/100+'0';
	str[1]=dat%100/10+'0';
	str[2]=dat%10+'0';
	//將數(shù)據(jù)顯示在1602的第2行第6列處
	Disp_1602_str(2,6,str);

	while(1);
}

將工程編譯后,下載到開(kāi)發(fā)板驗(yàn)證功能的正確性。

AT24C01 對(duì)寫(xiě)時(shí)序有一個(gè)特殊的要求,當(dāng)完成一次數(shù)據(jù)通信后,需要延遲 tWR 才能開(kāi)始下一次起始信號(hào)如下圖所示,tWR 為 AT24C01 內(nèi)部處理數(shù)據(jù)時(shí)間,查詢(xún) AT24C01 數(shù)據(jù)手冊(cè)可知為 10ms。因此,我們?cè)谥?a target="_blank">程序代碼第 19 行與第 22 行之間插入了第 20 行代碼達(dá)到延時(shí)的目的,我們可以將第 20 行代碼挪到后面測(cè)試一下效果。
圖片

13.2.4 AT24C01 多字節(jié)寫(xiě)通信

根據(jù)上面的介紹,大家很容易發(fā)現(xiàn)每隔 10ms 才能進(jìn)行一次正常的寫(xiě)數(shù)據(jù)操作是非常浪費(fèi)時(shí)間的,尤其是在進(jìn)行多個(gè)字節(jié)寫(xiě)操作的時(shí)候。AT24C01 提供了另外一種多字節(jié)的寫(xiě)模式,為頁(yè)操作模式。首先介紹一下 AT24C01 的內(nèi)部存儲(chǔ)器的分頁(yè)結(jié)構(gòu)。AT24C01 總共有 128 個(gè)字節(jié)的存儲(chǔ)空間,總共分為 16 頁(yè),每一頁(yè)總有 8 各字節(jié)。第一頁(yè)的地址范圍為 0x00~0x07,依次往下均分為 16 頁(yè)。頁(yè)操作模式通信時(shí)序如下圖所示:

圖片

如上如所示,首先發(fā)送起始信號(hào)、寫(xiě)器件地址、寫(xiě)起始地址,緊接著寫(xiě)入多個(gè)字節(jié),寫(xiě)完一個(gè)字節(jié),器件內(nèi)部會(huì)將地址自動(dòng)加 1,最后結(jié)束信號(hào)。這里需要注意的是,連續(xù)寫(xiě)的多個(gè)字節(jié)必須在同一頁(yè)內(nèi),不能進(jìn)行跨頁(yè)連續(xù)讀寫(xiě),因此一次通信周期內(nèi)最多可以寫(xiě)入 8 個(gè)字節(jié)的數(shù)據(jù)。如果我們需要寫(xiě)的數(shù)據(jù)很多,而一頁(yè)寫(xiě)不下怎么辦?首先,啟動(dòng)頁(yè)寫(xiě)通信,在寫(xiě)的過(guò)程中判斷是否要寫(xiě)到頁(yè)的邊界了,當(dāng)?shù)竭_(dá)頁(yè)邊界后停止該次頁(yè)寫(xiě)通信,再重新發(fā)起頁(yè)寫(xiě)通信將剩余的數(shù)據(jù)寫(xiě)入,這樣便實(shí)現(xiàn)了任意個(gè)字節(jié)的寫(xiě)入,具體函數(shù)如下圖所示。其中,str 為需要寫(xiě)入的字符串,addr 為寫(xiě)入 AT24C01 的起始地址,len 為寫(xiě)入字符個(gè)數(shù)。多字節(jié)寫(xiě)數(shù)據(jù)代碼如下:

//多字節(jié)寫(xiě)
void WrStr_AT24C01(unsigned char *str,unsigned char addr,unsigned char len)
{
	while(len > 0)//檢測(cè)上一次是否完成所以數(shù)據(jù)寫(xiě)操作
	{	
		while(1)
		{//循環(huán)檢測(cè)器件應(yīng)答信號(hào)
			Start_I2C();
			if(0 == Wr_I2C(0x50< 1)) break;//收到應(yīng)答,跳出循環(huán)
			Stop_I2C();//沒(méi)收到應(yīng)答,發(fā)送停止信號(hào),繼續(xù)循環(huán)檢測(cè)
		}
		Wr_I2C(addr); //寫(xiě)入要操作的初始地址addr
		
		while(len > 0)
		{
			Wr_I2C(*str++);//寫(xiě)入一個(gè)字節(jié),并將字符串指針指向下一個(gè)字符
			len--;//字符數(shù)減1
			addr++;//存儲(chǔ)地址加1	
			if(0 == (addr & 0x07))//檢測(cè)是否到達(dá)了下一頁(yè)的起始地址,
				break;			//即上一個(gè)字節(jié)已經(jīng)寫(xiě)到頁(yè)的最后邊界了
				           		//跳出停止繼續(xù)寫(xiě),每頁(yè)的起始地址后3位為0
								//因此判斷addr后3為是否為0即可	   
		}
		Stop_I2C();	
	}			
}

13.2.5 AT24C01 多字節(jié)讀通信

多字節(jié)讀時(shí)序如下圖所示,與單字節(jié)類(lèi)似,只是在第一個(gè)數(shù)據(jù)緊接著著讀取多個(gè)數(shù)據(jù),這里要注意的是只有最后一個(gè)字節(jié)的數(shù)據(jù)發(fā)送非應(yīng)答信號(hào),前面的數(shù)據(jù)均發(fā)送應(yīng)答信號(hào),這個(gè)也很好理解,應(yīng)為我們都到最后一個(gè)字節(jié)時(shí)要告訴 AT24C01 我們不再繼續(xù)讀數(shù)據(jù)了,因此發(fā)送非應(yīng)答信號(hào)。

圖片
多字節(jié)讀取函數(shù)代碼如下圖所示:

//多字節(jié)讀
void RdStr_AT24C01(unsigned char *str,unsigned char addr,unsigned char len)
{
	while(1)
	{//循環(huán)檢測(cè)器件應(yīng)答信號(hào)
		Start_I2C();
		if(0 == Wr_I2C(0x50< 1)) break;//收到應(yīng)答,跳出循環(huán)
		Stop_I2C();//沒(méi)收到應(yīng)答,發(fā)送停止信號(hào),繼續(xù)循環(huán)檢測(cè)
	}
	Wr_I2C(addr); //寫(xiě)入要操作的初始地址addr
    Start_I2C();//再次發(fā)送起始信號(hào)
	Wr_I2C((0x50< 1)|0x01);//通知地址50的器件,接下來(lái)讀操作
	while(len > 1)
	{
		*str++ = RdACK_I2C();//讀字節(jié)并應(yīng)答
		len--;
	}
	*str = RdNAK_I2C();//最后一個(gè)字節(jié),讀字節(jié)并非應(yīng)答
	Stop_I2C();		
}

將上述的多字節(jié)寫(xiě)、多字節(jié)讀取函數(shù)添加到驅(qū)動(dòng)文件“Drive_AT 24C01.c”、“Drive_AT 24C01.h”中,后續(xù)應(yīng)用中只需要將文件添加到項(xiàng)目中,調(diào)用相關(guān)的函數(shù)就可以了。

13.2.6 AT24C01 多字節(jié)讀寫(xiě)應(yīng)用

本小節(jié)實(shí)現(xiàn) AT24C01 多字節(jié)的讀寫(xiě)應(yīng)用,先向 AT24C01 連續(xù)寫(xiě)入多字節(jié)數(shù)據(jù),然后將數(shù)據(jù)讀出顯示在 1602 液晶顯示模塊上,驗(yàn)證讀寫(xiě)的正確性。主程序代碼如下所示:

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

#define uchar unsigned char
#define  uint unsigned int

sbit DU = P2^7;//數(shù)碼管段選、位選引腳定義
sbit WE = P2^6;	

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

void main()
{
	uchar dat=0;
	P0 = 0;//關(guān)閉所有數(shù)碼管
	WE = 1;
	WE = 0;

	Init_1602();//1602初始化

	WrStr_AT24C01(str1,0x05,16);//寫(xiě)入16個(gè)字節(jié)
	RdStr_AT24C01(str2,0x05,16);//讀取16個(gè)字節(jié)

	Disp_1602_str(1,1,str2); //將數(shù)據(jù)從第一行第一列開(kāi)始顯示

	while(1);
}

如代碼所示,從地址 0x05 開(kāi)始寫(xiě)入 16 個(gè)字節(jié)的數(shù)據(jù),由于 AT24C01 為 8 個(gè)字節(jié)為一頁(yè),因此本次為橫跨了 3 頁(yè)的寫(xiě)操作,有效的驗(yàn)證的多字節(jié)的寫(xiě)操作。

13.3 本章小結(jié)

本章詳細(xì)介紹了I2C總線的通信原理,以及驅(qū)動(dòng)函數(shù)的編寫(xiě),AT24C01芯片的使用。

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 單片機(jī)
    +關(guān)注

    關(guān)注

    6035

    文章

    44554

    瀏覽量

    634651
  • uart
    +關(guān)注

    關(guān)注

    22

    文章

    1235

    瀏覽量

    101354
  • I2C總線
    +關(guān)注

    關(guān)注

    8

    文章

    390

    瀏覽量

    60916
  • 總線通信
    +關(guān)注

    關(guān)注

    0

    文章

    49

    瀏覽量

    11829
  • AT24C01
    +關(guān)注

    關(guān)注

    0

    文章

    3

    瀏覽量

    5252
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    i2c總線ppt(I2C總線器件應(yīng)用)

    I2C總線器件應(yīng)用第一節(jié) I2C總線器件應(yīng)用概述I2C總線工作原理
    發(fā)表于 08-13 17:34 ?0次下載

    億恒C166 系列單片機(jī)I2C 總線的軟件模擬

    億恒C166 系列單片機(jī)I2C 總線的軟件模擬
    發(fā)表于 05-14 16:11 ?6次下載

    基于I2C總線的單主多從單片機(jī)之間的通信

    介紹了作者所設(shè)計(jì)的基于I2C 總線的測(cè)試系統(tǒng)的結(jié)構(gòu)及I2C 總線通信協(xié)議的特點(diǎn),給出了I2C
    發(fā)表于 12-19 17:06 ?108次下載

    什么是i2c總線

    什么是i2c總線  下載請(qǐng)點(diǎn)擊: i2c總線協(xié)議中文版 
    發(fā)表于 11-05 09:26 ?2919次閱讀

    I2C總線單片機(jī)C語(yǔ)言實(shí)現(xiàn)及其應(yīng)用

    I2C總線單片機(jī)C語(yǔ)言實(shí)現(xiàn)及其應(yīng)用 本文介紹了I2C總線的概念、接口特性和傳輸時(shí)序,提出了一
    發(fā)表于 10-17 08:36 ?2968次閱讀
    <b class='flag-5'>I2C</b><b class='flag-5'>總線</b>的<b class='flag-5'>單片機(jī)</b><b class='flag-5'>C</b>語(yǔ)言實(shí)現(xiàn)及其應(yīng)用

    PIC單片機(jī)I2C 24LC02 C讀寫(xiě)程序

    PIC單片機(jī)I2C 24LC02 C讀寫(xiě)程序 1   I2C總線特點(diǎn) &
    發(fā)表于 10-30 08:27 ?5394次閱讀

    AVR單片機(jī)I2C總線實(shí)驗(yàn)

     AVR單片機(jī)I2C總線實(shí)驗(yàn)。 1、用24C02記錄CPU啟動(dòng)次數(shù),并在PB口上顯示出來(lái)。 
    發(fā)表于 06-30 11:27 ?2057次閱讀

    基于CPLD的I2C總線接口設(shè)計(jì)

    在電路設(shè)計(jì)中,I2C總線是比較常用的兩線式串行通信方式,大多數(shù)的CPU都擅長(zhǎng)于并口操作,不具備直接操作I2C總線接口的能力。為了使不具備
    發(fā)表于 02-12 16:11 ?95次下載
    基于CPLD的<b class='flag-5'>I2C</b><b class='flag-5'>總線</b>接口設(shè)計(jì)

    i2c

    單片機(jī)i2c總線操作;單片機(jī)i2c總線操作;單片機(jī)
    發(fā)表于 05-17 11:09 ?35次下載

    基于I2C總線的單主多從通信

    基于I2C總線的單主多從單片機(jī)之間的通信
    發(fā)表于 08-30 16:03 ?13次下載
    基于<b class='flag-5'>I2C</b><b class='flag-5'>總線</b>的單主多從<b class='flag-5'>通信</b>

    80C51單片機(jī)模擬I2C總線的主機(jī)程序分享

    I2C總線協(xié)議程序 在使用的過(guò)程中一定要注意時(shí)序、時(shí)間的問(wèn)題。 i2c.c /* I2C.c 標(biāo)準(zhǔn)80C51
    發(fā)表于 12-05 15:39 ?3433次閱讀
    80<b class='flag-5'>C</b>51<b class='flag-5'>單片機(jī)</b>模擬<b class='flag-5'>I2C</b><b class='flag-5'>總線</b>的主機(jī)程序分享

    基于MCS-51單片機(jī)I2C總線接口電路的設(shè)計(jì)

    單片機(jī)控制系統(tǒng)中,廣泛使用I2C器件。如果單片機(jī)自帶I2C總線接口,則所有I2C器件對(duì)應(yīng)連接到
    發(fā)表于 10-15 16:13 ?3400次閱讀
    基于MCS-51<b class='flag-5'>單片機(jī)</b><b class='flag-5'>I2C</b><b class='flag-5'>總線</b>接口電路的設(shè)計(jì)

    使用單片機(jī)實(shí)現(xiàn)I2C總線實(shí)驗(yàn)文件免費(fèi)下載

    本文檔的主要內(nèi)容詳細(xì)介紹的是使用單片機(jī)實(shí)現(xiàn)I2C總線實(shí)驗(yàn)文件免費(fèi)下載。
    發(fā)表于 03-24 11:11 ?7次下載

    I2C總線的基本通信總結(jié)

    在電子設(shè)計(jì)開(kāi)發(fā)中I2C大家已經(jīng)很熟悉了,每一種電子產(chǎn)品小到電子開(kāi)關(guān),大到衛(wèi)星通信都會(huì)利用的I2C總線。據(jù)統(tǒng)計(jì)I2C在電子產(chǎn)品中占據(jù)了93%的
    的頭像 發(fā)表于 08-26 14:08 ?1.8w次閱讀
    <b class='flag-5'>I2C</b><b class='flag-5'>總線</b>的基本<b class='flag-5'>通信</b>總結(jié)

    51單片機(jī)——I2C總線

    本文主要介紹I2C總線協(xié)議時(shí)序圖,并介紹I2C總線的數(shù)據(jù)傳送格式,最后介紹了I2C總線存儲(chǔ)器
    發(fā)表于 11-23 16:22 ?13次下載
    51<b class='flag-5'>單片機(jī)</b>——<b class='flag-5'>I2C</b><b class='flag-5'>總線</b>
    主站蜘蛛池模板: 快插我我好湿啊公交车上做| 国产免费毛片在线观看| 香艳69xxxxx有声小说| 极品少妇高潮啪啪AV无码| 18av 在线| 日韩性xxx| 狠狠色狠狠色综合日日92 | 国产久青青青青在线观看| 亚洲幼女网| GAY空少被体育生开菊| 天天澡夜夜澡人人澡| 久久精品国产免费播放| 99视频精品全部免费观看| 婷婷亚洲五月色综合久久| 久久成人国产精品一区二区 | 年轻漂亮的妺妺中文字幕版| 国产 交换 丝雨 巅峰| 亚洲日本va中文字幕久久| 女教师跟黑人男朋友激情过后| 国产精品久久人妻无码网站一区L| 一区三区三区不卡| 日本在线免费播放| 激情内射亚洲一区二区三区 | 红桃传媒少妇人妻网站无码抽插| 999视频在线观看| 无人影院在线播放| 麻豆国产人妻欲求不满| 国产成人免费a在线视频app| 又亲又揉摸下面视频免费看| 三级黄色视屏| 久久强奷乱码老熟女| 国产AV一区二区三区传媒| 中文字幕一区二区三区在线播放| 色婷婷AV国产精品欧美毛片| 久久三级网站| 国产精品九九久久精品视| 2023极品少妇XXXO露脸| 香艳69xxxxx有声小说| 男生jj插入女生jj| 好男人社区| 成人免费肉动漫无遮网站|