欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136

 找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 4434|回復(fù): 0
打印 上一主題 下一主題
收起左側(cè)

AVR學(xué)習(xí)筆記九、基于AT24C16的數(shù)據(jù)存儲(chǔ)實(shí)驗(yàn)

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:231572 發(fā)表于 2017-9-7 09:26 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
9.1  I/O口模擬I2C總線實(shí)現(xiàn)AT24C16的讀寫
9.1.1、實(shí)例功能
I2C總線(Inter Integrate Circuit BUS)全稱為芯片間總線,是Philips公司推出的一種雙向二進(jìn)制總線。它在芯片間以兩根連線實(shí)現(xiàn)全雙工同步數(shù)據(jù)傳送,一條數(shù)據(jù)線(SDA)和一條串行時(shí)鐘線(SCL),可以很方便的構(gòu)成外圍器件擴(kuò)展系統(tǒng)。
I2C總線協(xié)議允許總線介入多個(gè)期間,總線上的器件既可以作為主控制器也可以作為被控制器,既可以是發(fā)送器,也可以是接收器。I2C總線在進(jìn)行數(shù)據(jù)交換時(shí),作為主控制器的器件需要通過總線競(jìng)爭(zhēng)獲得主控權(quán),然后才可以啟動(dòng)數(shù)據(jù)傳輸。系統(tǒng)中每個(gè)器件都具有唯一的芯片地址,數(shù)據(jù)傳輸時(shí)通過尋址可以確定數(shù)據(jù)接收方。
I2C總線自從出現(xiàn)以后,得到了廣泛應(yīng)用。I2C總線結(jié)構(gòu)簡(jiǎn)單,可靠性和抗干擾性好,可構(gòu)成各種通用的硬件和軟件模塊。方便重復(fù)利用,大大簡(jiǎn)化了系統(tǒng)的設(shè)計(jì)過程。
I2C總線的實(shí)現(xiàn)有兩種方法:一、軟件模擬I2C通信協(xié)議實(shí)現(xiàn)數(shù)據(jù)傳輸,二、利用硬件I2C接口實(shí)現(xiàn)數(shù)據(jù)傳輸。
ATmega16單片機(jī)集成了硬件I2C模塊,稱為TWI接口,TWI電路結(jié)構(gòu)簡(jiǎn)單,只占用兩個(gè)I/O口,可以實(shí)現(xiàn)多個(gè)器件共享一條總線,使用比較方便,系統(tǒng)也很簡(jiǎn)潔。AVR單片機(jī)用硬件實(shí)現(xiàn)了這種總線的時(shí)序,省去了很多編程工作。只要控制相關(guān)的寄存器,就可以實(shí)現(xiàn)通過TWI總線傳輸數(shù)據(jù)。
但是使用硬件I2C接口的缺點(diǎn)是接口固定,在特定的系統(tǒng)里面,會(huì)增加硬件和軟件設(shè)計(jì)的復(fù)雜程度。在本例中我們采用模擬I2C總線時(shí)序的方法實(shí)現(xiàn)I2C通信。軟件模擬I2C時(shí)序的方法增加了軟件的復(fù)雜程度,但是方便了硬件設(shè)計(jì),模擬I2C接口可以使用單片機(jī)的如何普通I/O口。
本節(jié)首先介紹I2C總線的的一些基本知識(shí):特點(diǎn)、結(jié)構(gòu)、原理、控制時(shí)序、與單片機(jī)的接口方法等。最后通過一個(gè)實(shí)例實(shí)現(xiàn)模擬I2C接口。
本實(shí)例分為三個(gè)功能模塊,分別描述如下:
● 單片機(jī)系統(tǒng):利用ATmega16單片機(jī)與AT24C16實(shí)現(xiàn)數(shù)據(jù)傳輸,利用模擬I2C總線接口的方法讀寫AT24C16。
● 外圍電路:外圍電路分兩部分:LED顯示部分(用于指示從AT24C16中讀取的數(shù)值正確與否)、AT24C16接口電路電路(實(shí)現(xiàn)模擬I2C總線功能)。
● 軟件程序:編寫軟件,實(shí)現(xiàn)對(duì)AT24C16的數(shù)據(jù)讀寫。
通過本實(shí)例的學(xué)習(xí),掌握以下內(nèi)容:
● 理解AT24C16的特點(diǎn)、結(jié)構(gòu)和原理和接口設(shè)計(jì)方法。
● 掌握AT24C16的控制時(shí)序和控制方法流程。
● 掌握模擬I2C總線的設(shè)計(jì)方法。
9.1.2 器件和原理
   1I2C總線介紹
   AT24C16的外形級(jí)封裝和引腳說明如圖9.1.1
file:///C:/Users/m/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg
               9.1.1 AT24C16的外形封裝和引腳說明
I2C總線協(xié)議規(guī)定,任何將數(shù)據(jù)傳送到總線的器件作為發(fā)送器。任何從總線接收數(shù)據(jù)的器件為接收器。主器件控制串行時(shí)鐘和起始、停止信號(hào)的發(fā)生。主器件何從期間都可以發(fā)送或接收數(shù)據(jù),但是主器件控制數(shù)據(jù)傳送模式(發(fā)送或者接收)。
通過器件地址輸入端A0、A1、A2可以實(shí)現(xiàn)講最多8個(gè)at24c01器件和a424c02器件、4個(gè)at24c04器件、2個(gè)at24c08器件、1個(gè)at24c16器件連接到總線上。當(dāng)總線上只有一個(gè)器件時(shí),A0、A1、A2可以連接到地或者懸空。
   WP寫保護(hù)引腳:當(dāng)該引腳連接到VCCI2C器件內(nèi)的內(nèi)容被寫保護(hù)(只能讀)。如果允許對(duì)器件進(jìn)行正常的讀寫,那么WP引腳需連接到地或者懸空。
