;*********************************************************
;Термометр на контроллере PIC16F84 с двумя датчиками DS1821 
; В.А. Трошков 2001г.
;********************************************************* 

	__CONFIG _CP_OFF & _WDT_OFF & _XT_OSC

 ; 16F84                DS1821 (Корпус PR35)
 ; PORTB, Bit 4 --------DQ (Датчик №1)
 ; PORTB, Bit 0 --------DQ (Датчик №2)

       LIST p=16F84a
#include <p16f84a.inc>

; Если применяется PIC16C84, то следует указать
; #include <p16с84.inc>

        constant DATA_PIN=4     ; Определение портов для
        constant DATA_PIN2=0	; датчиков DS1821
;-------------------------------------------
        CBLOCK  0CH

        T_C             ; Результат для отображения датчика 1
	T_C2		; Результат для отображения датчика 2
        _N              ; Переменная для установки задержек
        O_BYTE          ; Байт для передачи датчику 1
        I_BYTE          ; Принятый байт от датчика 1
        O_BYTE2         ; Байт для передачи датчику 2
        I_BYTE2         ; Принятый байт от датчика 2
        LOOP3		; Переменные для подпрограмм задержек          
        LOOP2           ;
        LOOP1         	;  
        TEMP		;
	TEMP2 		;
	LCDINFO		; Байт информации для дисплея
	DISPDATA	; Байт для передачи дисплею
	LCDTIME		; Задержка в микросекундах
        LSD		; Младший разряд значения температуры 1
        MSD		; Старший разряд значения температуры 1
	LSD2		; Младший разряд значения температуры 2
	MSD2		; Старший разряд значения температуры 2
        SIGN1           ; Знак температуры датчика 1 
        SIGN2           ; Знак температуры датчика 2 

        ENDC
;-------------------------------------------
; Назначение портов и выводов ЖКИ дисплея АС161В
;-------------------------------------------
LCDDATA	equ	PORTA	; i/o RA0-RA3 = 4-bit шина данных
LCDCTRL	equ	PORTB	; Управляющий сигнал
DISP_E  equ     1       ; Разрешение чтения/записи
DISP_RW equ     2       ; Чтение/запись дисплея
DISP_RS equ     3       ; Выбор регистра дисплея
BF_FLAG	equ	1	; Флаг занятости дисплея
I_FLAG	equ	2	; Флаг команды (чтение/запись)

;********************************************
;	Макросы
;********************************************
PORTALO	macro
	bsf     STATUS,RP0      ; Установка страницы 1 памяти 
	movlw   b'11100000'     ; Установка режима порта А
	movwf   TRISA           ; 
	bcf     STATUS,RP0      ; Возврат на страницу 0
	endm
;-------------------------------------------
PORTAHI	macro
	bsf     STATUS,RP0      ; Установка страницы 1 памяти 
	movlw   b'11101111'     ; Установка режима порта А
	movwf   TRISA           ; 
	bcf     STATUS,RP0      ; Возврат на страницу 0
	endm
;-------------------------------------------
CLKDISP	macro
	bsf	LCDCTRL,DISP_E	; Установка вывода Е дисплея в 1
	bcf	LCDCTRL,DISP_E	; Установка вывода Е дисплея в 0
	endm
;-------------------------------------------
DISPCLR	macro
	movlw   b'00000001'     ; Очистка дисплея
	call    SENDI           ; Передача команды на дисплей
	endm
;-------------------------------------------
LINE1	macro
	movlw	b'10000000'	; Установка индикатора в 1-ю позицию
	call	SENDI		; 1-й строки
	endm			; 
;-------------------------------------------
LINE2	macro
	movlw	b'11000000'	; Установка индикатора в 1-ю позицию
	call	SENDI		; 2-й строки (или в позицию 9 
	endm			; однострочного индикатора)
