; Lecteur DALLAS avec liaison RS232 9600 bauds
; 14 janvier 2001


	list P=16F876
	include <C:\progra~1\MPLAB2\P16F876.INC>

; configuration du processeur

	__CONFIG _CP_OFF&_DEBUG_OFF&_WRT_ENABLE_ON&_CPD_OFF&_LVP_OFF&_BODEN_ON&_PWRTE_ON&_WDT_ON&_HS_OSC

;____________________________________________________________________________________________________________________
; variables
;____________________________________________________________________________________________________________________

serie		equ 20
part1		equ 21
part2		equ 22
part3		equ 23
part4		equ 24
part5		equ 25
part6		equ 26
dallasCRC	equ 27
tmp		equ 28
compteur	equ 29
valeur		equ 2A
temp		equ 2B
rotation	equ 2C
nboctet		equ 2D
crc		equ 2F
adresse		equ 30
dataee		equ 31
saveW		equ 32
savesta		equ 33
saveFSR		equ 34
flag		equ 35
caractere	equ 36
adresseH	equ 37
adresseL	equ 38	
dataF		equ 39
nbkey		equ 3A
temp1		equ 3B
temp2		equ 3C
timer		equ 3D		; timer pour tempo 1 seconde
seconde		equ 3E		; compteur de secondes
key		equ 3F		; indice de la clef trouvée
decompte	equ 40		; decompte pour tempo relais
adlow		equ 41		; poids faible adresse R/W pour protocole
adhigh		equ 42		; poids fort   adresse R/W pour protocole

;____________________________________________________________________________________________________________________
; constantes
;____________________________________________________________________________________________________________________

skiprom		equ 0CC		; commande DALLAS 
readscratch	equ 0BE		;     "           "
convert		equ 44		;     "           "
readrom		equ 33		;     "           "
readram		equ 0F0		;     "           "
Ladress		equ 0
Hadress		equ 0
ahigh		equ 08
alow		equ 00
nbclef		equ 05		; nb maximum de clef
ACK		equ 06		; acknowledge liaison serie

;____________________________________________________________________________________________________________________
; etiquettes bits
;____________________________________________________________________________________________________________________

#define _data		PORTA,0
#define _rouge		PORTB,7
#define _verte		PORTB,6
#define _relais		PORTB,5
masque		equ b'10000000'		; masque de la led qui clignote
					; la led qui clignote doit être sur le PORTB
#define zero		STATUS,Z
#define _receivedcar	flag,0
#define idem		flag,1
#define _clignote	flag,2

;____________________________________________________________________________________________________________________
; macro commandes
;____________________________________________________________________________________________________________________

bank0	macro
	bcf STATUS,RP0
	bcf STATUS,RP1
	endm

bank1 	macro	
	bsf STATUS,RP0
	endm

bank2	macro
	bcf STATUS,RP0
	bsf STATUS,RP1
	endm

bank3	macro
	bsf STATUS,RP0
	bsf STATUS,RP1
	endm

;____________________________________________________________________________________________________________________
; entête programme
;____________________________________________________________________________________________________________________

	org 2100			; initialisation de l'EEPROM
	de 00,05

	org 0
	goto debut
	org 4
	goto interrupt

;____________________________________________________________________________________________________________________
; programme
;____________________________________________________________________________________________________________________

debut:
	clrwdt
	clrf flag
	movlw 5
	movwf timer
	call initwdt			; initialisation du watchdog
	call initportA			; initialisation PORT A
	call initportB
	call initportC			; initialisation PORT C
	call initV24			; initialisation RS232
	call inittmr1			; initialisation timer 1
	call initint			; initialisation des interruptions
	movlw 0
	movwf adresse
	clrwdt
	call readEE			; va lire l'adresse 0 de l'EEPROM
	xorlw 0
	btfsc zero
	goto firstaccess
	bsf _rouge

main:
	clrwdt
	call litcode
	btfsc STATUS,C
	goto access
	btfss _receivedcar
	goto main
	bcf _receivedcar
	movf caractere,w
	xorlw 'M'			; set mem ?
	btfsc zero
	goto setmem
	xorlw 'M'
	xorlw 'R'			; read mem ?
	btfsc zero
	goto readmem
	xorlw 'R'
	xorlw 'W'			; write mem
	btfsc zero
	goto writemem
	goto main