2I2C總線接口
I2C總線的信號(hào)線有兩種:
●時(shí)鐘線SCL。
●數(shù)據(jù)線SDA。
SCL和SDA都是雙向總線,I2C總線為同步傳輸串行總線結(jié)構(gòu),及總線上的數(shù)據(jù)信號(hào)完全與時(shí)鐘同步。數(shù)據(jù)傳輸采用主從方式:主器件尋址從器件,啟動(dòng)總線數(shù)據(jù)傳輸,并產(chǎn)生時(shí)鐘脈沖。總線傳輸中的所有狀態(tài)及操作都有相應(yīng)的編碼,主器件依照這些協(xié)議編碼自動(dòng)地進(jìn)行總線控制與管理。從器件接收主器件的請(qǐng)求并應(yīng)答。數(shù)據(jù)傳輸結(jié)束后,主器件將總線釋放。
當(dāng)總線空閑時(shí),SCL和SDA均為高電平。連接到總線上的器件的輸出端口必須是漏極開路,任一器件輸出低電平時(shí),總線信號(hào)變低。即總線SCL和SDA上的信號(hào)都是線“與”的關(guān)系。
由于SDA和SCL的端口輸出都是漏極開路,因此總線上必須連接上拉電阻。上拉電阻的大小與電源電壓、傳輸速率等有關(guān)系。當(dāng)傳輸速率為100KHz時(shí),上拉電阻一般采用10K,對(duì)于400KHz的傳輸速率,上拉電阻可以采用2K歐姆。
9.1.3I2C總線的尋址方式
I2C總線上的器件都是共用總線的,因此,主器件在進(jìn)行數(shù)據(jù)傳輸前必須選擇需要通信的從器件。即進(jìn)行總線尋址。
I2C總線上所有外圍器件都有唯一的地址,這個(gè)地址由器件地址和引腳地址兩部分組成。共7位。器件地址是I2C器件固有的地址編碼,器件出廠時(shí)已經(jīng)給定,不可更改。引腳地址由I2C總線外圍器件的地址引腳A0、A1、A2決定,根據(jù)其在電路中接電源正極、接地或者懸空的不同,形成不同的地址代碼。引腳地址數(shù)也決定了同一器件可接入總線的最大數(shù)目。
地址位與一個(gè)方向位共同構(gòu)成I2C總線器件尋址字節(jié)。尋址字節(jié)的格式如圖所示;方向位(R/W)規(guī)定了總線上主器件與外圍器件(從器件)的數(shù)據(jù)傳輸方向。當(dāng)方向位R/W=1時(shí),表示主器件讀取從器件的數(shù)據(jù);R/W=0時(shí),表示主器件向從器件發(fā)送數(shù)據(jù)。
file:///C:/Users/m/AppData/Local/Temp/msohtmlclip1/01/clip_image004.jpg
9.1.4I2C總線的數(shù)據(jù)傳輸協(xié)議
  I2C總線的數(shù)據(jù)傳輸遵循嚴(yán)格的時(shí)序格式,下面分別介紹數(shù)據(jù)傳輸過程中的格式。
1、起始信號(hào)、終止信號(hào)
   在時(shí)鐘線SCL為高電平期間,數(shù)據(jù)線SDA上出現(xiàn)高電平向低電平變化的下降沿時(shí),被認(rèn)為是起始信號(hào)。起始信號(hào)出現(xiàn)以后,后面才可以進(jìn)行尋址或數(shù)據(jù)傳輸?shù)取?/font>
   在時(shí)鐘信號(hào)SCL高電平期間,數(shù)據(jù)線SDA上出現(xiàn)由低電平到高電平變化的上升沿時(shí),被認(rèn)為是終止信號(hào)。終止信號(hào)一出現(xiàn),所有總線操作都結(jié)束,主器件釋放總線控制權(quán)。
   起始信號(hào)、終止信號(hào)的時(shí)序如下圖所示。
file:///C:/Users/m/AppData/Local/Temp/msohtmlclip1/01/clip_image006.jpg
2、數(shù)據(jù)讀寫
   當(dāng)SCL為高電平期間,SDA上的數(shù)據(jù)必須保持不變,如果此時(shí)SDA上的電平發(fā)生變化,則會(huì)被認(rèn)為是起始或者終止信號(hào)。只有在SCL為低電平期間,SDA上的數(shù)據(jù)才能發(fā)生變化。所以在進(jìn)行讀取SDA上的數(shù)據(jù)時(shí),必須使SCL處于低電平。
file:///C:/Users/m/AppData/Local/Temp/msohtmlclip1/01/clip_image008.jpg
3、總線數(shù)據(jù)位
   每次發(fā)送到I2C總線SDA上的數(shù)據(jù)必須是一個(gè)字節(jié),傳輸?shù)臄?shù)據(jù)字節(jié)按照由高位到低位的順序發(fā)送。在I2C總先啟動(dòng)后或應(yīng)答信號(hào)后的第1-8個(gè)時(shí)鐘脈沖,對(duì)應(yīng)于要傳送字節(jié)的8位數(shù)據(jù)。
I2C總線上的數(shù)據(jù)是伴隨著時(shí)鐘脈沖,一位一位的傳送的,每位數(shù)據(jù)占一個(gè)時(shí)鐘脈沖。在時(shí)鐘線SCL高電平期間,數(shù)據(jù)線SDA的狀態(tài)就表示要傳送的數(shù)據(jù),高電平為數(shù)據(jù)1,低電平為數(shù)據(jù)0.在數(shù)據(jù)傳送時(shí),數(shù)據(jù)線上數(shù)據(jù)的變化在時(shí)鐘線為低電平時(shí)完成;而時(shí)鐘線為高電平時(shí),數(shù)據(jù)線必須保持穩(wěn)定,否則數(shù)據(jù)線上的任何變化都被當(dāng)成起始或者終止信號(hào),從而導(dǎo)致數(shù)據(jù)傳輸停止。
file:///C:/Users/m/AppData/Local/Temp/msohtmlclip1/01/clip_image010.jpg
4、應(yīng)答信號(hào)、非應(yīng)答信號(hào)
   I2C總線數(shù)據(jù)傳送時(shí),每傳送一個(gè)字節(jié)數(shù)據(jù)后都必須有應(yīng)答信號(hào)。應(yīng)答信號(hào)由主器件產(chǎn)生。主器件在第9個(gè)時(shí)鐘位上釋放數(shù)據(jù)總線,使其處于高電平狀態(tài),此時(shí)從器件輸出低電平拉低數(shù)據(jù)線產(chǎn)生應(yīng)答信號(hào)。
   在傳送完一個(gè)字節(jié)數(shù)據(jù)后,在第9個(gè)時(shí)鐘位上,從器件輸出高電平為非應(yīng)答信號(hào)。非應(yīng)答信號(hào)的產(chǎn)生有兩種情況:
● 當(dāng)從器件正在進(jìn)行其他處理而無法接收總線上的數(shù)據(jù)時(shí),從器件不產(chǎn)生應(yīng)答,此時(shí)從器件釋放總線,將數(shù)據(jù)線置為高電平。這樣,主器件可產(chǎn)生一個(gè)停止信號(hào)來終止總線傳輸數(shù)據(jù)。
● 當(dāng)主器件接收來自從器件的數(shù)據(jù)時(shí),接收到最后一個(gè)字節(jié)數(shù)據(jù)后,必須給從器件發(fā)送一個(gè)非應(yīng)答信號(hào),使從器件釋放數(shù)據(jù)總線。這樣,主器件才可以發(fā)送終止信號(hào),從而終止數(shù)據(jù)傳送。
file:///C:/Users/m/AppData/Local/Temp/msohtmlclip1/01/clip_image012.jpg
5、數(shù)據(jù)傳送格式
   I2C總線協(xié)議規(guī)定了完整的數(shù)據(jù)傳送格式。按照協(xié)議規(guī)定,數(shù)據(jù)的傳輸以主器件發(fā)送起始信號(hào)開始,然后發(fā)送尋址從器件的尋址字節(jié)。尋址字節(jié)共8位,前7位為被尋址的從器件(對(duì)于AT24C16來說,由于總線上只能連接1個(gè)AT24C16,所以對(duì)AT24C16的尋址字節(jié),高4位固定為10101-3位則是其內(nèi)部頁(yè)地址的高3位),第0位是方向位。在尋址字節(jié)后面跟著操作地址,操作地址指明了對(duì)被尋址器件內(nèi)部的某一位或某幾位進(jìn)行操作。操作地址之后跟的就是要傳輸?shù)臄?shù)據(jù)了,數(shù)據(jù)傳輸結(jié)束后,主器件發(fā)送一個(gè)終止信號(hào)以釋放總線控制權(quán)。
數(shù)據(jù)可以單字節(jié)傳輸,也可以多字節(jié)傳輸,如果主器件希望繼續(xù)占用總線,則可以不發(fā)送停止信號(hào),馬上再次發(fā)送起始信號(hào),便可以進(jìn)行新的操作。
9.1.5  AT24C16的內(nèi)部數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)
   AT24C16內(nèi)部有2048*8位的存儲(chǔ)容量,即可以存儲(chǔ)2K字節(jié)的數(shù)據(jù)。這2K字節(jié)被放在128個(gè)頁(yè)內(nèi),每頁(yè)存放16個(gè)字節(jié)。所以對(duì)AT24C16內(nèi)部的訪問需要11位地址(0-7ff)。對(duì)AT24C16訪問時(shí),按照頁(yè)地址和頁(yè)偏移量的方式進(jìn)行訪問。比如要訪問第100頁(yè)的第3個(gè)字節(jié),則在發(fā)送尋址的時(shí)候,就要發(fā)送0X0643,其中頁(yè)地址的高三位放在器件地址中。所以在編寫程序?qū)?/font>AT24C16100頁(yè)的第3個(gè)字節(jié)進(jìn)行寫數(shù)據(jù)的時(shí)候,步驟如下:1)發(fā)送起始信號(hào);2)發(fā)送器件地址0XA61010 01101010是固定地址,011是頁(yè)地址的高三位,0表示寫操作);3)發(fā)送操作地址0X430100 00110100是頁(yè)地址的低四位,0011是頁(yè)地址偏移量,即第100頁(yè)內(nèi)的第三個(gè)字節(jié),4)發(fā)送要寫的數(shù)據(jù),5)發(fā)送終止信號(hào)。
  
  
9.1.6、電路和連接
LED發(fā)光二極管電路已經(jīng)在第一個(gè)實(shí)例中介紹過,本例中不再重復(fù)。本例中AT24C16與單片機(jī)的連接如圖9.1.2所示,由于AT24C16的數(shù)據(jù)線、時(shí)鐘線要求空閑狀態(tài)為高電平,所以我在AT24C16的數(shù)據(jù)線和時(shí)鐘線上分別加了4.7K的上拉電阻,如果不想接上拉電阻的話,可以使能PA2口的內(nèi)部上拉功能,但是程序設(shè)計(jì)會(huì)有些不同。AT24C16的數(shù)據(jù)線SDA、時(shí)鐘線SCL分別連到單片機(jī)的PC1、PC0口。
file:///C:/Users/m/AppData/Local/Temp/msohtmlclip1/01/clip_image014.jpg
圖9.1.2  AT24C16電路
7.1.4、程序設(shè)計(jì)
1、程序功能
程序的功能是使用單片機(jī)的PC1PC0口的模擬I2C總線時(shí)序?qū)崿F(xiàn)對(duì)AT24C16的數(shù)據(jù)讀寫操作,然后用LED的亮滅指示讀取數(shù)據(jù)的正確性。
2函數(shù)說明
本程序多個(gè)功能函數(shù),分別是:
● AT24C16操作相關(guān)函數(shù):
void I2C_Init(void);                    //I2C端口初始化
unsigned char I2C_Start(void);        //發(fā)送起始信號(hào)
void I2C_Stop(void);                    //發(fā)送結(jié)束信號(hào)
unsigned char I2C_WriteByte(unsigned char dat);  //寫一個(gè)字節(jié)
unsigned char I2C_ReadByte(unsigned char ack);   //讀一個(gè)字節(jié)
unsigned char EEPROM_ReadByte(unsigned intadd); //從固定地址讀一字節(jié)
void EEPROM_WriteByte(unsigned int add,unsigned char data);  //向固定地址寫一字節(jié)● 延時(shí)相關(guān)函數(shù):
void Delayus(unsigned intlus);         //us延時(shí)函數(shù)
void Delayms(unsigned intlms);        //ms延時(shí)函數(shù)
由于WINAVR自帶函數(shù)庫(kù)中的延時(shí)函數(shù)使用起來很不方便,并且晶振頻率不同,延時(shí)時(shí)間也有區(qū)別,所以本實(shí)例中自己寫了兩個(gè)延時(shí)函數(shù)。
    3使用WINAVR開發(fā)環(huán)境,使用的是外部12M的晶振,所以需要將makefile文件中的時(shí)鐘頻率修改為12M。另外在程序燒錄到單片機(jī)的時(shí)候,熔絲位也要選擇為外部12M晶振(注意是晶振,不是外部振蕩器,一定不要選擇錯(cuò)了,否則會(huì)導(dǎo)致單片機(jī)不能再燒寫程序)。