;-------------------------------------------
LCDINIT	macro
	PORTALO			; Установка порта А на вывод
	movlw   0xF0            ; Задержка 15 мс для инициализации ЖКИ
	call    LCDWAIT		; 
	movlw   b'00000010'     ; Установка 4-битного интерфейса ЖКИ
	movwf	LCDCTRL		; Команда в порт А
	CLKDISP		        ; Тактовый импульс на дисплей
	movlw   d'5'            ; Задержка 5 мс
	call    LCDWAIT		; 
	movlw   b'00101000'     ; Установка 4-битного интерфейса и 2-строчного режима
	call    SENDI           ; 
	movlw   b'00101000'     ; Установка 4-битного интерфейса и 2-строчного режима
	call    SENDI           ; 
	movlw   b'00001000'     ; Дисплей выключить
	call    SENDI           ; 
	DISPCLR
	movlw   b'00001100'     ; Дисплей включить
	call    SENDI           ; 
	movlw   b'00000110'     ; Установить режим инкремента без сдвига
	call    SENDI           ; 

	movlw	40		; Программирование символа градуса
	call	SENDI		; по адресу 0h
	movlw	1C
	call	SENDD
	movlw	14
	call	SENDD
	movlw	1C
	call	SENDD
	clrw
	call	SENDD
	clrw
	call	SENDD
	clrw
	call	SENDD
	clrw
	call	SENDD
	clrw
	call	SENDD


				; Программирование символа "Д"
				; по адресу 01h
	movlw	B'00001111'
	call	SENDD
	movlw	B'00000101'
	call	SENDD
	movlw	B'00000101'
	call	SENDD
	movlw	B'00001001'
	call	SENDD
	movlw	B'00010001'
	call	SENDD
	movlw	B'00011111'
	call	SENDD
	movlw	B'00010001'
	call	SENDD
	movlw	B'00000000'
	call	SENDD

				; Программирование символа "У"
				; по адресу 02h
	movlw	B'00010001'
	call	SENDD
	movlw	B'00010001'
	call	SENDD
	movlw	B'00010001'
	call	SENDD
	movlw	B'00001010'
	call	SENDD
	movlw	B'00000100'
	call	SENDD
	movlw	B'00001000'
	call	SENDD
	movlw	B'00010000'
	call	SENDD
	movlw	B'00000000'
	call	SENDD

				; Программирование символа "л"
				; по адресу 03h
	movlw	B'00000000'
	call	SENDD
	movlw	B'00000000'
	call	SENDD
	movlw	B'00001111'
	call	SENDD
	movlw	B'00000101'
	call	SENDD
	movlw	B'00000101'
	call	SENDD
	movlw	B'00010101'
	call	SENDD
	movlw	B'00001001'
	call	SENDD
	movlw	B'00000000'
	call	SENDD

				; Программирование символа "м"
				; по адресу 04h
	movlw	B'00000000'
	call	SENDD
	movlw	B'00000000'
	call	SENDD
	movlw	B'00010001'
	call	SENDD
	movlw	B'00011011'
	call	SENDD
	movlw	B'00010101'
	call	SENDD
	movlw	B'00010001'
	call	SENDD
	movlw	B'00010001'
	call	SENDD
	movlw	B'00000000'
	call	SENDD

	movlw	80		; Очистка
	call	SENDI

	endm

;******************************************************
; Основная программа
;******************************************************
        ORG 000H
        goto MAIN
        org     4
        goto    int
MAIN:
        clrf	PORTA		; Обнулить порт А
	clrf	PORTB		; Обнулить порт В
	bsf	STATUS,RP0	; Страница 1 памяти
	bcf	OPTION_REG,NOT_RBPU ;Включить подтягивающие резисторы
	movlw	b'11100000'	; Установить порт А на вывод
	movwf	TRISA		; 
	movlw	b'11000001'	; Установить управляющие биты для дисплея
	movwf	TRISB
	bcf	STATUS,RP0	; Возврат на страницу 2 памяти
        LCDINIT			; Инициализация дисплея
        CALL 	CONFIG_DEVICE   ; Инициализация датчика №1
        CALL 	CONFIG_DEVICE2  ; Инициализация датчика №2
