;**********************************************************************
;晶振為12MHZ,顯示實時時間,溫度
;測量溫度范圍為-55~+99攝氏度
;***********************************************************************
T_RST EQU P1.5 //DS1302復位線引腳
T_CLK EQU P1.6 //DS1302時鐘線引腳
T_IO EQU P1.7 //DS1302數據線引腳
TEM_L EQU 40H //存放從DS18B20中讀出的高、低位溫度值
TEM_H EQU 41H
TEM_NUM EQU 42H //存放溫度轉換后的整數部分
FLAG0 EQU 45H //FLAG0存放溫度的符號
DQ EQU P2.3 //DS18B20數據線
RS BIT P2.0 //LCD控制線定義
RW BIT P2.1
E BIT P2.2
SKIP_B20 EQU 0CCH //DS18B20跳過ROM命令
START_B20 EQU 44H //DS18B20溫度變換命令
READDS EQU 0BEH //DS18B20讀暫存器命令
ORG 0000H
AJMP MAIN
ORG 0100H
MAIN: MOV SP,#90H
ACALL LCD_INT //進行LCD初始化
MOV A,#8BH //在LCD第一行第12列顯示WEEK
LCALL W_COM
MOV A,#57H //字母'W'的字符庫為01010111
LCALL W_DAT
MOV A,#45H //字母'E'的字符庫為01000101
LCALL W_DAT
MOV A,#45H
LCALL W_DAT
MOV A,#4BH //字母'K’的字符庫為01001011
LCALL W_DAT
MOV A,#0C0H //第二行第一列顯示TIME
LCALL W_COM
MOV A,#54H //字母'T'的字符庫為01010100
LCALL W_DAT
MOV A,#49H //字母'I'的字符庫為01001001
LCALL W_DAT
MOV A,#4DH //字母'M'的字符庫為01001101
LCALL W_DAT
MOV A,#45H //字母'E'的字符庫為01000101
LCALL W_DAT
MOV 60H,#00H //設置秒存儲單元
MOV 61H,#00H //設置分存儲單元
MOV 62H,#16H //設置時存儲單元
MOV 63H,#05H //設置日存儲單元
MOV 64H,#01H //設置月存儲單元
MOV 65H,#03H //設置星期存儲單元
MOV 66H,#18H //設置年存儲單元
LCALL SET1302 //向DS1302寫入時間
REP: LCALL GET1302 //讀出時間
LCALL GET_TEM //讀出轉換后的溫度值
LCALL TEM_COV
;;;;;;;;;;在LCD第一行顯示年月日和星期;;;;;;;;;;
MOV A,#80H //顯示在LCD第一行第一列
LCALL W_COM //調用LCD寫命令子程序
MOV A,#'2'
ACALL W_DAT //調用LCD寫數據子程序
MOV A,#'0'
ACALL W_DAT
MOV A,56H //年拆分成十位與個位,轉換字符顯示
MOV B,#10H
DIV AB
ADD A,#30H //數字的字符庫從00110000B即30H開始
ACALL W_DAT
MOV A,B
ADD A,#30H
ACALL W_DAT
MOV A,#'-'
ACALL W_DAT
MOV A,54H //月拆分成十位與個位,轉換字符顯示
MOV B,#10H
DIV AB
ADD A,#30H
ACALL W_DAT
MOV A,B
ADD A,#30H
ACALL W_DAT
MOV A,#'-'
ACALL W_DAT
MOV A,53H //日拆分成十位與個位,轉換字符顯示
MOV B,#10H
DIV AB
ADD A,#30H
ACALL W_DAT
MOV A,B
ADD A,#30H
ACALL W_DAT
MOV A,#8FH //設置LCD顯示星期的位置為第一行第十六列
LCALL W_COM
MOV A,55H //顯示星期
ADD A,#30H
LCALL W_DAT
;;;;;;;;;;在LCD第二行顯示時分秒和溫度;;;;;;;;;;;;;
MOV A,#0C4H //寫入顯示緩沖區的起始地址為第二行第五列開始
LCALL W_COM
MOV A,52H //小時拆分成十位與個位,轉換字符顯示
MOV B,#10H
DIV AB
ADD A,#30H
LCALL W_DAT
MOV A,B
ADD A,#30H
LCALL W_DAT
MOV A, #':'
LCALL W_DAT
MOV A,51H //分拆分成十位與個位,轉換字符顯示
MOV B,#10H
DIV AB
ADD A,#30H
LCALL W_DAT
MOV A,B
ADD A,#30H
LCALL W_DAT
MOV A, #':'
LCALL W_DAT
MOV A,50H //秒拆分成十位與個位,轉換字符顯示
MOV B,#10H
DIV AB
ADD A,#30H
LCALL W_DAT
MOV A,B
ADD A,#30H
LCALL W_DAT
MOV A,#0CDH //溫度顯示在LCD第二行第十四列
LCALL W_COM
MOV A,FLAG0 //顯示溫度正負號
ACALL W_DAT
MOV A,TEM_NUM //溫度整數拆分成十位和個位顯示
MOV B,#0AH
DIV AB //商送給A,余數送給B
ADD A,#30H
CJNE A,#30H,REP1 //如果十位為0,則不顯示
MOV A,#20H //字符庫中00100000B(20H)為空白
REP1: ACALL W_DAT //調用LCD寫數據子程序
MOV A,B //將求得的余數送給A
ADD A,#30H
ACALL W_DAT //調用LCD寫數據子程序
LJMP REP
/******************時間**************************/
;;;;;;;;累加器A寫一字節到DS1302;;;;;;;;;;;;;
WE: MOV 70H,#08H //一個字節八位,移動八次
INB1: MOV A,B //將命令字送給A
RRC A //通過A移入進位標志位C
MOV B,A
MOV T_IO,C //移入到芯片內
SETB T_CLK
CLR T_CLK
DJNZ 70H,INB1
RET
;;;;;;;;讀一字節到累加器A中;;;;;;;;;;;;;;;;;
READ: MOV 70H,#08H //一個字節八位,移動八次
OUTB1: MOV C,T_IO //從芯片內移動到進位標志位C
RRC A //通過C再移入累加器A中
SETB T_CLK
CLR T_CLK
DJNZ 70H,OUTB1
RET
;;;;;;;;;向DS1302寫入時間子程序;;;;;;;;;;;;;;
SET1302:CLR T_RST //RST引腳為低電平,數據傳送終止
CLR T_CLK //清零時鐘總線
SETB T_RST //RST引腳為高電平,邏輯控制有效
MOV B,#8EH //控制命令字(10001110-進行存取時間,寫操作)
LCALL WE //調用寫字節命令
MOV B,#00H //寫操作前清寫保護位W
LCALL WE
SETB T_CLK
CLR T_RST
MOV R0,#60H //秒 分 時 日 月 星期 年 數據存儲在60-66H單元
MOV R7,#07H //共7個字節
MOV R1,#80H //寫秒寄存器命令
S1: CLR T_RST
CLR T_CLK
SETB T_RST
MOV B,R1 //寫入寫秒指令
LCALL WE
MOV A,@R0 //將秒存儲單元中的數值送給A
MOV B,A
LCALL WE
INC R0 //R0加一,指向下一個寫入的日歷、時鐘數據
INC R1 //指向下一個時間寄存器
INC R1
SETB T_CLK
CLR T_RST
DJNZ R7,S1
CLR T_RST
CLR T_CLK
SETB T_RST
MOV B,#8EH //控制命令字(10001110-進行存取時間,寫操作)
LCALL WE
MOV B,#80H //控制寄存器中WP置1
LCALL WE
SETB T_CLK
CLR T_RST //結束寫過程
RET
;;;;;;;;;;;;;;;讀時間子程序;;;;;;;;;;;;;;;;;
GET1302:MOV R0,#50H
MOV R7,#7
MOV R1,#81H //讀秒寄存器命令
G1: CLR T_RST
CLR T_CLK
SETB T_RST
MOV B,R1 //寫入讀秒寄存器命令
LCALL WE
LCALL READ
MOV @R0,A //存入讀出數據
INC R0 //指向下一個存放日歷、時鐘的存儲單元
INC R1 //指向下一個日歷、時鐘寄存器
INC R1
SETB T_CLK
CLR T_RST
DJNZ R7,G1 //未讀完,繼續讀下一個
RET
/********************溫度************************/
;;;;;;;;;;;;;;DS18B20復位程序;;;;;;;;;;;;;;;;;
B20_INT:SETB DQ //將數據線置高電平“1”
NOP //延時
NOP
CLR DQ //數據線拉到低電平“1”
MOV R7,#0CH //延時60*12=720US
INT_DEL:ACALL DEL60US
DJNZ R7,INT_DEL
SETB DQ //數據線拉到高電平“1”
ACALL DEL60US //延時等待
ACALL DEL60US
MOV C,DQ //將數據線的狀態送給C,判斷初始化是否成功,是否產生一個低電平
JC ERROR //如果C等于1,則跳出,初始化失敗
ACALL DEL60US //初始化成功,CPU讀到數據線上的低電平,繼續延時
ACALL DEL60US
ACALL DEL60US
ACALL DEL60US
RET
ERROR: CLR DQ //初始化未成功,繼續進行初始化
SJMP B20_INT
RET
;;;;;;;;;;;;;;;;;讀DS18B20一個字節到累加器A子程序;;;;;;;;;;;;
R_BYTE: MOV R7,#08H //讀取8位為一字節
SETB DQ
NOP
NOP
LOOP: CLR DQ //將數據線從高電平拉為低電平時,作為一個讀周期的開始
NOP //延時,保證低電平至少為1US
NOP
NOP
SETB DQ
MOV R6,#07H //循環到A的最高位
DJNZ R6,[ DISCUZ_CODE_1 ]nbsp;
MOV C,DQ //將數據線中的值送給進位標志位C
ACALL DEL60US
RRC A //累加器A帶進位右移
SETB DQ
DJNZ R7,LOOP //將一字節讀到累加器A
ACALL DEL60US
ACALL DEL60US
RET
;;;;;;;;;;;;;累加器A寫到DS18B20子程序;;;;;;;;;;
W_BYTE: MOV R7,#08H //將8位連續數據(一字節)寫入A
SETB DQ //拉高數據線
NOP
NOP
LOOP1: CLR DQ //將數據線拉到低電平,作為寫周期的開始
MOV R6,#07H //循環到累加器A的最高位Acc.7
DJNZ R6,$
RRC A //從累加器A的最高位開始寫入
MOV DQ,C //將進位C送給DS18B20(寫入時序,0或者1時序)
ACALL DEL60US //保持60US
SETB DQ //在15US內將數據線拉為高電平
DJNZ R7,LOOP1 //將一字節寫入A
RET
DEL60US:MOV R6,#1EH //延時(30*2)us
DJNZ R6,$
RET
;;;;;;;;;;;讀溫度子程序;;;;;;;;;;;;;;;;;;
GET_TEM:ACALL B20_INT //DS18B20復位程序
MOV A,#0CCH //DS18B20跳過ROM命令
ACALL W_BYTE //調用寫DS18B20子程序
ACALL DEL60US
ACALL DEL60US
MOV A,#44H //DS18B20溫度轉換命令,開始裝換溫度
ACALL W_BYTE //調用寫DS18B20子程序
ACALL DEL60US
ACALL B20_INT //寫完之后,將DS18B20復位
MOV A,#0CCH //DS18B20跳過ROM命令
ACALL W_BYTE //調用寫DS18B20子程序
ACALL DEL60US
MOV A,#0BEH //DS18B20讀暫存器命令
ACALL W_BYTE //調用寫DS18B20子程序
ACALL DEL60US
ACALL R_BYTE //讀溫度低字節
MOV TEM_L,A //將讀出的溫度低字節保存在40H
ACALL R_BYTE //讀溫度高字節
MOV TEM_H,A // 將讀出的溫度高字節保存在41H
RET
;;;;;將從DS18B20中讀出的溫度轉換成整數顯示;;;;;;;;;;;;
TEM_COV:MOV FLAG0,#'+' //設置當前溫度為正,并且存放在45H
MOV A,TEM_H //將讀取的溫度高字節送給A
SUBB A,#0F8H //判斷C的值是否為1,為1則為正,為0則為負
JC TEM0 //看溫度值是否為負,不是(C=1),轉
MOV FLAG0,#'-' //是,置FLAG0為負
MOV A,TEM_L //將讀取的溫度低字節送給A
CPL A //求此時負值溫度的補碼
ADD A,#01H
MOV TEM_L,A //將求得的補碼存放在40H
MOV A,TEM_H //將讀取的溫度高字節送給A
CPL A
ADDC A,#01H
MOV TEM_H,A //在將其補碼放在41H
TEM0: MOV A,TEM_L //存放整數部分到TEMPER_NUM
ANL A,#0F0H //取出溫度低字節的高四位
SWAP A //將取出的高四位存放在A中低四位位置
MOV TEM_NUM,A //將其存放在42H
MOV A,TEM_H
SWAP A
ORL A,TEM_NUM
MOV TEM_NUM,A
RET
/***************LCD顯示*******************/
;;;;;;LCD初始化子程序;;;;;;;;;;;;
LCD_INT:MOV A,#00000001H //清屏
ACALL W_COM //調用讀命令子程序
MOV A,#00111000B //傳輸8位數據,顯示兩行,使用5*7的字符
LCALL W_COM
MOV A,#00001100B //顯示器開,光標關,字符不閃爍
LCALL W_COM
MOV A,#00000110B //字符不動,光標自動右移一格
LCALL W_COM
RET
;;;;;寫入命令子程序(RS=0,RW=0);;;;;;
W_COM: ACALL F_BUSY
CLR E
CLR RS
CLR RW
SETB E
MOV P0,A
CLR E
RET
;;;;;寫入數據子程序(RS=1,RW=0);;;;;
W_DAT: ACALL F_BUSY
CLR E
SETB RS
CLR RW
SETB E
MOV P0,A
CLR E
RET
;;;;;查忙子程序;;;;;;;;;;;;;
F_BUSY: PUSH ACC
MOV P0,#0FFH
CLR RS //忙標志
SETB RW
WAIT: CLR E //給使能端有效信號(下降沿觸發)
SETB E
JB P0.7,WAIT //直接尋址位P0.7是否為1,為1則忙,繼續等待
POP ACC
RET
END
|