setmem:
	movlw d'255'
	movwf seconde
sm1:
	clrwdt
	movf seconde,w			; time out liaison serie une seconde
	btfsc zero
	goto main
	btfss _receivedcar		; attent adresse basse
	goto sm1
	bcf _receivedcar
	movf caractere,w	
	movwf adlow			; dans le registre
	movlw d'255'
	movwf seconde
sm2:
	clrwdt
	movf seconde,w			; time out liaison serie
	btfsc zero
	goto main
	btfss _receivedcar		; attend adresse haute
	goto sm2
	bcf _receivedcar
	movf caractere,w
	movwf adhigh			; dans le registre
	movlw ACK
	call transmit			; puis transmettre un ACK
	goto main

readmem:
	movlw d'255'
	movwf seconde
rm1:
	clrwdt
	movf seconde,w
	btfsc zero
	goto main
	btfss _receivedcar
	goto rm1
	bcf _receivedcar
	movf caractere,w
	xorlw 'E'
	btfsc zero
	goto rEEPROM
	xorlw 'E'
	xorlw 'F'
	btfsc zero
	goto rflash
	xorlw'F'
	xorlw 'R'
	btfss zero
	goto main
rram:					; lecture dans la ram
	movlw 8
	movwf compteur
	movlw serie
	movwf FSR
rr1:
	movf INDF,w
	call transmit
	incf FSR,f
	decfsz compteur,f
	goto rr1
	movlw ACK
	call transmit
	goto main

rflash:					; lecture dans la flash
	clrwdt
	movf adlow,w
	movwf adresseL
	movf adhigh,w
	movwf adresseH
	call readF
	call transmit			; envoi de l'octet
	movlw ACK
	call transmit
	movf adlow,w
	addlw 1
	btfsc zero
	incf adhigh,f
	movf adlow,w
	goto main
rEEPROM:
	clrwdt
	movf adlow,w
	movwf adresse
	call readEE			; va lire l'EEPROM
	call transmit
	movlw ACK
	call transmit
	incf adlow,f
	goto main

writemem:
	movlw d'255'
	movwf seconde
wm1:
	clrwdt
	movf seconde,w
	btfsc zero
	goto main
	btfss _receivedcar
	goto wm1
	bcf _receivedcar
	movf caractere,w
	xorlw 'E'
	btfsc zero
	goto wEEPROM
	xorlw 'E'
	xorlw 'F'
	btfsc zero
	goto wFLASH
	xorlw 'F'
	xorlw 'R'
	btfss zero
	goto main
wRAM:					; RAZ des 8 octets du code DALLAS en RAM
	clrwdt
	movlw 8
	movwf compteur
	movlw serie
	movwf FSR
wr1:
	movlw 0
	movwf INDF
	incf FSR,f
	decfsz compteur,f
	goto wr1
	movlw ACK
	call transmit
	goto main
wFLASH:					; ecriture dans la FLASH
	clrwdt
	movf adlow,w
	movwf adresseL
	movf adhigh,w
	movwf adresseH
	movlw d'255'
	movwf seconde
wf1:
	clrwdt
	movf seconde,w
	btfsc zero
	btfss _receivedcar
	goto wf1
	bcf _receivedcar
	movf caractere,w
	movwf dataF
	call writeF
	movlw ACK
	call transmit		
	movf adlow,w
	addlw 1
	btfsc zero
	incf adhigh,f
	movf adlow,w
	goto main
wEEPROM:				; ecriture dans l'EEPROM
	movf adlow,w
	movwf adresse
	movlw d'255'
	movwf seconde
we1:
	clrwdt
	movf seconde,w
	btfsc zero
	goto main
	btfss _receivedcar
	goto we1
	bcf _receivedcar
	movf caractere,w
	movwf dataee
	call writeEE
	movlw ACK
	call transmit
	incf adlow,f
	goto main


firstaccess:				; aucune clef dans la flash
	bsf _clignote
fa1:
	clrwdt
	call litcode
	btfss STATUS,C
	goto fa1
	bcf _clignote
	bcf _rouge
	call entercode	
	bsf _verte
	call setrelais
	bcf _verte
	bsf _rouge
	goto main

