;以下程式之讀取寫入時序是針對笙泉82G516,工作於12MHz設計,如要在其他單晶片工作,請自行調整時序, 否則可能無法正常工作 ;將讀取到的溫度顯示在七段顯示器上 DQ EQU P3.3 ;DS18B20資料線 TEMP_H EQU 2AH ;讀到的溫度,高位元組 TEMP_L EQU 2BH ;讀到的溫度,低位元組 LED_CNT EQU 32H ;控制LED顯示位置暫存器 LED_BUF EQU 33H ;LED顯示資料暫存器, 共需4個byet LED EQU P2 ORG 00H JMP MAIN ORG 0BH JMP SCAN_LED MAIN: MOV A,#0 MOV LED_BUF,A MOV LED_BUF+1,A MOV LED_BUF+2,A MOV LED_BUF+3,A MOV TMOD,#00000001B MOV TH0,#(65536-2000) /256 MOV TL0,#(65536-2000) MOD 256 MOV IE,#10000010B SETB TR0 MOV R4,#0 MOV LED_CNT,#LED_BUF READ_T: CALL INIT_18B20 MOV A,#0CCH CALL WR_BYTE MOV A,#044H CALL WR_BYTE MOV R5,#80 ;等溫度轉換完畢,要750 ms CALL DELAY CALL INIT_18B20 MOV A,#0CCH CALL WR_BYTE MOV A,#0BEH CALL WR_BYTE CALL RD_BYTE MOV TEMP_L,A ;將讀到的溫度, 存到TMP_L CALL RD_BYTE MOV TEMP_H,A ;將讀到的溫度, 存到TMP_H MOV LED_BUF,#00000000B ;先將七段顯示器最高位先清除 JNB TEMP_H.7,PLUS ;如果最高位元為0,代表溫度為正 MOV A,TEMP_L CPL A ;如果溫度為負, ADD A,#1 ;取補數再加1 MOV TEMP_L,A MOV A,TEMP_H CPL A ADDC A,#0 MOV TEMP_H,A MOV LED_BUF,#01000000B ;最高位顯示負號 PLUS: MOV DPTR,#FONT MOV A,TEMP_L ANL A,#0F0H MOV B,A MOV A,TEMP_H ;將高位元組的後4位元與低位元組的前4位元 ANL A,#0FH ;組合成溫度的整數值 ORL A,B SWAP A MOV B,#10 DIV AB MOVC A,@A+DPTR MOV LED_BUF+1,A MOV A,B MOVC A,@A+DPTR ORL A,#10000000B ;此位數要加上小數點 MOV LED_BUF+2,A MOV A,TEMP_L ;小數點以下佔4位元,每格代表0.0625度 ANL A,#0FH ;直接用查表比較快 MOV DPTR,#DIGIT ;數值0~15對應到0.0~0.9度 MOVC A,@A+DPTR MOV DPTR,#FONT ;再將此數值改成七段顯示器字型 MOVC A,@A+DPTR MOV LED_BUF+3,A ; MOV R5,#250 ;測試用,休息一下再讀下一次溫度 ; CALL DELAY ;好像連續轉換讀到的溫度會高一些? JMP READ_T ;7段顯示器掃描程式, 依序將LED_BUF內儲存之內容送至7段顯示器顯示 SCAN_LED: PUSH ACC MOV TH0,#(65536-2000) /256 MOV TL0,#(65536-2000) MOD 256 MOV A,R4 ADD A,#0F8H ;在實驗版中, P1.7~P1.4另有其他用途, 先設為1, 避免干擾 MOV P1,A MOV R0,LED_CNT MOV A,@R0 MOV LED,A ;顯示於LED INC LED_CNT INC R4 CJNE R4,#4,NOT_END MOV R4,#0 ;掃完4次,重設初值 MOV LED_CNT,#LED_BUF NOT_END: POP ACC RETI DIGIT: DB 0,1,1,2,3,3,4,4,5,6,6,7,8,8,9,9 ;數值0~15對應到0.0~0.9度 FONT: DB 3fh,06h,5bh,4fh,66h,6dh,7dh,07h,7fh,6fh ;0~9之7段顯示器字型 WR_BYTE: ;寫入一位元組訊號 CLR TR0 ;避免計時器中斷影響寫入時序, 先關掉計時器 MOV R6,#8 WR_1BIT: RRC A CLR DQ MOV R7,#45 ;持續至多15 us,起始訊號 DJNZ R7,$ MOV DQ,C ;將要寫入DS18B20的資料送出 MOV R7,#60 ;持續20 us,等待ds18b20讀取 DJNZ R7,$ SETB DQ MOV R7,#100 ;持續35 us,等待ds18b20回復 DJNZ R7,$ DJNZ R6,WR_1BIT SETB TR0 ;重新啟動計時器 RET RD_BYTE: ;讀取一位元組訊號 CLR TR0 ;避免計時器中斷影響寫入時序, 先關掉計時器 MOV R6,#8 RD_1BIT: CLR DQ MOV R7,#2 ;起始訊號, 持續 2 us DJNZ R7,$ SETB DQ MOV R7,#30 ;等待 10 us後再讀訊號訊號 DJNZ R7,$ MOV C,DQ ;從DQ接腳讀回DS18B20送出之訊號 RRC A MOV R7,#150 ;持續50 us,等待ds18b20回復 DJNZ R7,$ DJNZ R6,RD_1BIT SETB TR0 ;重新啟動計時器 RET INIT_18B20: ;喚醒DS18B20 CLR DQ MOV R5,#50 ;持續 500 us,起始訊號 CALL DELAY10 SETB DQ MOV R5,#8 ;持續 80 us,等待DS18B20回應 CALL DELAY10 ; JNB DQ,OK_18B20 ; MOV P2,#55H ;DS18B20不存在時,P2顯示01010101 ; JMP $ ;此段程式暫時不用 ;OK_18B20: MOV R5,#42 CALL DELAY10 RET DELAY: ;延遲時間 = R5 * 10 ms MOV R6,#200 DEL: MOV R7,#150 DJNZ R7,$ DJNZ R6,DEL DJNZ R5,DELAY RET DELAY10: ;延遲時間 = R5 * 10 us MOV R7,#30 DJNZ R7,$ DJNZ R5,DELAY10 RET END