4、程序說明。在本實(shí)例中我們首先了解了I2C總線的原理和特點(diǎn),用模擬I2C總線接口的方式實(shí)現(xiàn)了對(duì)AT24C16的讀寫操作。
5、程序代碼
#include <avr/io.h>        //io端口寄存器配置文件,必須包含
#include <util/delay.h>
//端口聲明
/*注:
AVR單片機(jī)I/O口模擬I2C總線時(shí)建議在外部連接上拉電阻 ,這樣可通過改變I/O口輸入輸出方向的方式
來設(shè)置高低電平, 輸出口保持不變(0) ,此時(shí)如DDRX寄存器為1則變成輸出0,若DDRX為0,則I/O口
呈現(xiàn)高阻狀態(tài),但因外部的上拉電阻,總線相當(dāng)于設(shè)置高電平,即通過設(shè)置DDRX的方式控制總線的高低
*/
#define SCL_INPUT (DDRC &=~(1 << PC0))  //SCL設(shè)置為輸入口
#define SCL_OUTPUT (DDRC |= (1<< PC0))  //SCL設(shè)置為輸出口
#define SCL_LOW (PORTC &= ~(1<< PC0))   //SCL設(shè)置為輸出低電平
#define SCL_HIGH (PORTC |= (1<< PC0))   //SCL設(shè)置為輸出高電平
#define SCL_INDATA (PINC & (1<< PC0))   //讀取SCL的端口狀態(tài)
#define SDA_INPUT (DDRC &=~(1 << PC1))   //SDA設(shè)置為輸入口
#define SDA_OUTPUT (DDRC |= (1<< PC1))   //SDA設(shè)置為輸出口
#define SDA_LOW (PORTC &= ~(1<< PC1))    //SDA設(shè)置為輸出低電平
#define SDA_HIGH (PORTC |= (1<< PC1))   //SDA設(shè)置為輸出高電平
#define SDA_INDATA (PINC & (1<< PC1))   //讀取SDA的端口狀態(tài)
//變量聲明
#define EEPROM_BUS_ADDRESS0xa0         //器件地址
//函數(shù)聲明
void Delayus(unsigned intlus);         //us延時(shí)函數(shù)
void Delayms(unsigned intlms);        //ms延時(shí)函數(shù)
void I2C_Init(void);                    //I2C端口初始化
unsigned char I2C_Start(void);         //發(fā)送起始信號(hào)
void I2C_Stop(void);                    //發(fā)送結(jié)束信號(hào)
unsigned char I2C_WriteByte(unsigned char dat);  //寫一個(gè)字節(jié)
unsigned char I2C_ReadByte(unsigned char ack);   //讀一個(gè)字節(jié)
unsigned charEEPROM_ReadByte(unsigned int add); //從固定地址讀一字節(jié)
void EEPROM_WriteByte(unsignedint add,unsigned char data);  //向固定地址寫一字節(jié)
int main(void)            //GCC中main文件必須為返回整形值的函數(shù),沒有參數(shù)
{
       unsignedchar i;
       PORTB= 0x00;     
       DDRB= 0xFF;   //端口PortB設(shè)為輸出口,通過相應(yīng)位LED的變化指示程序運(yùn)行結(jié)果
       I2C_Init();        //I2C端口初始化
       EEPROM_WriteByte(0x01aa,0x5a);
//向固定地址寫一字節(jié),向第26頁(yè)的第十個(gè)字節(jié)寫入數(shù)據(jù)0x5a
       i= EEPROM_ReadByte(0x01aa); //從固定地址讀一字節(jié)  
       if(i== 0x5a)
       {
              PORTB|= 0x01;     //讀出的數(shù)據(jù)正確,則LED0點(diǎn)亮
       }
       else
       {
              PORTB|= 0x02;       //讀出的數(shù)據(jù)不正確,則LED1點(diǎn)亮
       }     
       while(1)
       {
              
       }
}
//I2C初始化函數(shù)
void I2C_Init(void)
{
       SCL_LOW;    //SCL的PORT狀態(tài)鎖定為0,以后不再改變
       SCL_INPUT;   //SCL設(shè)置為輸入口
      
       SDA_LOW;    //SDA的PORT狀態(tài)鎖定為0,以后不再改變
       SDA_INPUT;    //SDA設(shè)置為輸入口
       Delayus(10);
}
//I2C起始條件
unsigned char I2C_Start(void)
{
       Delayus(10);
       SDA_INPUT;   //SDA高電平
       Delayus(10);  //延時(shí)一段時(shí)間,使單片機(jī)時(shí)鐘頻率符合I2C時(shí)鐘
       SCL_INPUT;   //SCL高電平
       Delayus(10);   
       SDA_OUTPUT;      //SDA變低,產(chǎn)生由高到低的變化
       Delayus(10);   
       SCL_OUTPUT;       //SCL變低,占用總線
       Delayus(10);   
       return1;
}
//I2C結(jié)束條件
void I2C_Stop(void)
{
       Delayus(10);
       SDA_OUTPUT;   //SDA低電平
       Delayus(10);   
       SCL_INPUT;   //SCL高電平     
       Delayus(10);   
       SDA_INPUT;   //SDA變?yōu)楦唠娖剑a(chǎn)生由低到高的變化
       Delayus(10);         
}
//向I2C寫一個(gè)字節(jié)
unsigned char I2C_WriteByte(unsigned char dat)
{
       unsignedchar i,ack; //ack為應(yīng)答信號(hào)
       for(i= 0;i < 8; i++)       //寫8位(1個(gè)字節(jié))數(shù)據(jù)
       {
              if(dat& 0x80)        //寫入數(shù)據(jù),左移,從最高位寫入
              {
                     SDA_INPUT;       //如果該位為1,SDA拉高電平
              }
              else
              {
                     SDA_OUTPUT;            //     如果該位為0,SDA拉低電平
              }
              SCL_INPUT;        //SCL高電平,保持?jǐn)?shù)據(jù)
              Delayus(10);
              SCL_OUTPUT;              //SCL低電平,數(shù)據(jù)被送入I2C
              dat<<= 1;       //需要寫入的數(shù)據(jù)左移一位,送最高位
              Delayus(10);    //
       }
       Delayus(10);
       SDA_INPUT;             //SDA拉高,同時(shí)變?yōu)檩斎肟?/div>
       Delayus(10);
       SCL_INPUT;     //SCL拉高,準(zhǔn)備讀取應(yīng)答信號(hào)
       Delayus(10);
      
       if(SDA_INDATA)
       {
              ack= 0;           //如果此時(shí)SDA為高,說明沒有應(yīng)答信號(hào)
              PORTB|= 0x04;     //沒有應(yīng)答信號(hào),點(diǎn)亮LED2
       }
       else
       {
              ack= 1;         //如果此時(shí)SDA為低,說明有應(yīng)答信號(hào)
              PORTB|= 0x08;       //有應(yīng)答信號(hào),點(diǎn)亮LED3
       }
       SCL_OUTPUT;             //SCL拉低
       Delayus(10);
       returnack;       //返回應(yīng)答信號(hào)
}
//從I2C讀一個(gè)字節(jié)
unsigned char I2C_ReadByte(unsigned char ack)
{
       unsignedchar i,dat = 0;     //dat為讀出的數(shù)據(jù)
       SDA_INPUT;                  //SDA變?yōu)檩斎肟?/div>
       for(i= 0;i < 8;i++)       //讀出8位(1個(gè)字節(jié))數(shù)據(jù)
       {
              Delayus(10);
              SCL_OUTPUT;              //SCL低,這時(shí)允許從I2C發(fā)送數(shù)據(jù)到SDA上
              Delayus(10);
              SCL_INPUT;    //SCL高,準(zhǔn)備讀取SDA上的數(shù)據(jù)
              
              Delayus(10);
              dat<<= 1;       //讀取的數(shù)據(jù)左移一位,從最高位讀起
              if(SDA_INDATA)
              {
                     dat++; //如果DSA為高,則讀取的數(shù)據(jù)加1
              }            
              Delayus(10);
       }
       SCL_OUTPUT;           //SCL拉低,準(zhǔn)備下一個(gè)數(shù)據(jù)變化
       Delayus(10);
       if(!ack)     //
       {
              SDA_INPUT;   //發(fā)送NACK
       }
       else
       {
              SDA_OUTPUT;             //發(fā)送ACK
       }
       Delayus(10);
       SCL_INPUT;       //SCL高
       Delayus(10);
       SCL_OUTPUT;       //SCL低
      
       Delayus(10);
      
       return(dat);     //返回讀到的數(shù)據(jù)
}
//從固定地址讀一字節(jié)
unsigned charEEPROM_ReadByte(unsigned int add)
{
       unsignedchar data;
       I2C_Start();         //發(fā)送起始信號(hào)                    
       I2C_WriteByte(EEPROM_BUS_ADDRESS | ((add>> 8) << 1));  
//寫器件地址和頁(yè)地址的高3位           
       I2C_WriteByte(add);  //寫頁(yè)地址的低4位和頁(yè)地址內(nèi)部偏移量   
       I2C_Start();         //發(fā)送起始信號(hào)
       I2C_WriteByte(EEPROM_BUS_ADDRESS | 0x01);  //發(fā)送讀命令
       data= I2C_ReadByte(0);   //讀一個(gè)字節(jié)   
       I2C_Stop();               //發(fā)送結(jié)束信號(hào)   
       returndata;
}
//向固定地址寫一字節(jié)
void EEPROM_WriteByte(unsignedint add,unsigned char data)
{
       I2C_Start();         //發(fā)送起始信號(hào)                    
       I2C_WriteByte(EEPROM_BUS_ADDRESS | ((add>> 8) << 1));
//寫器件地址和頁(yè)地址的高3位  
       I2C_WriteByte(add);  //寫頁(yè)地址的低4位和頁(yè)地址內(nèi)部偏移量   
       I2C_WriteByte(data);  //寫一個(gè)字節(jié)數(shù)據(jù)
       I2C_Stop();               //發(fā)送結(jié)束信號(hào)
       Delayms(10);
}
//us級(jí)別的延時(shí)函數(shù)
void Delayus(unsigned int lus)
{
       while(lus--)
       {
              _delay_loop_2(3);     
//_delay_loop_2(1)是延時(shí)4個(gè)時(shí)鐘周期,參數(shù)為3則延時(shí)12
                         //個(gè)時(shí)鐘周期,本實(shí)驗(yàn)用12M晶體,則12個(gè)時(shí)鐘周期為12/12=1us
    }
}
//ms級(jí)別的延時(shí)函數(shù)
void Delayms(unsigned int lms)
{
       while(lms--)
       {
              Delayus(1000);        //延時(shí)1ms
    }
}
9.2 基于硬件接口的AT24C02的讀寫實(shí)驗(yàn)
9.2.1、實(shí)例功能
AVR單片機(jī)提供了實(shí)現(xiàn)標(biāo)準(zhǔn)2先串行總線通信TWI(兼容I2C總線)硬件接口。其主要性能和特點(diǎn)有:
● 簡(jiǎn)單,但是強(qiáng)大而靈活的串行通信接口,只需要兩根線;
● 支持主機(jī)和從機(jī)操作;
● 器件可以作為發(fā)送器,也可以作為接收器;
● 7位地址空間,最大允許有128個(gè)從機(jī);
● 支持多主機(jī)模式;
● 最高可達(dá)400K的數(shù)據(jù)傳輸率;
● 全可編程的從機(jī)地址
● 地址監(jiān)聽中斷可以是AVR單片機(jī)從休眠狀態(tài)喚醒。
    AVR的TWI是支持I2C通信的硬件接口,使用硬件接口的優(yōu)點(diǎn)是可以直接使用硬件接口完成I2C通信,而不必使用I/O口模擬I2C的時(shí)序。比軟件模擬要簡(jiǎn)單,代碼短,效率高。