newaccess:				; adjonction d'une clef
	movlw 0				; verifier 
	movwf adresse			; si
	call readEE			; le nombre maxi de clef 
	addlw 1				; n'est pas atteint
	sublw nbclef 
	btfss STATUS,C
	goto endna
	bcf _verte
	bcf _rouge
	bsf _clignote
	clrf seconde
na0:
	clrwdt
	movf seconde,w
	xorlw 5
	btfss zero
	goto na0
	clrf seconde
na1:
	clrwdt
	movf seconde,w
	xorlw 0A			; time out = 10 secondes	
	btfsc zero
	goto endna
	call litcode
	btfss STATUS,C
	goto na1
	call entercode	
	bcf _clignote
	bcf _rouge
	bsf _verte
	call setrelais
endna:
	bcf _clignote
	bcf _verte
	bsf _rouge
	goto main

access:					; une clef a été présentée
	clrwdt
	call findkey
	btfss STATUS,C
	goto main			; la clef n'est pas valide
	bcf _rouge
	bsf _verte
	call setrelais
	bcf _verte
	bsf _rouge
	movf key,w
	btfss zero			; si la precedente clef est la 0
	goto main
	clrwdt
	call litcode			; alors aller voir si elle est tjrs la
	btfss STATUS,C
	goto main			; la clef présente n'est plus la
	bcf _rouge			; sinon passer en mode programmation
	bsf _clignote
	goto newaccess			; adjonction d'une clef

	
setrelais:
	movlw 1
	movwf adresse
	clrwdt
	call readEE			; lire l'adresse 1 de l'eeprom
	xorlw 0
	btfsc zero
	goto bistable			; si adresse(1)=0 alors bistable
	movwf decompte			; sinon adresse(1)=tempo relais
	clrf seconde
	bsf _relais			; enclencher le relais
sr1:
	clrwdt
	movf seconde,w			; et attendre
	xorwf decompte,w
	btfss zero			; la tempo
	goto sr1
	bcf _relais			; declencher le relais
	return
bistable:
	movf PORTB,w			; complementer
	xorlw b'00100000'		; B5 ( sortie relais )
	movwf PORTB			
	clrf seconde			; et atendre
bs1:	
	clrwdt
	movf seconde,w
	xorlw 5				; 5 secondes
	btfss zero
	goto bs1
	return	