MAIN_1:
        CALL 	START_CONVERT   ; Старт преобразования датчика №1
        CALL 	READ_TEMP       ; Чтение датчика №1
        MOVWF 	T_C             ; Результат чтения в регистре Т_С
        CALL 	STOP_CONVERT    ; Остановка преобразования датчика №1
	btfsc	T_C,7		; Проверка знака температуры
	goto	minus		; Если бит 7=1, то знак "-"
plus	movlw	'+'		; Иначе знак "+"
	movwf	SIGN1		; Изображение "+" для отображения
disp    CALL 	DISPLAY         ; Результат измерения на дисплей
        movlw   4               ; Пауза 1 секунда
        MOVWF 	LOOP3
MAIN_2:
        CALL 	DELAY_LONG
        DECFSZ 	LOOP3, F
        GOTO 	MAIN_2
;-----------------------------------------------
; Все то же самое для второго датчика
;-----------------------------------------------
MAIN_3:
        CALL 	START_CONVERT2
        CALL 	READ_TEMP2
        MOVWF 	T_C2
        CALL 	STOP_CONVERT2
	btfsc	T_C2,7
	goto	minus2
plus2	movlw	'+'
	movwf	SIGN2
disp2	CALL 	DISPLAY2
	movlw   4
        MOVWF 	LOOP3
MAIN_4:
        CALL 	DELAY_LONG
        DECFSZ 	LOOP3, F
        GOTO 	MAIN_4
        GOTO 	MAIN_1		; Возврат к 1-му датчику
;-----------------------------------------
minus	movlw	'-'		; Изображение "-"
	movwf	SIGN1		; для отображения
	movf	T_C,w		; Преобразование отрицательного
	sublw	0FF		; числа в НЕХ-коде
	addlw	1		; в модуль числа 
	movwf	T_C		; десятичного представления
	goto	disp

minus2	movlw	'-'		; То же для 2-го датчика
	movwf	SIGN2
	movf	T_C2,w
	sublw	0FF
	addlw	1
	movwf	T_C2
	goto	disp2
;----------------------------------------
CONFIG_DEVICE:
        CALL 	INIT
        MOVLW 	0CH
        MOVWF 	O_BYTE
        CALL 	OUT_BYTE
        MOVLW 	03H             ; Однократный режим, активный уровень 1
        MOVWF 	O_BYTE
        CALL 	OUT_BYTE
        MOVLW 	.20             ; Задержка 20 мс для программирования датчика
        MOVWF 	LOOP1
        CALL 	DELAY_N_MS
        RETURN

CONFIG_DEVICE2:			; То же для датчика №1
        CALL 	INIT2
        MOVLW 	0CH
        MOVWF 	O_BYTE2
        CALL 	OUT_BYTE2
        MOVLW 	03H 
        MOVWF 	O_BYTE2
        CALL 	OUT_BYTE2
        MOVLW 	.20 
        MOVWF 	LOOP1
        CALL 	DELAY_N_MS
        RETURN
;---------------------------------------

START_CONVERT:
        CALL 	INIT
        MOVLW 	0EEH
        MOVWF 	O_BYTE
        CALL 	OUT_BYTE
        MOVLW 	.100            ; Задержка 100 мс
        MOVWF 	LOOP1
        CALL 	DELAY_N_MS
        RETURN

START_CONVERT2:
        CALL 	INIT2
        MOVLW 	0EEH
        MOVWF 	O_BYTE2
        CALL 	OUT_BYTE2
        MOVLW 	.100
        MOVWF 	LOOP1
        CALL 	DELAY_N_MS
        RETURN