本實(shí)例包括三個(gè)功能模塊,分別介紹如下:
● 單片機(jī)系統(tǒng):利用ATmega16單片機(jī)與AT24C16通信,實(shí)現(xiàn)數(shù)據(jù)的讀寫,并使用LED指示讀寫數(shù)據(jù)是否正確。
● 外圍電路:外圍電路分兩部分:LED顯示電路(實(shí)現(xiàn)指示讀寫數(shù)據(jù)是否正確)、AT24C16通信電路(實(shí)現(xiàn)對(duì)AT24C16的讀寫操作)。
● 軟件程序:編寫軟件,實(shí)現(xiàn)利用AVR的硬件I2C接口對(duì)AT24C16進(jìn)行數(shù)據(jù)讀寫數(shù)據(jù)功能。
通過本實(shí)例的學(xué)習(xí),掌握以下內(nèi)容:
● 理解AVR單片機(jī)硬件I2C接口的特點(diǎn)、原理。
● 掌握AVR單片機(jī)硬件I2C接口的控制時(shí)序和控制方法流程。
● 掌握使用查詢方法對(duì)AT24C16進(jìn)行操作的軟件編程。
9.2.2 器件和原理
上一示例中我們已經(jīng)對(duì)I2C總線的特點(diǎn)、原理進(jìn)行了了解,并且通過利用I/O口模擬I2C總線時(shí)序的方法實(shí)現(xiàn)對(duì)AT24C16的讀寫。
在本例中我們學(xué)習(xí)使用AVR提供的硬件I2C接口。
1、TWI模塊描述
     AVR的TWI模塊由總線接口單元、比特率發(fā)生器、地址匹配單元和控制單元等模塊構(gòu)成。
     ● SDA和SCL引腳
     SDA和SCL是AVR單片機(jī)TWI接口的引腳。引腳的輸出驅(qū)動(dòng)器包含一個(gè)波形斜率限制器,以滿足TWI規(guī)范;引腳的輸入部分包含尖峰抑制但愿,以去除小于50ns的毛刺。
     ●波特率發(fā)生器
     TWI工作在主控器模式時(shí),又該控制單元產(chǎn)生TWI時(shí)鐘信號(hào),并驅(qū)動(dòng)時(shí)鐘線SCL,
      ●總線接口單元
      這個(gè)單元包括:數(shù)據(jù)和地址移位寄存器、起始、停止信號(hào)控制和總線仲裁判定的硬件電路。
      ● 地址匹配單元
      地址匹配單元將檢測(cè)總線上接收到的地址是否與TWAR寄存器中的7位地址相匹配。如果匹配成功,將通知控制單元轉(zhuǎn)入適當(dāng)?shù)牟僮鳡顟B(tài)。TWI可以響應(yīng),也可以不響應(yīng)主控器對(duì)其的尋址訪問。
● 控制單元
      控制單元監(jiān)聽TWI總線,并根據(jù)TWI控制寄存器的設(shè)置作出相應(yīng)的響應(yīng)。
      當(dāng)在TWI總線上產(chǎn)生需要應(yīng)用程序干預(yù)處理的事件時(shí),先對(duì)TWI的中斷標(biāo)志位TWINT進(jìn)行相應(yīng)設(shè)置,在下一個(gè)時(shí)鐘周期時(shí),將表示這個(gè)事件的狀態(tài)字寫入TWI狀態(tài)寄存器TWSR中。在其他情況下,TWSR中的內(nèi)容為一個(gè)表示無事件發(fā)生的狀態(tài)字。一旦TWINT標(biāo)志位置1,就會(huì)將時(shí)鐘線SCL拉低,暫停TWI總線上的傳送,讓用戶程序處理事件。
      在下列事件出現(xiàn)時(shí),TWINT標(biāo)志位設(shè)為“1”:
● 在TWI傳送完一個(gè)起始或再次起始(START/RESTART)信號(hào)后;
● 在TWI傳送完一個(gè)主控器尋址讀/寫(SLA+R/W)數(shù)據(jù)后;
● 在TWI傳送完一個(gè)地址字節(jié)后;
● 在TWI丟失總線控制權(quán)后;
● 在TWI被主控器尋址(地址匹配成功)后;
● 在TWI接收到一個(gè)數(shù)據(jù)字節(jié)后;
● 在作為被控器時(shí),TWI接收到停止或再次起始信號(hào)后;
● 由于非法的起始或停止信號(hào)造成總線上的沖突出錯(cuò)時(shí)。
2、TWI寄存器
1)、波特率寄存器  TWBR
file:///C:/Users/m/AppData/Local/Temp/msohtmlclip1/01/clip_image016.jpg
TWBR用于設(shè)置波特率發(fā)生器的分頻因子,波特率發(fā)生器是一個(gè)頻率分頻器,當(dāng)工作在主控器模式下,它產(chǎn)生和提供SCL引腳上的時(shí)鐘信號(hào)。
     在主機(jī)模式下,TWBR的值應(yīng)大于10,否則可能會(huì)產(chǎn)生不正確的輸出。尤其在中斷模式下,TWBR的值應(yīng)大于10
2)、控制寄存器   TWCR
file:///C:/Users/m/AppData/Local/Temp/msohtmlclip1/01/clip_image018.jpg
      TWCR用來控制TWI操作。例如使能TWI接口;在總線上加起始和終止信號(hào);產(chǎn)生ACK應(yīng)答等。
● 位7–TWINT:TWI中斷標(biāo)志位。當(dāng)TWI接口完成當(dāng)前工作并期待應(yīng)用程序響應(yīng)時(shí),該位被置位。如果全局中斷控制位和TWCR寄存器中的TWIE位都置位,則MCU將跳到TWI中斷向量處。一旦TWINT標(biāo)志位被置位,,時(shí)鐘線SCL將被拉位低。在執(zhí)行中斷服務(wù)程序時(shí),TWINT標(biāo)志位不會(huì)由硬件自動(dòng)清零,必須通過由軟件將該位寫為“1”來清零,清零TWINT標(biāo)志位將開始TWI接口的操作,因此對(duì)TWI寄存器TWAR、TWI狀態(tài)寄存器TWSR、TWI數(shù)據(jù)寄存器TWDR的訪問,必須在清零TWINT標(biāo)志位前完成。
● 位6—TWEA:TWI應(yīng)答(ACK)允許位。TWEA位控制應(yīng)答ACK信號(hào)的發(fā)生。如果TWEA位置1,則在器件作為主控器接收器時(shí),接收到一個(gè)數(shù)據(jù)字節(jié)時(shí), ACK脈沖將在TWI總線上發(fā)生。如果清零TWEA位,將使器件暫時(shí)虛擬地脫離TWI總線。
● 位5—TWSTA:TWI起始(START)信號(hào)狀態(tài)位。當(dāng)要將器件設(shè)置為串行總線上的主控器時(shí),須設(shè)置TWSTA位為1.TWI借口硬件將檢查總線是否空閑。如果總線空閑,將在總線上發(fā)送一個(gè)起始信號(hào);如果總線不空閑,則TWI將等待總線上一個(gè)停止信號(hào)被檢測(cè)后,再發(fā)出一個(gè)新的起始信號(hào),以獲得總線的控制權(quán)而成為主控器。當(dāng)起始信號(hào)發(fā)出后,硬件將自動(dòng)清零TWSTA位。
● 位4—TWSTO:TWI停止(STOP——信號(hào)狀態(tài)位。當(dāng)芯片工作在主控模式時(shí),設(shè)置TWSTO位為1,將在總線上產(chǎn)生一個(gè)終止信號(hào)。當(dāng)終止信號(hào)發(fā)出后,TWSTO位將被自動(dòng)清零。
● 位3—TWWC:TWI寫沖突標(biāo)志位。當(dāng)TWINT為0時(shí),試圖向TWI寫數(shù)據(jù),TWWC位將被置1;當(dāng)TWINT位為1時(shí),寫數(shù)據(jù)時(shí),TWWC由硬件自動(dòng)清零。
● 位2—TWEN:TWI允許位。TWEN用于使能TWI接口操作和激活TWI接口。該位置1,則TWI接口模塊將I/O引腳PC0、PC1轉(zhuǎn)換為SCL和SDA引腳。如果該位清零,則TWI模塊將被關(guān)閉,所有TWI傳輸將被終止,PC0、PC1轉(zhuǎn)換為普通I/O引腳。
● 位1—保留位。讀出總為0;
● 位0—TWIE:TWI中斷使能位。當(dāng)該位為1,并且全局終端也使能時(shí),只要TWINT標(biāo)志為1,TWI中斷請(qǐng)求就使能。
4)狀態(tài)寄存器     TWSR
file:///C:/Users/m/AppData/Local/Temp/msohtmlclip1/01/clip_image020.jpg
位【7:3】--TWS:TWI狀態(tài)位。這5位反映了TWI邏輯狀態(tài)和TWI總線的狀態(tài)。不同的狀態(tài)碼表示不同的操作狀態(tài),具體可查詢數(shù)據(jù)手冊(cè)獲得。注意,從TWSR寄存器中讀取的值包括了5位狀態(tài)值和2位預(yù)分頻值。因此,在檢查狀態(tài)位時(shí),應(yīng)該將預(yù)分頻器位屏蔽,使?fàn)顟B(tài)檢驗(yàn)與預(yù)分頻器無關(guān)。
位2—保留。讀出始終為0;
位【1:0】--TWPS:TWI預(yù)分頻器位。這些位能讀能寫,用于設(shè)置波特率的預(yù)分頻率。如下表所示。
file:///C:/Users/m/AppData/Local/Temp/msohtmlclip1/01/clip_image022.jpg
5)數(shù)據(jù)寄存器     TWDR
file:///C:/Users/m/AppData/Local/Temp/msohtmlclip1/01/clip_image024.jpg
    在發(fā)送模式下,TWDR寄存器的內(nèi)容為下一個(gè)要傳送的字節(jié);在接受模式下,TWDR寄存器的內(nèi)容為最后接受的字節(jié)。當(dāng)TWI不處在字節(jié)移位操作過程時(shí),該寄存器可以被讀寫即當(dāng)TWI中斷標(biāo)志位置位時(shí),該寄存器可以被寫入。在第一次TWI中斷發(fā)生前,數(shù)據(jù)寄存器不能由用戶初始化。