;-----------------------------------------------------------------------------------
; ecriture de la clef dans la flash et MAJ index ( adresse 0 de l'EEPROM )
;-----------------------------------------------------------------------------------

entercode:
	movlw 0
	movwf adresse
	call readEE
	movwf nbkey
	movlw nbclef			; nombre maxi de clef
	xorwf nbkey,w			; à comparer au nombre de clef
	btfsc zero			
	return				; si egal alors retour
	movlw alow
	movwf adresseL
	movlw ahigh
	movwf adresseH
	movf nbkey,w
	btfsc zero
	goto ec10
ec1:
	clrwdt
	decf nbkey,f
	movf adresseL,w
	addlw 8
	btfsc STATUS,C
	incf adresseH,f
	movwf adresseL
	movf nbkey,w
	btfsc STATUS,Z	
	goto ec10
	goto ec1
ec10:
	movlw serie
	movwf FSR
	movlw 8
	movwf temp1		; compteur ( nombre d'octets )
ec2:				; ecriture de la clef
	clrwdt
	movf INDF,w
	movwf dataF
	call writeF
	incf adresseL,f
	btfsc STATUS,Z
	incf adresseH,f
	incf FSR,f
	decfsz temp1,f
	goto ec2
	movlw 0			; mise à jour du flag nbkey
	movwf adresse
	call readEE
	movwf dataee
	incf dataee,f
	call writeEE
	return
	
;-----------------------------------------------------------------------------------
; recherche de la clef dans la flash
;-----------------------------------------------------------------------------------

findkey:
	clrf key		; clef maitre indice 0
	movlw 00		; à l'adresse 0 de l'EEPROM
	movwf adresse
	call readEE
	movwf nbkey		; nombre de clef
	movlw ahigh		; poids fort adresse 1ere clef
	movwf adresseH
	movlw alow		; poids faible adresse 1ere clef
	movwf adresseL
	addlw 7			; positionner sur l'octet de CRC
	movwf adresseL
fk1:
	clrwdt
	call readF		; lire l'octet de crc
	xorwf dallasCRC,w	; comparer au crc de l'octet courant
	btfsc STATUS,Z
	goto fkcrc		; le CRC est le meme
fk10:
	incf key,f		; numero de la clef maitre
	decfsz nbkey,f		; sinon clef suivante dans la flash
	goto fk2		
	bcf STATUS,C		; derniere clef
	return			; retour
fk2:
	movlw 8
	addwf adresseL,f	; ajouter 8 a l'adresse courante
	btfsc STATUS,C
	incf adresseH,f		; si roll over increment adresse haute
	goto fk1
fkcrc:				; le crc est le même
				; verif des octets suivants
	movlw 7			; tester les 7 autres codes
	movwf rotation		
	movf adresseL,w		; sauvegarde adresse courante
	movwf temp1
	movf adresseH,w
	movwf temp2
	movlw part6		; 1er octet du code
	movwf FSR		; dans registre d'indirection
	bsf idem
fkcrc1:
	clrwdt
	incf adresseL,f
	decf adresseL,f
	btfsc STATUS,Z		; adresse basse courante=0 ?
	decf adresseH,f		; oui alors decrementer le poids fort de l'adresse suivante
	decf adresseL,f		; et decrementer le poids faible
	call readF		; lecture de la flash
	movwf dataF
	movf INDF,w
	xorwf dataF,w
	btfss STATUS,Z
	bcf idem
	decf FSR,f		; octet suivant du code
	decfsz rotation,f
	goto fkcrc1
	bsf STATUS,C		; flag clef trouvée
	btfsc idem		; si idem est mis 
	return			; alors retour
	movf temp1,w
	movwf adresseL
	movf temp2,w
	movwf adresseH
	goto fk10
	
	
	
	

		

;-----------------------------------------------------------------------------------
; ecriture lecture dans l'EEPROM
;-----------------------------------------------------------------------------------

;
; ecriture EEPROM
; en entrée 	dataee=octet à ecrire
;		adresse = adresse
;

writeEE:
	movf adresse,w
	bank2
	movwf EEADR
	bank0
	movf dataee,w
	bank2
	movwf EEDATA
	bank3
	bcf EECON1,EEPGD
	bsf EECON1,WREN	
	bcf INTCON,GIE
	movlw 55H
	movwf EECON2
	movlw 0AA
	movwf EECON2
	bsf EECON1,WR
wee1:
	clrwdt
	btfsc EECON1,WR
	goto wee1
	bcf INTCON,EEIF
	bcf EECON1,WREN
	bank0
	bsf INTCON,GIE
	return

;
; lecture EEPROM
; en entrée 	adresse = adresse à lire
; en sortie	W=octet lu		
;

readEE:
	movf adresse,w
	bank2
	movwf EEADR
	bank3
	bcf EECON1,EEPGD
	bsf EECON1,RD
	bcf STATUS,RP0
	movf EEDATA,w
	bank0
	return

;-----------------------------------------------------------------------------------
; ecriture lecture dans la FLASH
;-----------------------------------------------------------------------------------

;
; ecriture FLASH
; en entrée 	adresseH = MSB adresse
;		adresseL = LSB adresse
; 		dataF	 = octet à ecrire		
;

writeF:				; suivant doc MICROCHIP page 45
	movf adresseH,w
	bank2
	movwf EEADRH
	bank0
	movf adresseL,w
	bank2
	movwf EEADR
	bank0
	movf dataF,w
	bank2
	movwf EEDATA
	bank3
	bsf EECON1,EEPGD
	bsf EECON1,WREN
	bcf INTCON,GIE
	movlw 55
	movwf EECON2
	movlw 0AA
	movwf EECON2
	bsf EECON1,WR	
	nop
	nop
	bsf INTCON,GIE
	bcf EECON1,WREN
	bank0	
	return

;
; lecture FLASH
; en entrée 	adresseH = MSB adresse
;		adresseL = LSB adresse	
; en sortie	W=octet lu		
;

readF:				; suivant doc MICROCHIP page 44
	movf adresseH,w
	bank2
	movwf EEADRH
	bank0
	movf adresseL,w
	bank2
	movwf EEADR
	bank3
	bsf EECON1,EEPGD
	bsf EECON1,RD
	nop
	nop
	bank2
	movf EEDATA,W
	bank0
	return

;-----------------------------------------------------------------------------------
; lecture du code du bouton
;-----------------------------------------------------------------------------------

litcode:
	call touchreset		; reset du bouton
	btfss STATUS,C		; bouton present ?
	goto notpresent		; non
	movlw readrom		; commande lecture identification
	call touchbyte		; et envoi
	call touchreceive	; lecture octet 1 ( LSB temperature )
	movwf serie
	call touchreceive
	movwf part1
	call touchreceive
	movwf part2
	call touchreceive
	movwf part3
	call touchreceive
	movwf part4
	call touchreceive
	movwf part5
	call touchreceive
	movwf part6
	call touchreceive
	movwf dallasCRC
	movlw serie		; verification 
	movwf FSR		; que
	movlw 8			; les
	movwf compteur		; octets
	clrf tmp		; composants
lcboucle:
	movf INDF,w		; le code
	addwf tmp,f		; ne
	decfsz compteur,f	; sont 
	goto lcboucle		; pas 
	movf tmp,w		; tous
	btfsc zero		; à
	goto notpresent		; 0
	call crc8		; verification du crc8
	return			; si le crc est bon le carry est mis
notpresent:
	bcf STATUS,C
	return
			
;
; reset hard sur bouton dallas
;

touchreset:
	bcf _data		; met la ligne à 0
	call tempo480
tr2:
	bsf _data		; tempo
	movlw 03F		; de
	movwf compteur		; 70 µS
tr3:
	decfsz compteur,f	; au niveau
	goto tr3		; haut
tr4:
	call inversedata	; ligne en entrée		
	btfsc _data	
	goto noack		; pas de reponse de dallas
	bsf STATUS,C
	call tempo480
	bsf _data
	call inversedata	; ligne en sortie
	return
noack:
	bcf STATUS,C
	clrwdt
	call tempo480
	bsf _data		
	call inversedata	; ligne en sortie
	return

;
; octet de commande bouton
; l'octet de commande est dans W
;

touchbyte:
	movwf valeur
	movlw 8			; nombre de bits
	movwf rotation		; dans registre rotation
bit_loop:
	rrf valeur,f		; rotation par la droite
	btfsc STATUS,C
	goto send_one
	bcf _data		; mise à 0 de la ligne
	nop
	nop
	nop
	nop
	call tempo65
	bsf _data
	goto tb1
send_one:
	bcf _data		; met la ligne à 0
	nop			; pendant
	nop			; au moins
	nop			; 1
	nop			; microseconde
	bsf _data		; puis met la ligne à 1
	call tempo65
tb1:
	decfsz rotation,f
	goto bit_loop
	return

;
; routine de reception d'un octet
; resultat dans W
;

touchreceive:
	movlw 8			; nombre de
	movwf rotation		; rotations
bitr_loop:
	bcf _data		; ligne à 0
	nop			; pendant
	nop			; au 
	nop			; moins
	nop			; 1 µS	
	call inversedata	; data en entrée
	bcf STATUS,C
	nop			; tempo
	nop			; de 
	nop			; 1 µS ( temps de montée )
	btfsc _data		; test de la ligne
	bsf STATUS,C
	rrf valeur,f		; et stockage bit dans octet
	call inversedata	; data en sortie
	bsf _data
	call tempo65		; tempo de 65 µS
	decfsz rotation,f	; 8 fois
	goto bitr_loop		; bit suivant
	movf valeur,w	; octet dans W
	return
		
tempo65:
	movlw 04C		; tempo de 65 µS
	movwf compteur
tp651:
	decfsz compteur,f
	goto tp651
	return	
	

tempo480:
	movlw 0DF		; tempo
	movwf compteur		; de 480 µS
t4801:
	clrwdt
	nop
	nop
	decfsz compteur,f
	goto t4801
	return

crc8:
	clrf crc
	movlw 7
	movwf nboctet
	movlw serie
	movwf FSR
vcrc1:
	clrwdt
	movlw 8
	movwf compteur
	movf INDF,w
vcrc2:
	clrwdt
	xorwf crc,w
	movwf temp
	rrf temp,w
	movf crc,w
	btfsc STATUS,C
	xorlw 18
	movwf temp
	rrf temp,w
	movwf crc
	movf INDF,w
	movwf temp
	bcf STATUS,C
	rrf temp,f
	btfsc STATUS,C
	bsf temp,7
	movf temp,w
	movwf INDF
	decfsz compteur,f
	goto vcrc2
	incf FSR,f
	decfsz nboctet,f
	goto vcrc1
fin:
	movf dallasCRC,w
	xorwf crc,w
	bsf STATUS,C
	btfss STATUS,Z
	bcf STATUS,C
	return

inversedata:
	bank1
	movf TRISA,w
	xorlw 1
	movwf TRISA
	bank0
	return

;-----------------------------------------------------------------------------------
; initialisations
;-----------------------------------------------------------------------------------

initportA:
	bank0
	clrf PORTA
	bank1
	movlw 0x06			; PORT A = digital input/output
	movwf ADCON1
	movlw b'00000000'		; PORT A en sortie
	movwf TRISA
	bank0
	bsf _data
	return

initportB:
	bank0
	clrf PORTB
	bank1
	movlw b'00000000'
	movwf TRISB
	bank0
	return

initportC:
	bank0
	clrf PORTC
	bank1
	movlw b'10000000'		; RC7 en entrée ( RX )
	movwf TRISC
	bank0
	return

inittmr1:				; initialisation du timer 1
	clrf TMR1L
	clrf TMR1H
	movlw b'00110000'		; timer 1 source = Fosc/4
					; prescaler = 1/8
	movwf T1CON
	movlw 0				; tmr1 := FFFF x 2,89 µS = 0,2 secondes 
	movwf TMR1L
	movlw 0
	movwf TMR1H
	bank1
	bsf PIE1,TMR1IE			; met les interruptions sur timer 1
	bank0
	bsf T1CON,TMR1ON		; start timer 1
	return	

initint:
	bsf INTCON,PEIE			; periperal int enable
	bsf INTCON,GIE			; global int enable
	return

initwdt:				; initialisation du watchdog
	movlw b'11111100'		; prescaler du wdt à 16x72 mS = 1 seconde
	bank1
	movwf OPTION_REG
	bank0
	return
	

;-----------------------------------------------------------------------------------
; RS232
;-----------------------------------------------------------------------------------

initV24:
	bank1
	bcf TXSTA,BRGH			; low speed pour diviseur
	bsf TXSTA,CSRC			; master mode
	movlw 11H			; valeur 17
	movwf SPBRG			; dans diviseur horloge 9600 bauds
	bcf TXSTA,SYNC			; mode asynchrone
	bsf TXSTA,TXEN			; emission enable
	bsf PIE1,RCIE			; interrupt sur reception
	bank0
	bsf RCSTA,CREN			; reception continue enable
	bsf RCSTA,SPEN			; serial port enable	
	return

;
; envoi d'un caractere sur la liaison
; caractere dans W
;
transmit:
	bank1
transmit1:
	btfss TXSTA,TRMT		; registre emission vide ?
	goto transmit1			; non alors retour
	bank0
	movwf TXREG			; registre emission := accu
	bank1
transmit2:
	clrwdt
	btfss TXSTA,TRMT
	goto transmit2
	bank0
	return



interrupt:
	clrwdt
	movwf saveW
	movf STATUS,w
	bank0
	movwf savesta		; sauvegarde registre de status
	movf FSR,w
	movwf saveFSR
	btfsc PIR1,RCIF		; caractere dans buffer
	goto reception
	btfsc PIR1,TMR1IF	; timer 1 expire
	goto timer1int
	goto endint
reception:
	btfsc RCSTA,OERR	; over run error
	goto orerror
	bcf PIR1,RCIF
	movf RCREG,w		; caractere dans W
	movwf caractere
	bsf _receivedcar
	goto endint
orerror:
	bcf RCSTA,CREN
	bsf RCSTA,CREN
	movf RCREG,w
	goto endint
timer1int:
	bcf PIR1,TMR1IF		; RAZ flag
	decfsz timer,f		; 5 rotations ?
	goto endint
	movlw 5
	movwf timer
	incf seconde,f		; seconde=seconde+1
	btfss _clignote
	goto endint
	movlw masque
	xorwf PORTB,f
endint:
	movf saveFSR,w
	movwf FSR
	bcf STATUS,RP0
	movf savesta,w
	movwf STATUS		; reprise registre statut
	movf saveW,w		; reprise accu
	retfie






	end