;---------------------------------------
READ_TEMP:
        CALL 	INIT
        MOVLW 	0AAH
        MOVWF 	O_BYTE
        CALL 	OUT_BYTE
        CALL 	IN_BYTE
        MOVF 	I_BYTE, W
        RETURN

READ_TEMP2:
        CALL 	INIT2
        MOVLW 	0AAH
        MOVWF 	O_BYTE2
        CALL 	OUT_BYTE2
        CALL 	IN_BYTE2
        MOVF 	I_BYTE2, W
        RETURN
;---------------------------------------
STOP_CONVERT:
        CALL 	INIT
        MOVLW 	22H
        MOVWF 	O_BYTE
        CALL 	OUT_BYTE
        RETURN

STOP_CONVERT2:
        CALL 	INIT2
        MOVLW 	22H
        MOVWF 	O_BYTE2
        CALL 	OUT_BYTE2
        RETURN
;---------------------------------------
DISPLAY:
	LINE1
	movlw	02h		; "У"
	call	SENDD
	movlw	03h		; "л"
	call	SENDD
	movlw	'.'		; "."
	call	SENDD
	movf	SIGN1,w		; Изображение "+" или "-"
	call	SENDD
	movf	T_C,w
	call 	BINBCD		; Преобразование к десятичному виду
	movf	MSD,W		; Изображение десятка градусов
	addlw	30
	call	SENDD
	movf	LSD,W		; Изображение единиц градусов
	addlw	30
	call	SENDD
	movlw	0		; Изображение символа градусов
	call	SENDD
	movlw	' '		; Пробел
	call	SENDD
	return

DISPLAY2
	LINE2
	movlw	01h		; "Д"
	call	SENDD
	movlw	'o'		; "о"
	call	SENDD
	movlw	04h		; "м"
	call	SENDD
	movlw	' '		; Пробел
	call	SENDD
	movf	SIGN2,w
	call	SENDD
	movf	T_C2,w
	call	BINBCD2
	movf	MSD2,W
	addlw	30
	call	SENDD
	movf	LSD2,W
	addlw	30
	call	SENDD
	movlw	0		; Изображение символа градусов
	call	SENDD	
        return
;-------------------------------------------
; Стандартные процедуры для интерфейса 1-Wire
;-------------------------------------------
INIT:
        CALL    PIN_HI
        CALL    PIN_LO
        MOVLW   .50              ; Задержка 500 мкс
        CALL 	DELAY_10USEC
        CALL    PIN_HI
        MOVLW   .50              ; Задержка 500 мкс
        CALL 	DELAY_10USEC
        RETURN

INIT2:
        CALL    PIN_HI2
        CALL    PIN_LO2
        MOVLW   .50              ; Задержка 500 мкс
        CALL 	DELAY_10USEC
        CALL    PIN_HI2
        MOVLW   .50              ; Задержка 500 мкс
        CALL 	DELAY_10USEC
        RETURN
;-------------------------------------------
WAIT:
        CALL    IN_BYTE
        MOVLW   0FFH
        SUBWF   I_BYTE, W
        BTFSS   STATUS, Z
        GOTO    WAIT
        RETURN

WAIT2:
        CALL    IN_BYTE2
        MOVLW   0FFH
        SUBWF   I_BYTE2, W
        BTFSS   STATUS, Z
        GOTO    WAIT2
        RETURN
;-------------------------------------------
IN_BYTE:              		; Прием байта в W 
        MOVLW   .8
        MOVWF    _N
        CLRF    I_BYTE
IN_BYTE_1:
        CALL 	PIN_LO
        NOP
        CALL 	PIN_HI
        NOP
        NOP
        NOP
        NOP
        NOP
        NOP
        MOVF    PORTB, W        ; 7 usecs later, fetch from DATA_PIN
        MOVWF   TEMP
        BTFSS   TEMP, DATA_PIN
        BCF 	STATUS, C       ; its a zero
        BTFSC   TEMP, DATA_PIN
        BSF 	STATUS, C       ; its a one
        RRF     I_BYTE, F
        MOVLW 	.6              ; now delay 60 usecs
        CALL    DELAY_10USEC
        DECFSZ  _N, F
        GOTO    IN_BYTE_1
        MOVFW   I_BYTE          ; return the result in W
        RETURN

IN_BYTE2:              		; returns byte in W
        MOVLW   .8
        MOVWF    _N
        CLRF    I_BYTE2
IN_BYTE_12:
        CALL 	PIN_LO2         ; momentary low on DATA_PIN
        NOP
        CALL 	PIN_HI2
        NOP
        NOP
        NOP
        NOP
        NOP
        NOP
        MOVF    PORTB, W        ; 7 usecs later, fetch from DATA_PIN
        MOVWF   TEMP2
        BTFSS   TEMP2, DATA_PIN2
        BCF 	STATUS, C       ; its a zero
        BTFSC   TEMP2, DATA_PIN2
        BSF 	STATUS, C       ; its a one
        RRF     I_BYTE2, F
        MOVLW 	.6              ; now delay 60 usecs
        CALL    DELAY_10USEC
        DECFSZ  _N, F
        GOTO    IN_BYTE_12
        MOVFW   I_BYTE2          ; return the result in W
        RETURN
;------------------------------------------
OUT_BYTE:
        MOVLW   .8
        MOVWF   _N
OUT_BYTE_1:
        RRF     O_BYTE, F
        BTFSS   STATUS, C
        GOTO    OUT_0
        GOTO    OUT_1
OUT_BYTE_2:
        DECFSZ  _N, F
        GOTO    OUT_BYTE_1
        RETURN

OUT_BYTE2:
        MOVLW   .8
        MOVWF   _N
OUT_BYTE_12:
        RRF     O_BYTE2, F
        BTFSS   STATUS, C
        GOTO    OUT_02
        GOTO    OUT_12
OUT_BYTE_22:
        DECFSZ  _N, F
        GOTO    OUT_BYTE_12
        RETURN
;-------------------------------------------
OUT_0:
        CALL    PIN_LO          ; bring DATA_PIN low
        MOVLW   .6              ; for 60 usecs
        CALL    DELAY_10USEC
        CALL    PIN_HI
        GOTO    OUT_BYTE_2
OUT_1:
        CALL    PIN_LO          ; momentary low
        CALL    PIN_HI
        MOVLW 	.6
        CALL 	DELAY_10USEC
        GOTO    OUT_BYTE_2

;-----------------------------------------

PIN_HI:
        BSF     STATUS, RP0
        BSF     TRISB, DATA_PIN ; high impedance
        BCF     STATUS, RP0
        RETURN
OUT_02:
        CALL    PIN_LO2          ; bring DATA_PIN low
        MOVLW   .6               ; for 60 usecs
        CALL    DELAY_10USEC
        CALL    PIN_HI2
        GOTO    OUT_BYTE_22
OUT_12:
        CALL    PIN_LO2          ; momentary low
        CALL    PIN_HI2
        MOVLW 	.6
        CALL 	DELAY_10USEC
        GOTO    OUT_BYTE_22

;---------------------------------------

PIN_HI2:
        BSF     STATUS, RP0
        BSF     TRISB, DATA_PIN2  ; high impedance
        BCF     STATUS, RP0
        RETURN
;---------------------------------------
PIN_LO:
        BCF     PORTB, DATA_PIN
        BSF     STATUS, RP0
        BCF     TRISB, DATA_PIN    ; low impedance zero
        BCF     STATUS, RP0
        RETURN
PIN_LO2:
        BCF     PORTB, DATA_PIN2
        BSF     STATUS, RP0
        BCF     TRISB, DATA_PIN2    ; low impedance zero
        BCF     STATUS, RP0
        RETURN
;---------------------------------------
DELAY_LONG
        MOVLW 	.250      ; Задержка 250 мс
        MOVWF 	LOOP1
DELAY_N_MS:
OUTTER:
        MOVLW   .110      ; Задержка 1 мс
        MOVWF   LOOP2
INNER:
        NOP
        NOP
        NOP
        NOP
        NOP
        NOP
        DECFSZ  LOOP2, F
        GOTO 	INNER
        DECFSZ  LOOP1, F
        GOTO 	OUTTER
        RETURN
;---------------------------------------
DELAY_10USEC:   	;Задержка определяется как W * 10 мкс
        MOVWF 	LOOP1
DELAY_10USEC_1:
        NOP
        NOP
        NOP
        NOP
        NOP
        NOP
        NOP
        DECFSZ 	LOOP1, F
        GOTO 	DELAY_10USEC_1
        RETURN
;********************************************
; Стандартные процедуры работы с дисплеем
;********************************************
SENDI:
	bsf	LCDINFO,I_FLAG	; Next data is an instruction
SENDD:
	movwf   DISPDATA        ; Store send-data for later use
	PORTAHI			; Put PortA tristate
	bcf	LCDCTRL,DISP_RS	; RS=0 => Instruction
	bsf	LCDCTRL,DISP_RW	; RW=1 => Read
DISPBUSY:
	bsf	LCDCTRL,DISP_E	; Display puts data on LCDDATA
	bcf     LCDINFO,BF_FLAG	; Busy flag is probably = 0
	btfsc   PORTA,3         ; Read busy flag from display
	bsf     LCDINFO,BF_FLAG	; Busy flag was = 1
	bcf	LCDCTRL,DISP_E	; Lower display enable port
	CLKDISP			; Clock out the last and uninteresting nibble
	btfsc   LCDINFO,BF_FLAG ; Check if display is ready
	goto    DISPBUSY        ; The display is not ready
	PORTALO			; Put portA in a low impedance state
	bsf	LCDCTRL,DISP_RS	; RS=1 => Data
	bcf	LCDCTRL,DISP_RW	; RW=0 => Write
	btfsc   LCDINFO,I_FLAG	; Check if SENDData?
	bcf	LCDCTRL,DISP_RS	; No, RS=0 => Instruction
	swapf   DISPDATA,W      ; Put first nibble to send in W-low
	movwf   LCDDATA		; Put first nibble to portA
	CLKDISP			; Clock out the first nibble to display
	movf    DISPDATA,W      ; Put last nibble to send in W
	movwf	LCDDATA		; Put last nibble on portA
	CLKDISP			; Clock out the last nibble to display
	bcf     LCDINFO,I_FLAG	; Assume next send is SENDD
	return
;----------------------------------------
LCDWAIT:
	clrf	LCDTIME		; Clear time downcounter
LCDWAITLOOP:
	nop			; Extend timerloop to 256
	decfsz	LCDTIME,F	; Decrement timer
	goto	LCDWAITLOOP	; and loop if not down to zero again
	movwf	LCDTIME		; W contains outer loop value
	decfsz	LCDTIME,W	; Decrement
	goto	LCDWAIT
	return
;-------------------------------------
BINBCD:	
	CLRF 	MSD
	MOVF	T_C,w
	MOVWF	LSD
GTENTH:
	movlw	d'10'
	subwf	LSD,W
	btfss	STATUS,C
	goto	OVER
	movwf	LSD
	incf	MSD,F
	goto	GTENTH
OVER:	retlw	0

BINBCD2:	
	CLRF 	MSD2
	MOVF	T_C2,w
	MOVWF	LSD2
GTENTH2:
	movlw	d'10'
	subwf	LSD2,W
	btfss	STATUS,C
	goto	OVER2
	movwf	LSD2
	incf	MSD2,F
	goto	GTENTH2
OVER2:	retlw	0
;------------------------------------
int:    retfie
;*************************************************
        END