6)(被控器)地址寄存器TWAR
file:///C:/Users/m/AppData/Local/Temp/msohtmlclip1/01/clip_image026.jpg
  TWAR寄存器高7位的內(nèi)容為被控器的7位地址字。當(dāng)TWI設(shè)置為被控接收器或被控發(fā)送器時(shí),在TWAR中應(yīng)設(shè)置被控器尋址地址。而在主控器模式下,不需要設(shè)置TWAR。
  9.2.3、電路連接
本例中的電路連接與上一實(shí)例完全相同,在此不再說明。   
  需要提醒的是,在AT24C16的接口電路中,我們?cè)陔娐钒迳显黾恿藘蓚(gè)上拉電阻,這兩個(gè)上拉電阻分別接在SCL和SDA引腳上。
9.2.4 利用硬件TWI接口實(shí)現(xiàn)I2C總線的讀寫
       1、程序功能
程序的功能是使用單片機(jī)的硬件TWI接口實(shí)現(xiàn)I2C總線的讀寫操作,然后將讀出數(shù)據(jù)通過LED指示正確與否。硬件TWI接口可以使用查詢和中斷兩種方式實(shí)現(xiàn)I2C總線的讀寫,在本實(shí)例中我們使用查詢法實(shí)現(xiàn),下一實(shí)例中我們?cè)儆懻撌褂弥袛喾绞降牟僮鳌?/font>
2函數(shù)說明
本程序多個(gè)功能函數(shù),分別是:
● TWI硬件i2c總線操作相關(guān)函數(shù):
void I2C_Init(void);                    //I2C端口初始化
unsigned char I2C_Start(void);        //發(fā)送起始信號(hào)
void I2C_Stop(void);                    //發(fā)送結(jié)束信號(hào)
unsigned char I2C_WriteByte(unsigned char dat);  //寫一個(gè)字節(jié)
unsigned char I2C_ReadByte(unsigned char ack);   //讀一個(gè)字節(jié)
unsigned char EEPROM_ReadByte(unsigned intadd); //從固定地址讀一字節(jié)
void EEPROM_WriteByte(unsigned intadd,unsigned char data);  //向固定地址寫一字節(jié)
void EEPROM_ReadPage(unsigned intadd,unsigned char n,unsigned char *data);
                                                    //多字節(jié)讀操作
void EEPROM_WritePage(unsigned intadd,unsigned char n,unsigned char *data);
                                                     //多字節(jié)寫操作
● 延時(shí)相關(guān)函數(shù):
void Delayus(unsigned intlus);         //us延時(shí)函數(shù)
void Delayms(unsigned int lms);        //ms延時(shí)函數(shù)
由于WINAVR自帶函數(shù)庫(kù)中的延時(shí)函數(shù)使用起來很不方便,并且晶振頻率不同,延時(shí)時(shí)間也有區(qū)別,所以本實(shí)例中自己寫了兩個(gè)延時(shí)函數(shù)。
    3使用WINAVR開發(fā)環(huán)境,使用的是外部12M的晶振,所以需要將makefile文件中的時(shí)鐘頻率修改為12M。另外在程序燒錄到單片機(jī)的時(shí)候,熔絲位也要選擇為外部12M晶振(注意是晶振,不是外部振蕩器,一定不要選擇錯(cuò)了,否則會(huì)導(dǎo)致單片機(jī)不能再燒寫程序)。
4、程序說明
在本實(shí)例中我們不但實(shí)現(xiàn)了使用AVR單片機(jī)的硬件TWI接口,通過查詢方法實(shí)現(xiàn)了對(duì)AT24C16的讀寫,并且通過控制LED的亮滅來指示讀出的數(shù)據(jù)是否正確。
在程序中我們使用查詢法實(shí)現(xiàn)對(duì)AT24C16的讀寫,寫操作的具體步驟是:
1TWI寄存器配置;
2)發(fā)送START信號(hào);
3)輪詢等待TWINT置位,TWINT置位表示START信號(hào)已發(fā)出;
4)發(fā)送寫器件地址,到TWDR寄存器,清零TWINT標(biāo)志位,等待TWINT再次置位,再次置位表示數(shù)據(jù)已發(fā)送完成;
5)讀取總線狀態(tài)是否是器件地址發(fā)送完成并收到ACK
6)發(fā)送數(shù)據(jù)地址,并清零TWINT標(biāo)志位,然后等待TWINT再次置位,再次置位表示數(shù)據(jù)已發(fā)送完成;
7)讀取總線狀態(tài)是否是器件地址發(fā)送完成并收到ACK
8)發(fā)送數(shù)據(jù)字節(jié),并清零TWINT標(biāo)志位,然后等待TWINT再次置位,再次置位表示數(shù)據(jù)已發(fā)送完成;
9)讀取總線狀態(tài)是否是器件地址發(fā)送完成并收到ACK
10)數(shù)據(jù)寫操作結(jié)束,發(fā)送終止信號(hào)。
讀操作的具體步驟是:
1TWI寄存器配置;
2)發(fā)送START信號(hào);
3)輪詢等待TWINT置位,TWINT置位表示START信號(hào)已發(fā)出;
4)發(fā)送寫器件地址,到TWDR寄存器,清零TWINT標(biāo)志位,等待TWINT再次置位,再次置位表示數(shù)據(jù)已發(fā)送完成;
5)讀取總線狀態(tài)是否是器件地址發(fā)送完成并收到ACK
6)發(fā)送數(shù)據(jù)地址,并清零TWINT標(biāo)志位,然后等待TWINT再次置位,再次置位表示數(shù)據(jù)已發(fā)送完成;
7)讀取總線狀態(tài)是否是器件地址發(fā)送完成并收到ACK
8)發(fā)送重復(fù)開始(RESTART)信號(hào),并清零TWINT標(biāo)志位,然后等待TWINT再次置位,再次置位表示發(fā)送重復(fù)開始信號(hào)完成;
9)發(fā)送讀數(shù)據(jù)信號(hào),并等待發(fā)送完成ACK,判斷總線狀態(tài)是否正確;
10)讀取TWDR的值,并根據(jù)是否讀取完最后一個(gè)字節(jié),發(fā)送ACKNACK
11)數(shù)據(jù)讀取完畢,發(fā)送終止信號(hào)。
5、程序代碼
由于本實(shí)例的程序量比較大,這里就不再列出了,直接放在附件里面。
9.3 使用中斷方法實(shí)現(xiàn)TWI總線的讀寫
9.3.1、實(shí)例功能
     在前面的實(shí)例中我們分別學(xué)習(xí)了使用模擬I2C總線和硬件TWI接口實(shí)現(xiàn)對(duì)AT24C16的讀寫,這兩種方法都存在編程比較復(fù)雜,代碼執(zhí)行效率低等缺點(diǎn)。在本實(shí)例中我們將學(xué)習(xí)使用中斷方法實(shí)現(xiàn)對(duì)AT24C16的讀寫;中斷方法的優(yōu)點(diǎn)是執(zhí)行效率高,不占用CPU過多時(shí)間,從而使CPU能有更多的時(shí)間處理別的任務(wù),非常適合實(shí)時(shí)多任務(wù)系統(tǒng)中使用。
