?? text2.asm
字號:
;*****************************************************************
;name:測溫傳感器DS18B20和24C02的結(jié)合應(yīng)用
;bye :zxinfeng
;dat :05.08.07
;功能:主要目的是one-wrie協(xié)議和I2C協(xié)議的綜合運用。
;數(shù)字溫度計測溫范圍為-50-125度,精度誤差在0.1度之內(nèi)
;LED直接讀顯示溫度.在顯示的過程中,如果有按鍵按下且是功能鍵盤的話,
;就判斷是哪個功能鍵,KEY10把當(dāng)前顯示的溫度值存入24C02,KEY11把已經(jīng)
;存入到24C02中的數(shù)調(diào)用顯示在數(shù)碼管的前四位上;KEY12把已經(jīng)存入到24C02
;中的數(shù)清,同時,數(shù)碼管前四位顯示0
;*****************************************************************
scl bit p3.6 ;24C02與單片機(jī)接口
sda bit p3.7
ack bit 29h ;24C02應(yīng)答位變量
flag equ 2ah ;按鍵標(biāo)志位
dat equ p3.0 ;18B20與單片機(jī)接口
temph equ 30h ;讀18B20溫度存放寄存器
templ equ 31h
sla data 32h ;24c02器件從地址變量
suba data 33h ;24c02器件子地址變量
bcd_0 equ 34h ;溫度小數(shù)位寄存器,同時32H也是24C02發(fā)送緩沖區(qū)首址
bcd_1 equ 35h ;個位
bcd_10 equ 36h ;十位
bcd_100 equ 37h ;百位
tempzheng equ 38h ;18b20的溫度調(diào)整好存放寄存器
lie equ 39h ;鍵盤掃描列數(shù)寄存器
keyvalue equ 3ah ;鍵值寄存器
mrd equ 3bh ;24c02接收緩沖區(qū)首址
mrd1 equ 3ch
mrd2 equ 3dh
mrd3 equ 3eh
;-------------------------程序開始----------------------
org 0000h
ajmp main
main: nop
mov sp,#55h
lcall proinit
loop:
lcall get_temper ;調(diào)用得到溫度程序
lcall read_temper ;調(diào)用讀溫度程序
lcall display
lcall keyscan
mov a,flag
cjne a,#0ffh,next ;無鍵接下,跳轉(zhuǎn)
mov a,keyvalue ;有鍵按下,判斷大不大于10
cjne a,#9,next1 ;以確定是不是功能鍵
next: ajmp loop ;是數(shù)字鍵,返回
next1: jc next ;小于9(即C=0),轉(zhuǎn)數(shù)字鍵處理
lcall canskey ;是功能鍵,調(diào)用相應(yīng)的程序
ajmp loop
;--------程序初始化程序------------
proinit:
clr f0
clr ack
mov p3,#0
mov templ,#0
mov temph,#0
mov bcd_0,#0
mov bcd_1,#0
mov bcd_10,#0
mov bcd_100,#0
mov mrd,#0
mov mrd1,#0
mov mrd2,#0
mov mrd3,#0
mov sla,#0
mov suba,#0
mov lie,#0
mov keyvalue,#0
ret
;------------------------------------------------------------
;取得溫度程序段
;啟動溫度轉(zhuǎn)換命令,這時候,DS18B20開始開始測得溫度并把其存入TH處TL中
;用到寄存器有:R2、R4
;------------------------------------------------------------
get_temper:
lcall ds18b20init ;發(fā)ds18b20復(fù)位和存在脈沖
jnb f0,get_end
mov a,#0cch ;總線上只有一個18B20,使用跳過ROM就可以了
lcall writebyte ;寫一個字節(jié)程序段
mov a,#44h ;發(fā)溫度轉(zhuǎn)換命令
lcall writebyte
get_end:
ret
;-------------------------------------------------------------
;讀出溫度程序段
;先發(fā)送DS18B20復(fù)位脈沖和跳過ROM,(每次對寄存器操作之前,
;都要有這兩步)之后,讀取暫存區(qū)的溫度值,并進(jìn)行調(diào)整.
;用到寄存器有R2、R4、R5、R0,出口參數(shù):31H(TEMPH)、30H(TEMPL)
;tempzheng(38h)
;-------------------------------------------------------------
read_temper:
lcall ds18b20init
jnb f0,read_end
mov a,#0cch
lcall writebyte ;再次跳過ROM
mov a,#0beh ;讀暫存器內(nèi)部命令
lcall writebyte
lcall readtemp ;調(diào)用讀RAM程序
;把1820中的溫度值計到CPU中的程序段
lcall temp_cov ;把讀出的溫度值進(jìn)行調(diào)整(因為整數(shù)部分在TH的低四位和TL的高四位
;要把它們調(diào)整到一個寄存器里面)
read_end:
ret
;---------ds18b20復(fù)位和存在脈沖----------
ds18b20init:
clr ea
int10: setb dat
nop
mov r2,#200
int11: clr dat ;p3.0作為在DS18B20的單線接口
djnz r2,int11 ;主機(jī)復(fù)位脈沖是3us*200=600us,(18B20停在低電平超過480us會發(fā)生復(fù)位)
setb dat ;釋放總線
mov r2,#30 ;延時60us,等待狀態(tài)穩(wěn)定
int12: djnz r2,int12
clr c
orl c,dat ;看總線有沒有變低(即有沒有存在脈沖)
jc endint ;C中的數(shù)=1,表示DAT是高電平,沒有存在脈沖,返回主程序
setb f0 ;有DS18B02存在,建立存在標(biāo)志位。
mov p1,#0feh ;存在DS18B20,使P1.0口的燈亮
mov r2,#120
int13: djnz r2,int13 ;延時240us,這是存在脈沖的時間
clr c
orl c,dat
jnc int13
ret
endint:
clr f0
mov p1,#7fh ;不存在,使p1.1口的LED亮
ret
;----------DS18B20寫一個字節(jié)子程序--------
writebyte:
clr ea
mov r4,#8 ;要寫入的字節(jié)數(shù)
setb dat
nop
nop
wr10: clr dat
mov r2,#8
wr11: djnz r2,wr11 ;等待16us
rrc a
mov dat,c
mov r2,#40
wr12: djnz r2,wr12
setb dat
djnz r4,wr10
ret
;-----把DS18B20中的溫度值讀到CPU中的程序段-----
readtemp:
mov r5,#2 ;將溫度高位和低位都讀出
mov r0,#31h ;將低位存入31H,(高位存入30H)
rd10: clr ea
clr c
mov r4,#8
setb dat
nop
nop
rd11:
clr dat
nop
nop
nop
setb dat ;上述幾條指令,是為了產(chǎn)生讀時間隙
mov r2,#8
rd12: djnz r2,rd12 ;等待狀態(tài)穩(wěn)定,delay16us
mov c,dat ;依次讀入DS18B20的數(shù)據(jù)
rrc a
mov r2,#30
rd14: djnz r2,rd14 ;延時60us
djnz r4,rd11 ;判斷8位讀出完沒有?
mov @r0,a ;把讀出的數(shù)送出
dec r0
djnz r5,rd10 ;判斷16位是否全讀出,沒有的話反回繼續(xù)讀
setb dat
ret
;------------DS18B20溫度調(diào)整程序-----------
temp_cov:
mov a,temph
anl a,#80h
jz tempz ;最高位是0,跳到正數(shù)處理
ajmp tempf ;最高位是1,跳到負(fù)數(shù)處理
ret
tempf:
clr c
mov a,templ
cpl a
add a,#01h ;取反后的結(jié)果加1,這是補(bǔ)碼的形式
mov templ,a
mov a,temph
cpl a
addc a,#00h
mov temph,a
tempz:
mov a,templ
anl a,#0fh ;屏蔽掉高四位,只保留小數(shù)部分
mov dptr,#temptab
movc a,@a+dptr
mov bcd_0,a ;把小數(shù)部分BCD碼送入bcd_0
mov a,templ ;整數(shù)部分
anl a,#0f0h
swap a
mov templ,a
mov a,temph
anl a,#0fh
swap a
orl a,templ ;把整數(shù)部分在高低兩個寄存器里的值,合到一個寄存器里
mov tempzheng,a ;把整合到一起的整數(shù)放在整數(shù)寄存器里
lcall p16_bcd
ret
;---------------------------------------
p16_bcd:
mov a,tempzheng
mov b,#100
div ab
mov bcd_100,a ;把百位數(shù)存放在R7中
mov a,b ;把低位再次取到A中
mov b,#10
div ab
mov bcd_10,a ;十位數(shù)入BCD_10
mov bcd_1,b ;個位數(shù)入bcd_1
ret
;--------------------------------------------------------------
;鍵盤掃描程序段
;判斷有無按鍵按下,并求得按鍵值
;用到R3、R4、flag、lie、出口參數(shù)是keyvalue
;--------------------------------------------------------------
keyscan:
lcall keys ;判斷有鍵按下沒有
jnz keyd
ajmp knd ;沒有按鍵按下反回主程序(不返回keyscan,
;是為了在沒有按鍵的情況下,執(zhí)行顯示程序,實現(xiàn)動態(tài)掃描。)
keyd: acall delay8ms
acall keys
jz knd ;同上
mov flag,#0ffh
mov a,#0efh
mov lie,a
mov p2,a
mov r4,#00h ;列號送給r4
loop1: mov a,p2
jb acc.0,lone ;無鍵按下,轉(zhuǎn)查第一行
mov r3,#0 ;;首行鍵號入r3
ljmp keyacc
lone: jb acc.1,ltwo
mov r3,#4
ljmp keyacc
ltwo: jb acc.2,lthr
mov r3,#8
ljmp keyacc
lthr: jb acc.3,next3 ;第三行無鍵按下,改查下一列
mov r3,#12
ljmp keyacc
next3:
jnb acc.7,knd ;查到最后一列沒有
inc r4
mov a,lie
rl a
mov lie,a ;修改LIE中的數(shù)值
mov p2,a
ajmp loop1
keyacc: mov a,r3
add a,r4
mov keyvalue,a
wait: acall keys ;等待鍵釋放
jnz wait
ret
keys: mov a,#0fh ;判斷有沒有鍵按下的程序斷
mov p2,a
mov a,p2
cpl a ;變正邏輯,以高電平表示有鍵按下
anl a,#0fh
ret
knd: mov flag,#00h
ret ;查到最后一列,沒有鍵按下,屬于誤操作,返回
;-------------------------------------------------------------
;功能鍵處理程序段
;-------------------------------------------------------------
canskey:
cjne a,#10,cannext1
lcall iwrnbyte ;轉(zhuǎn)到存入子程序
ajmp endcan
cannext1:
cjne a,#11,cannext2
lcall irdnbyte ;轉(zhuǎn)入調(diào)出子程序
lcall r_display ;把調(diào)出的數(shù)字送顯
ajmp endcan
cannext2:
cjne a,#12,endcan
lcall clear0 ;轉(zhuǎn)到清零24c02子程序
endcan: ret
;--------------------------------------------
;24C02處理程序段
;--------------------------------------------
;------向器件指定地址寫數(shù)據(jù)------
iwrnbyte:
mov 39h,#4
mov sla,#0a0h
mov suba,#00h ;指定器件內(nèi)部地址,即要把數(shù)據(jù)存放在24C02中的區(qū)域!!!
wrloop:
lcall start ;調(diào)用啟動I2C總線子程序
mov a,sla ;指定器件地址
lcall wrbyte ;指定器件地址后,調(diào)用發(fā)送字節(jié)子程序
lcall cack ;調(diào)用檢查應(yīng)答位子程序
jnb ack,endiwr ;無應(yīng)答,退出
mov a,suba
lcall wrbyte ;指定器件地址后,調(diào)用發(fā)送字節(jié)子程序
lcall cack ;調(diào)用檢查應(yīng)答位子程序
mov a,bcd_0
lcall wrbyte ;開始寫入數(shù)據(jù)(其入口參數(shù)是ACC,所以有上述兩條指令)
lcall cack
jnb ack,wrloop
mov a,bcd_1
lcall wrbyte ;開始寫入數(shù)據(jù)(其入口參數(shù)是ACC,所以有上述兩條指令)
lcall cack
jnb ack,wrloop
mov a,bcd_10
lcall wrbyte ;開始寫入數(shù)據(jù)(其入口參數(shù)是ACC,所以有上述兩條指令)
lcall cack
jnb ack,wrloop
mov a,bcd_100
lcall wrbyte ;開始寫入數(shù)據(jù)(其入口參數(shù)是ACC,所以有上述兩條指令)
lcall cack
jnb ack,wrloop
endiwr: lcall stop ;數(shù)據(jù)寫完,調(diào)用結(jié)束總線子程序
ret
;-------從24C02指定地址讀取數(shù)據(jù)------
irdnbyte:
mov 40h,#4 ;要讀出的字節(jié)數(shù)
mov sla,#0a0h
mov r1,#00h ;確定24C02內(nèi)部地址
mov r0,#mrd ;把接收緩沖區(qū)首址送給R0.
rdloop:
lcall start
mov a,sla
lcall wrbyte ;指定器件地址后,調(diào)用發(fā)送字節(jié)子程序
lcall cack ;調(diào)用檢查應(yīng)答位子程序
jnb ack,endird ;無應(yīng)答,退出
mov a,r1
lcall wrbyte
lcall cack
lcall start ;重新啟動總線
; mov a,sla ;讀取第0個寄存器的內(nèi)容
; inc a ;準(zhǔn)備進(jìn)行讀操作
mov a,#0a1h ;代替上面兩條指令
lcall wrbyte ;把24C02中00單元的內(nèi)容寫到總線上
lcall cack
jnb ack,irdnbyte
lcall rdbyte ;讀操作開始 (讀操作的出口參數(shù)是ACC)
mov @r0,a ;從低字節(jié)開始讀取到顯示緩沖區(qū)
inc r0
inc r1
djnz 40h,rdloop
endird: lcall stop
ret
;--------------------------------
;把24C02中存儲的數(shù)清0,即再次向24c02的存儲區(qū)中寫0
clear0:
mov 42h,#4
mov sla,#0a0h ;指定地址
mov r1,#00h ;指定器件子地址
clearloop:
lcall start ;調(diào)用啟動I2C總線子程序
mov a,sla
lcall wrbyte ;指定器件地址后,調(diào)用發(fā)送字節(jié)子程序
lcall cack ;調(diào)用檢查應(yīng)答位子程序
jnb ack,endc ;無應(yīng)答,退出
mov a,r1
lcall wrbyte ;指定器件地址后,調(diào)用發(fā)送字節(jié)子程序
lcall cack ;調(diào)用檢查應(yīng)答位子程序
mov a,#0 ;把00H寫到SDA總線上,再送入24C02內(nèi)部(即清0)
lcall wrbyte ;開始寫入數(shù)據(jù)(其入口參數(shù)是ACC,所以有上一條指令)
lcall cack
jnb ack,clearloop
mov a,#0 ;把00H寫到SDA總線上,再送入24C02內(nèi)部(即清0)
lcall wrbyte ;開始寫入數(shù)據(jù)(其入口參數(shù)是ACC,所以有上一條指令)
lcall cack
jnb ack,clearloop
mov a,#0 ;把00H寫到SDA總線上,再送入24C02內(nèi)部(即清0)
lcall wrbyte ;開始寫入數(shù)據(jù)(其入口參數(shù)是ACC,所以有上一條指令)
lcall cack
jnb ack,clearloop
mov a,#0 ;把00H寫到SDA總線上,再送入24C02內(nèi)部(即清0)
lcall wrbyte ;開始寫入數(shù)據(jù)(其入口參數(shù)是ACC,所以有上一條指令)
lcall cack
jnb ack,clearloop
mov mrd,#0
mov mrd1,#0
mov mrd2,#0
mov mrd3,#0
lcall r_display ;清0之后,把MTD中的數(shù)送顯,給人能看出清0的結(jié)果
endc: lcall stop
ret
;---------啟動I2C總線子程序-------
start:
setb sda
nop
setb scl ;發(fā)送開始條件的時鐘信號
lcall delay4ms
clr sda
lcall delay4ms
clr scl ;鎖住總線,準(zhǔn)備發(fā)送數(shù)據(jù)
nop
ret
;結(jié)束子程序
stop:
clr sda
nop
setb scl ;發(fā)送結(jié)束條件的時鐘信號
lcall delay4ms
setb sda ;結(jié)束總線
lcall delay4ms
ret
;檢查應(yīng)答位子程序(返回值,ACK=1時。表示有應(yīng)答)
cack:
setb sda
nop
nop
setb scl
clr ack
nop
nop
mov c,sda
jc cend
setb ack
cend: nop
clr scl
nop
ret
;寫字節(jié)子程序
wrbyte:
mov r2,#8 ;要發(fā)送的位數(shù)送R0
wlp: rlc a ;取移位數(shù)據(jù)(調(diào)用前已經(jīng)把求得的鍵值送入ACC了)
jc wr1 ;C=0,轉(zhuǎn)到WR1
sjmp wr3
wlp1: djnz r2,wlp
nop
ret
wr3: clr sda ;發(fā)送0
nop
setb scl
lcall delay4ms
clr scl
sjmp wlp1
wr1: setb sda ;發(fā)送1
nop
setb scl
lcall delay4ms
clr scl
sjmp wlp1
;讀取字節(jié)子程序
rdbyte:
mov r2,#08h
rlp: setb sda
nop
setb scl ;時鐘線為高,接收數(shù)據(jù)
nop
nop
mov c,sda ;讀取數(shù)據(jù)位
clr scl
rlc a
nop
nop
nop
nop
djnz r2,rlp
ret
;--------------------------------------------------------------
;顯示子程序
;后四位顯示的是DS18B20測得的溫度,
;前四位顯示的是24C02中存儲的溫度值
;入口參數(shù)是tempzheng
;--------------------------------------------------------------
display:
mov a,bcd_0 ;小數(shù)位顯示程序
anl a,#0fh ;把其中的整數(shù)部分屏蔽掉.
orl a,#70h
mov p0,a
lcall delay8ms
mov a,bcd_1
orl a,#60h ;打開相應(yīng)的位選(第二位)
mov p0,a
lcall delay8ms
mov a,bcd_10
orl a,#50h
mov p0,a
lcall delay8ms
mov a,bcd_100
orl a,#40h
mov p0,a
lcall delay8ms
r_display:
mov a,mrd
orl a,#30h
mov p0,a
acall delay8ms
mov a,mrd1
orl a,#20h
mov p0,a
acall delay8ms
mov a,mrd2
orl a,#10h
mov p0,a
acall delay8ms
mov a,mrd3
orl a,#00h
mov p0,a
acall delay8ms
ret
;-----------------延時程序------------------------------
delay4ms:
nop
nop
nop
nop
nop
ret
delay8ms:
mov r6,#2h
d: mov r7,#20h
d0: djnz r7,d0
djnz r6,d
ret
;--------------小數(shù)部分表----------------------------
temptab:
db 00h,00h,01h,01h,02h,03h,03h,04h,05h,05h,06h
db 06h,07h,08h,08h,09h,09h
;----------------------------------------------------
end
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -