仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
0.png (17.93 KB, 下載次數: 75)
下載附件
2019-1-26 23:11 上傳
0.png (10.37 KB, 下載次數: 65)
下載附件
2019-1-26 23:12 上傳
帶有全面中文注釋的單片機源程序如下:
- ;**********************************************************************
- ;晶振為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
-
復制代碼
所有資料51hei提供下載:
LCD1602時鐘溫度顯示+仿真.zip
(77.69 KB, 下載次數: 99)
2019-1-26 14:51 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|