本實(shí)例包括三個(gè)功能模塊,分別介紹如下:
● 單片機(jī)系統(tǒng):利用ATmega16單片機(jī)的硬件TWI接口實(shí)現(xiàn)對(duì)AT24C16的讀寫,并將讀取出來的數(shù)據(jù)通過串口發(fā)送到計(jì)算機(jī),同時(shí)利用LED指示讀出的數(shù)據(jù)是否正確。
● 外圍電路:外圍電路分三部分:串口電路部分(實(shí)現(xiàn)將讀取的數(shù)值送到計(jì)算機(jī)的功能)、LED顯示電路(指示讀取的數(shù)據(jù)是否正確)、AT24C16接口電路(實(shí)現(xiàn)對(duì)AT24C16的讀寫)。
● 軟件程序:編寫軟件,實(shí)現(xiàn)使用中斷方法對(duì)AT24C16進(jìn)行數(shù)據(jù)的讀寫。
通過本實(shí)例的學(xué)習(xí),掌握以下內(nèi)容:
● 理解使用中斷方法實(shí)現(xiàn)TWI總線的接口設(shè)計(jì)方法和程序設(shè)計(jì)。
9.3.2、器件和原理
前面的實(shí)例中我們已經(jīng)了解了TWI總線的使用方法以及I2C總線的通信協(xié)議和操作時(shí)序,在此我們不再重復(fù)。
9.3.3、電路連接
本實(shí)例的電路由三部分:串口轉(zhuǎn)換電路、LED顯示電路、AT24C16接口電路。這些電路我們?cè)谇懊嬉呀?jīng)介紹過,在此不再說明。
需要提醒的是,在AT24C16的接口電路中,我們?cè)陔娐钒迳显黾恿藘蓚(gè)上拉電阻,這兩個(gè)上拉電阻分別接在SCL和SDA引腳上。
9.3.4 程序設(shè)計(jì)
       1、程序功能
程序的功能是使用單片機(jī)的TWI硬件接口,實(shí)現(xiàn)在中斷方式下對(duì)AT24C16的讀寫,然后將讀出數(shù)據(jù)通過串口發(fā)送到計(jì)算機(jī),并且在電路板上通過LED的亮滅指示讀取的數(shù)據(jù)是否正確。
2函數(shù)說明
本程序多個(gè)功能函數(shù),分別是:
● 端口初始化函數(shù),設(shè)置各端口的初始工作狀態(tài)。
● 串口通信相關(guān)函數(shù):
void Usart_Init(void);  //USART寄存器設(shè)置
void Usart_PutChar(unsigned charcTXData);  //字節(jié)發(fā)送函數(shù)
這些函數(shù)已經(jīng)在前面的實(shí)例中做過介紹,在此不再重復(fù)。
● AT24C16操作相關(guān)函數(shù):
void I2C_Init(void);                    //I2C端口初始化
unsigned char EEPROM_ReadWrite(unsigned charI2C_Add,unsigned int add,
                                    unsignedchar n,unsigned char *data);  
     //讀寫數(shù)據(jù)操作,參數(shù)分別是:器件地址,數(shù)據(jù)地址,數(shù)據(jù)長(zhǎng)度,讀寫的數(shù)據(jù)
● 延時(shí)相關(guān)函數(shù):
void Delayus(unsigned intlus);         //us延時(shí)函數(shù)
void Delayms(unsigned intlms);        //ms延時(shí)函數(shù)
由于WINAVR自帶函數(shù)庫(kù)中的延時(shí)函數(shù)使用起來很不方便,并且晶振頻率不同,延時(shí)時(shí)間也有區(qū)別,所以本實(shí)例中自己寫了兩個(gè)延時(shí)函數(shù)。
    3使用WINAVR開發(fā)環(huán)境,使用的是外部12M的晶振,所以需要將makefile文件中的時(shí)鐘頻率修改為12M。另外在程序燒錄到單片機(jī)的時(shí)候,熔絲位也要選擇為外部12M晶振(注意是晶振,不是外部振蕩器,一定不要選擇錯(cuò)了,否則會(huì)導(dǎo)致單片機(jī)不能再燒寫程序)。
4、程序說明
在本實(shí)例中我們不但實(shí)現(xiàn)了使用AVR單片機(jī)的硬件TWI接口,通過中斷方法實(shí)現(xiàn)了對(duì)AT24C16的讀寫,并且將讀出的數(shù)據(jù)通過串口發(fā)送到計(jì)算機(jī)進(jìn)行顯示,同時(shí)通過控制LED的亮滅來指示讀出的數(shù)據(jù)是否正確。
     使用中斷方法的處理步驟和查詢法的步驟基本一致,不同之處在于在中斷方式下不用使程序在等待中斷標(biāo)志位置位時(shí)一直處于等待狀態(tài),而是在中斷標(biāo)志置位后自動(dòng)進(jìn)入中斷處理函數(shù)。      

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表