單片機學習之二十:E2PROM芯片24C02的讀寫程序
一、實驗目的:
給24C02的內(nèi)部RAM寫入一組數(shù)據(jù),數(shù)據(jù)從24C02內(nèi)部RAM的01h開始存放。然后再把這組數(shù)據(jù)讀出來,檢驗寫入和讀出是否正確。
在這里我們給24C02中寫入0、1、2的段碼,然后把它讀出來,送到數(shù)碼管顯示。
二、理論知識準備:
上面兩個實驗主要學習的是利用單片機的串口進行通訊,本實驗要介紹的是基于I2C總線的串行通訊方法,下面我們先介紹一下I2C總線的相關理論知識。
(一)、I2C總線概念
I
(二)、I2C總線結(jié)構(gòu)
I
一個典型的I2C總線應用系統(tǒng)的組成結(jié)構(gòu)如下圖所示(假設圖中的微控制器、LCD驅(qū)動、E2PROM、ADC各器件都是具有I2C總線接口的器件):
我們知道單片機串行通訊的發(fā)送和接收一般都各用一條線TXD和RXD,而I2C總線的數(shù)據(jù)線既可以發(fā)送也可以接受,工作方式可以通過軟件設置。所以,I2C總線結(jié)構(gòu)的硬件結(jié)構(gòu)非常簡潔。
當某器件向總線上發(fā)送信息時,它就是發(fā)送器,而當其從總線上接收信息時,又成為接收器。
(三)、I
下面我們看看I2C總線是如何進行數(shù)據(jù)傳送的。我們知道,在一根數(shù)據(jù)線上傳送數(shù)據(jù)時必須一位一位的進行,所以我們首先研究位傳送。
1、位傳輸
I
那么是不是所有I2C總線中的信號都必須符合上述的有效性呢?只有兩個例外,就是開始和停止信號。
開始信號:當SCL為高電平時,SDA發(fā)生從高到低的跳變,就定義為開始信號。
停止信號:當SCL為高電平時,SDA發(fā)生從低到高的跳變,就定義為結(jié)束信號。
開始和結(jié)束信號的時序圖如下圖所示:
2、數(shù)據(jù)傳輸?shù)淖止?jié)格式
SDA傳送數(shù)據(jù)是以字節(jié)為單位進行的。每個字節(jié)必須是8位,但是傳輸?shù)淖止?jié)數(shù)量不受限制,首先傳送的是數(shù)據(jù)的最高位。每次傳送一個字節(jié)完畢,必須接收到從機發(fā)出的一個應答位,才能開始下一個字節(jié)的傳輸。如果沒有接受到應答位,主機則產(chǎn)生一個停止條件結(jié)束本次的傳送。那么從機應該發(fā)出什么信號算是產(chǎn)生了應答呢?這個過程是這樣的。當主器件傳送一個字節(jié)后,在第9個SCL時鐘內(nèi)置高SDA線,而從器件的響應信號將SDA拉低,從而給出一個應答位。
好啦,了解了I2C傳輸數(shù)據(jù)的格式,現(xiàn)在來研究雙方傳送的協(xié)議問題。
3、 I
I
(1)、主器件發(fā)出開始信號
(2)、主器件發(fā)出第一個字節(jié),用來選通相應的從器件。其中前7位為地址碼,第8位為方向位(R/W)。方向位為“0”表示發(fā)送,方向位為“1”表示接受。
(3)、從機產(chǎn)生應答信號,進入下一個傳送周期,如果從器件沒有給出應答信號,此時主器件產(chǎn)生一個結(jié)束信號使得傳送結(jié)束,傳送數(shù)據(jù)無效。
(4)、接下來主、從器件正式進行數(shù)據(jù)的傳送,這時在I2C總線上每次傳送的數(shù)據(jù)字節(jié)數(shù)不限,但每一個字節(jié)必須為8位(傳送的時候先送高位,再送低位)。當一個字節(jié)傳送完畢時,再發(fā)送一個應答位(第9位),如上一條所述,這樣每次傳送一個字節(jié)都需要9個時鐘脈沖。數(shù)據(jù)的傳送過程如下圖所示:
(四)、
AT
我們對引腳的功能作一個簡單的解釋:
VCC,GND:電源、地引腳
A
SCLK、SDA:通信引腳
WP:寫保護引腳
從上面的電路連接知:A2A1A0=000,可見如果要對24C02進行寫操作,尋址字節(jié)是1010 000 0;如果對24C02進行讀操作,尋址字節(jié)是1010 000 1。用單片機的P1.6腳作為串行時鐘線,用P1.7腳作串行數(shù)據(jù)線。
(五)、程序分析
寫過程:
(1)、主機首先發(fā)出開始信號
(2)、發(fā)出寫24C02的尋址字節(jié)1010 000 0,即0A0H
(3)、發(fā)數(shù)據(jù)寫入24C02的地址,本例中為01H
(4)、往24C02中寫入數(shù)據(jù),這里是3個字節(jié),分別為48h,0ebh,52h。
(5)、寫完畢發(fā)出停止信號
讀過程:
(1)、主機發(fā)出start信號
(2)、發(fā)寫24C02的尋址字節(jié)1010 000 0
(大家可能要問:我們是讀數(shù)據(jù),為什么要發(fā)寫信號呢?這是因為你首先要送出一個信號,說明從24C02中的哪個地址讀取數(shù)據(jù)。)
(3)、發(fā)要讀取的數(shù)據(jù)在24C02中的地址,即01h
(4)、主機發(fā)start信號
(5)、發(fā)讀24C02的尋址字節(jié)1010 000 1
(5)、從24 C02中讀取數(shù)據(jù)
(6)、讀取完畢發(fā)出停止信號
在這個程序中,我們把開始信號,結(jié)束信號、寫一個字節(jié)數(shù)據(jù)、讀一個字節(jié)數(shù)據(jù)都編制成為通用的子程序,便于在程序中隨時調(diào)用。發(fā)送和接受應答位的過程放到子程序中,這樣可以使得程序結(jié)構(gòu)簡化。具體的程序如下所示,希望大家認真理解。
三、實驗程序
Org 0000h
I2cdata equ 30h ;發(fā)送數(shù)據(jù)緩沖區(qū)的首址
2402data equ 01h ;接受緩沖區(qū)首址
numdata equ 03h ;傳送的字節(jié)數(shù),傳送3個字節(jié)
Sda bit p1.7
Scl bit p1.6
Ajmp main
Main: Lcall init ;初始化給30h,31h,32h中存入0,1,2的段碼
Mainwr: Lcall start ;啟動
Mov r7,#
Lcall send ;發(fā)送寫
Mov r7,#2402data
Lcall send ;發(fā)送數(shù)據(jù)存入
Mov r5,#Numdata ;欲發(fā)送的字節(jié)數(shù)
Mov r0,#i2cdata ;發(fā)送緩沖區(qū)的首址
wrloop: Mov a,@r0
Mov r7,a
Inc r0
Lcall send
Djnz r5, wrloop ;把3個字節(jié)的數(shù)據(jù)發(fā)送出去
lcall stop ;停止
lcall d1s
mov r5,#Numdata ; 要讀取的字節(jié)數(shù)重新賦值
Mainre: lcall start ;啟動
Mov r7,#
Lcall send ;發(fā)送寫
Mov r7,#2402data
Lcall send ;發(fā)接受緩沖區(qū)首址
Lcall start ; 再次啟動
Mov r7,#
Lcall send ;發(fā)送讀
Reloop: Lcall read ;調(diào)用讀取一個字節(jié)數(shù)據(jù)的子程序
mov p0,r7 ;把讀進來的數(shù)送到p0口顯示
lcall d1s
lcall d1s
Djnz r5,reloop
Lcall stop ;3字節(jié)讀取完畢發(fā)出停止信號
Ajmp $
init: mov p2,#0ffh ;初始化,30h、31h、32h中存入0、1、2的段碼
mov 30h,#48h
mov 31h,#0ebh
mov 32h,#52h
ret
start: setb sda ;啟動信號子程序,大家可以參考開始信號的時序圖
setb scl
lcall d5u
clr sda
lcall d5u
clr scl
ret
stop: clr sda ;停止信號子程序
setb scl
lcall d5u
setb sda
lcall d5u
clr sda
clr scl
ret
;send是發(fā)送一個字節(jié)子程序
send: mov r6,#08h
mov a,r7 ;要發(fā)送的數(shù)在r7中
sendlop1 : rlc a ;左環(huán)移,把A的最高位移入cy
mov sda,c ;把cy的值通過sda發(fā)送出去
setb scl ;在scl上產(chǎn)生一個時鐘
lcall d5u
clr scl
djnz r6, sendlop1 ;重復8次,發(fā)送一個字節(jié)
;cack是檢查應答信號的子程序
cack: setb sda ;主機首先拉高sda
setb scl ;發(fā)出一個時鐘
lcall d5u
sendlop2:mov c,sda ;讀入sda的狀態(tài),如果是0表示接受到了應答
jc sendlop2
clr scl ;接受到應答位,結(jié)束時鐘
ret
read: mov r6,#08h ;讀取一個字節(jié)子程序
readlop1: setb sda ;置sda為輸入方式
setb scl ;發(fā)出一個時鐘
lcall d5u
mov c,sda ;讀入sda狀態(tài)
rlc a ;把該位的狀態(tài)移入A中
clr scl ;結(jié)束時鐘
djnz r6,readlop1 ;重復8次,讀入一個字節(jié)
mov r7,a ;讀進來的數(shù)放在r7中
;sack是發(fā)送應答位子程序
sack: clr sda ;拉低sda線
setb scl ;發(fā)出時鐘信號
lcall d5u
clr scl
setb sda
ret
d5u: nop ;延時5us子程序
nop
nop
nop
nop
ret
d1s: mov r1,#100 ;延時1s子程序
del1: mov r4,#20
del2: mov r3,#0ffh
del3: djnz r3,del3
djnz r4,del2
djnz r1,del1
ret
end
大家把這個程序下載到測試板上面,發(fā)現(xiàn)數(shù)碼管依次顯示數(shù)字0、1、2
評論