;=======================================================================
; Fichier : gene_freq.asm
; Titre: GENERATEUR de Frequences ATMEGA8 -  Afficheur LCD 2x16
; Version: 1.0
; Auteur: Fred
; Date: 06/02/2006				     
;									
;							
;=======================================================================

;Déclaration des Variables
;Déclaration des Vecteurs d'interruptions
;Routines de traitement des interruptions
;Programme de RESET
;PROGRAMME PRINCIPAL
;ROUTINES

;mul16_8	MULTIPLICATION 8 bits x 16 bits resultat sur 24 bits
;div24_8	DIVISION 24 bits par 8 bits, resultat sur 24 bits


.include "m8def.inc"	; nom du fichiers de références des registres (ATMEGA 8)


;------------------------------------------------------------------------
;Déclaration des Variables		                 	
;------------------------------------------------------------------------
;r0,1,2 = Fout (max=2^24 = 16.777216 MHz . En fait on se limitera a Fout max = 8MHz (8000 000 Hz) )
.def SAUVREG = r3	; registre de sauvegarde de SREG
.def fact_div =r4	;facteur de division (valeur appliquee au commutateur 74LS151 a la sortie du generateur)

;r15 reserve pour l'INT_EXT0

.def a=r16
.def AA=r17
.def BB=r18
.def rang = r17	;=AA volontairement
.def n_touche = r18	;=BB volontairement

;r20..25 reserve pour les variables locales
;r26,27 reserve comme registre d'adresse d'indexation (X)

.def cpt0 = r19	;LSB 		utilise pour compteur diviseur de frequence (voir EXT_INT1)
.def cpt1 = r28	;BYTE2		utilise pour compteur diviseur de frequence (voir EXT_INT1)
.def cpt2	= r29	;HIGH BYTE	utilise pour compteur diviseur de frequence (voir EXT_INT1)

;r30,31 reserve comme registre d'adresse d'indexation (Z) permet la lecture en memoire de programme

.DSEG
	dtlcd:		.BYTE 1
	TAB_AFF8:		.BYTE 8	;tableau de 8 octets codants 8 chiffres a afficher

	nombre1:		.BYTE 3	;nombre code sur 3 octets (binaire) 0...16 777 216
	nombre2:		.BYTE 3	;""

	dividende: 	.BYTE 3
	numerateur:	.BYTE 1
	denominateur:	.BYTE 1
 


;------------------------------------------------------------------------
;MACROS
;------------------------------------------------------------------------
	
;cette macro fait @0(variable en RAM, 24bits)  := @1 valeur(24bits) pasee en parametre
.MACRO	Mset24
	ldi	a,BYTE1(@1)
	sts	@0+0,a
	ldi	a,BYTE2(@1)
	sts	@0+1,a
	ldi	a,BYTE3(@1)
	sts	@0+2,a

.ENDMACRO	

;------------------------------------------------------------------------
;cette macro fait @0(variable en RAM, 24bits)  := r20,21,22
.MACRO	Mstore24
	sts	@0+0,r20
	sts	@0+1,r21
	sts	@0+2,r22

.ENDMACRO	

;------------------------------------------------------------------------
;cette macro fait 3 registres successifs  := @0 (variable en RAM, 24bits, pasee en parametre)
.MACRO	Mload24
	lds	r20,@0+0
	lds	r21,@0+1
	lds	r22,@0+2


.ENDMACRO	


;------------------------------------------------------------------------
;Déclaration des Vecteurs d'interruptions
;------------------------------------------------------------------------

.CSEG
.ORG 0x0000			;début zone mémoire programme
	rjmp	RESET		;RESET
	rjmp	EXT_INT0		;Interruption externe INT0
	rjmp 	EXT_INT1		;Interruption externe INT1
	rjmp 	TIM2_COMP		;Interrution comparaison réussie TIMER2
	rjmp 	TIM2_OVF		;Interrution débordement compteur TIMER2  
	rjmp 	TIM1_CAPT		;Interrution entrée capture TIMER1
	rjmp	TIM1_COMPA	;Interrution comparateurA TIMER1
	rjmp 	TIM1_COMPB	;Interrution comparateurB TIMER1
	rjmp	TIM1_OVF		;Interrution débordement compteur TIMER1 
	rjmp 	TIM0_OVF		;Interrution débordement compteur TIMER0 
	rjmp 	SPI_STC		;Interrution transmissions SPI terminée
	rjmp 	UART_RXC		;Interrution réception UART terminé RX
	rjmp 	UART_DRE		;Interrution UART vide 
	rjmp 	UART_TXC		;Interrution émission UART terminé TX
	rjmp 	ADC_ok		;Interrution Conversion A/D terminée
	rjmp 	EE_RDY		;Interrution EEPROM prête
	rjmp 	ANA_COMP		;Interrution comparaison analogique effectuée
	
;------------------------------------------------------------------------
;Routines de traitement des interruptions
;------------------------------------------------------------------------
;F-in limite avec Qx=16MHz = 450kHz

			
EXT_INT0:		in	sauvreg,sreg
		push 	sauvreg
		push	a

		subi	cpt0,1	;attention: l'instruction 'dec' ne positionne pas 'c'
		brcc	fin_int0

		subi	cpt1,1
		brcc	fin_int0

;		subi	cpt2,1
;		brcc	fin_int0
;-------------
;les 3 lignes de code suivantes divisent par 2 la frequence de passage dans cette reoutine
;L'avantage est de fournir un signal exploitable de rapport cyclique = 1/2
;au niveau materiel, on comparera la frequence de sortie a 50Hz au lieu de 100 Hz (voir schema)
		in	a,pinc	;inverse etat du pin pc4 (genere le signal de sortie)
		eor	a,r15	;r15 contient la valeur constante (5)
		out	portc,a
;-------------
		mov	cpt0,r0	;transfert de Fout dans les registres de comptage (rechargement du compteur 24 bits)
		mov	cpt1,r1	;(rechargement du compteur 24 bits)
		mov	cpt2,r2	;(rechargement du compteur 24 bits)

			
fin_int0:		pop	a
		pop 	sauvreg
		out 	sreg,sauvreg
		reti

;------------------------------------------------------------------------
EXT_INT1:		reti
;------------------------------------------------------------------------
TIM2_COMP:	reti
;------------------------------------------------------------------------
TIM2_OVF:		reti
;------------------------------------------------------------------------
TIM1_CAPT:	reti
;------------------------------------------------------------------------
TIM1_COMPA:	reti
;------------------------------------------------------------------------
TIM1_COMPB:	reti
;------------------------------------------------------------------------
TIM1_OVF:		reti	
;------------------------------------------------------------------------
TIM0_OVF:		reti
;------------------------------------------------------------------------
SPI_STC:		reti
;------------------------------------------------------------------------
UART_RXC:		reti
;------------------------------------------------------------------------
UART_DRE:   	reti
;------------------------------------------------------------------------
EE_RDY:		reti
;------------------------------------------------------------------------
ANA_COMP:		reti
;------------------------------------------------------------------------
ADC_ok:		reti
;------------------------------------------------------------------------
UART_TXC:		reti
;------------------------------------------------------------------------
UART_RXC1:	reti
;------------------------------------------------------------------------


;------------------------------------------------------------------------
;Programme de RESET
;------------------------------------------------------------------------


RESET:	ldi	a,low(RAMEND)
	out	SPL,a		; Initialisation de la pile à   
	ldi	a,high(RAMEND)	; l'adresse haute de la SRAM
	out	SPH,a	
;------------------------------------------------------------------------
;initialisation des ports
	ldi 	a,0b11111110	; PB0 (=ICP1) en entree
	out 	ddrb,a

	ldi 	a,0b00000000	; pd0,1 et pd4,5,6,7(switchs) en entree
	out 	ddrd,a
	ldi	a,0b11110011	; R de tirage validee pour switchs
	out 	portd,a


	ldi 	a,0b11111111	;toutes en sorties	
	out 	ddrc,a
	clr 	a
	out 	portc,a		; sorties = 0
;------------------------------------------------------------------------
;wachtdog	
;	wdr			
;	ldi 	a,0b00001111	; wachtdog enable; delai = 2s (voir p:82)
;	out 	wdtcr,a

	wdr
	ldi	a,0b00011111
	out 	wdtcr,a
	ldi	a,0b00010111
	out 	wdtcr,a		; disable le wachtdog. (voir p:83)


;------------------------------------------------------------------------
;TIMSK
;Timer Interrupt Mask; voir pdf p:70
;bit7 (OCIE2)
;bit6 (TOIE2)
;bit5 (TICIE1) Timer/Counter1, Input Capture Interrupt Enable
;bit4 (OCIE1A) Timer/Counter1, Output Compare A Match Interrupt Enable
;bit3 (OCIE1B) Timer/Counter1, Output Compare B Match Interrupt Enable
;bit2 (TOIE1)  Timer/Counter1, Overflow Interrupt Enable
;bit1 inutilise
;bit0 (TOIE0) Timer/Counter0 Overflow Interrupt Enable

		;   76543210
	ldi	a,0b00000000	
	out	TIMSK,a
;------------------------------------------------------------------------
;TCCR1B
;definit le mode de fonctionnement  du Timer1 avec utilisation de la fonction 'capture' sur pin ICP1
;voir Tavernier p:94-95 ;et p:81-82 du datasheet.pdf

;bit7 (ICNC1): enable/disable reducteur de bruit
;bit6 (ICES1)=1: transfert du registre de comptage TCNT1 dans le registre de capture ICR1 sur front montant du pin ICP
;bit5 : inutilise
;bit4 : inutilise
;bit3 (WGM12 ou CTC1): raz registre de comptage (TCNT1) apres comparaison
;bits2,1,0: taux de predivision applique a l'horloge systeme. voir Tavernier p:95

		;   76543210
	ldi	a,0b11000011	; horloge/64
	out	TCCR1B,a
;------------------------------------------------------------------------
;MCUCR bits[1,0]
;ISC11 ISC10 Description
;0 0 The low level of INT1 generates an interrupt request.
;0 1 Any logical change on INT1 generates an interrupt request.
;1 0 The falling edge   of INT1 generates an interrupt request.
;1 1 The rising  edge   of INT1 generates an interrupt request.

	ldi	a,0b00000011	;enable INT0(externe) sur front montant
	out	MCUCR,a		;voir p:64 du datasheet.pdf et Tavernier p:30

;------------------------------------------------------------------------
;GICR (GENERAL INTERRUPT CONTROL REGISTER)
;page 47 et 65 du datasheet
;bit 7 = INT1 enable
;bit 6 = INT0 enable

	ldi	a,0b01000000	; enable INT0(externe)
	out	GICR,a

;------------------------------------------------------------------------
initvar:	clr	a
	sts	TAB_AFF8+0,a
	sts	TAB_AFF8+1,a
	sts	TAB_AFF8+2,a
	sts	TAB_AFF8+3,a
	sts	TAB_AFF8+4,a
	sts	TAB_AFF8+5,a
	sts	TAB_AFF8+6,a
	sts	TAB_AFF8+7,a

;	ldi	a,1
;	sts	numerateur,a
;	ldi	a,1
;	sts	denominateur,a

	ldi	a,1
	mov	fact_div,a

	ldi	r20,BYTE1(4)	;Fixe Fout
	ldi	r21,BYTE2(4)
	ldi	r22,BYTE3(4)

	mov	r0,r20	;r20,21,22 := Fout
	mov	r1,r21
	mov	r2,r22

	ldi	rang,4		;rang (position decimale) du chiffre a modifier

	wdr			; raz Watchdog


;------------------------------------------------------------------------
;zone de tests de procedures


;------------------------------------------------------------------------
;PROGRAMME PRINCIPAL
;------------------------------------------------------------------------
	wdr

	cli	;arret des interruptions (pendant l'affichage qui utilise une tempo)
	ldi	a,0b00010000
	mov	r15,a	;valeur constante dans r15 durant tout le programme (pour economiser une instruction dans INT_EXT0)

zero:	rcall 	dspclr	;efface LCD
	rcall 	home
	rcall 	fset
	rcall 	setmod0
	rcall 	dsp10c1

	ldi	a,0
	rcall	ddras

	
	rcall	tp100ms

	mov	r20,r0	;r20,21,22 := Fout
	mov	r21,r1
	mov	r22,r2

.equ nbr_chiffres = 5

	rcall	affnb8
	ldi	a,nbr_chiffres
	rcall	affiphyN

	mov	a,rang
	subi	a,8-nbr_chiffres
	rcall	ddras

	rcall	tp100ms

	sei	;Sets the Global Interrupt flag (I) in SREG (status register)
bcl0:	wdr

	rcall	scrute

	cli
	ldi	a,0
	rcall	ddras

	mov	r20,r0	;r20,21,22 := Fout
	mov	r21,r1
	mov	r22,r2

	rcall	affnb8
	ldi	a,nbr_chiffres
	rcall	affiphyN

	ldi	a,6
	rcall	ddras
;	rcall	tp100ms
	mov	a,fact_div
	rcall	affi_a
	ldi	a,3
	rcall	affiphyN
;	rcall	tp100ms

	
	mov	a,rang
	subi	a,8-nbr_chiffres
	rcall	ddras
	sei

	rcall	attente	;attend relachement des touches
	rcall	tp100ms	;ne pas supprimer

	rjmp	bcl0
	
;------------------------------------------------------------------------
;ROUTINES
;------------------------------------------------------------------------
;attend qu'une touche soit appuyee et la traite

scrute:	in	n_touche,pind
	com	n_touche
	andi	n_touche,0b11110011	;masque

	breq	scrute		;si aucune touche appuyee
;----------------------------------
	cpi	n_touche,1	;TOUCHE DEPLACE CURSEUR A DROITE
	brne	scr2

	dec	rang

	rcall	tp100ms
	rjmp	fin_scr	
;----------------------------------
scr2:	cpi	n_touche,2	;TOUCHE DEPLACE CURSEUR A GAUCHE
	brne	scr3

	inc	rang

	rcall	tp100ms
	rjmp	fin_scr
;----------------------------------
scr3:	cpi	n_touche,16	;TOUCHE INCREMENTE Fout (uniquement le digit sous le curseur)
	brne	scr4

	rcall	charge1p	;(valeurs positives pour incrementer Fout)

	mov	r20,r0	;r20,21,22 := Fout
	mov	r21,r1
	mov	r22,r2

	rcall	add24a	;r21,22,23:=r21,22,23 + nombre1 Modifie : Fout:=Fout + nombre1(multiple de 10)

	rjmp	storeF
;----------------------------------
scr4:	cpi	n_touche,32	;TOUCHE DECREMENTE Fout (uniquement le digit sous le curseur)
	brne	scr5
	
	rcall	charge1m	;(valeurs negatives pour decrementer Fout)

	mov	r20,r0	;r20,21,22 := Fout
	mov	r21,r1
	mov	r22,r2

	rcall	add24a	;r21,22,23:=r21,22,23 + nombre1
	brcs	storeF	;si pas debordement

	rcall	charge1p	;si debordement
	rcall	add24a	;RAZ derniere decrementation

	rjmp	storeF
;----------------------------------
scr5:	cpi	n_touche,64	;TOUCHE decremente facteur de division
	brne	scr6

	dec	fact_div
	brpl	scr5b
	inc	fact_div

scr5b:	rcall	tp100ms
	rjmp	fin_scr
;----------------------------------
scr6:	cpi	n_touche,128	;TOUCHE incremente facteur de division
	brne	fin_scr

	inc	fact_div

	rcall	tp100ms
	rjmp	fin_scr
;----------------------------------

	
storeF:	mov	r0,r20	;r20,21,22 := Fout
	mov	r1,r21
	mov	r2,r22

	mov	cpt0,r0	;tranfert de Fout dans les registres de comptage
	mov	cpt1,r1	;(rechargement du compteur 24 bits)
	mov	cpt2,r2


fin_scr:	ret
;FIN DE LA ROUTINE scrute

;------------------------------------------------------------------------
;attend relachement des touches
attente:	in	n_touche,pind
	com	n_touche
	andi	n_touche,0b00001111
	cpi	n_touche,0
	brne	attente
	ret
;------------------------------------------------------------------------
;charge une valeur decimale multiple de 10 dans nombre1
;remarque : un tableau en FLASH (lu par l'instruction LPM) ne m'a pas paru judicieux, vu la taille des mots (3 octets)
;je verrais plutot une version calculee de cette routine (par multiplication de 10 dans une boucle)
charge1p:	cpi	rang,7
	brne	cg6p
	Mset24 	nombre1, 1	;appel ; nombre1(sur 3octets):=1
cg6p:	cpi	rang,6
	brne	cg5p
	Mset24 	nombre1, 10	;appel ; nombre1(sur 3octets):=10
cg5p:	cpi	rang,5
	brne	cg4p
	Mset24 	nombre1, 100	;appel ; nombre1(sur 3octets):=100
cg4p:	cpi	rang,4
	brne	cg3p
	Mset24 	nombre1, 1000	;appel ; nombre1(sur 3octets):=1000
cg3p:	cpi	rang,3
	brne	cg2p
	Mset24 	nombre1, 10000	;appel ; nombre1(sur 3octets):=10000
cg2p:	cpi	rang,2
	brne	cg1p
	Mset24 	nombre1, 100000	;appel ; nombre1(sur 3octets):=100000
cg1p:	cpi	rang,1
	brne	cg0p
	Mset24 	nombre1, 1000000	;appel ; nombre1(sur 3octets):=1000000
cg0p:	ret
;------------------------------------------------------------------------
;charge une valeur decimale multiple de 10 dans nombre1
charge1m:	cpi	rang,7
	brne	cg6m
	Mset24 	nombre1, -1	;appel ; nombre1(sur 3octets):=-1
cg6m:	cpi	rang,6
	brne	cg5m
	Mset24 	nombre1, -10	;appel ; nombre1(sur 3octets):=-10
cg5m:	cpi	rang,5
	brne	cg4m
	Mset24 	nombre1, -100	;appel ; nombre1(sur 3octets):=-100
cg4m:	cpi	rang,4
	brne	cg3m
	Mset24 	nombre1, -1000	;appel ; nombre1(sur 3octets):=-1000
cg3m:	cpi	rang,3
	brne	cg2m
	Mset24 	nombre1, -10000	;appel ; nombre1(sur 3octets):=-10000
cg2m:	cpi	rang,2
	brne	cg1m
	Mset24 	nombre1, -100000	;appel ; nombre1(sur 3octets):=-100000
cg1m:	cpi	rang,1
	brne	cg0m
	Mset24 	nombre1, -1000000	;appel ; nombre1(sur 3octets):=-1000000
cg0m:	ret

;========================================================================
; PROCEDURES D'AFFICHAGE PHYSIQUE SUR LE LCD
;========================================================================


;FUNCTION SET

fset:	cbi	portc,2	;E=0
	cbi	portc,3	;R/S=0

	ldi	a,56	;56=(32 + 16(=8bits) + 8(=2lignes))  ou 48=(32 + 16(=8bits) + 0(=1ligne))
	sts	dtlcd,a		

	rcall 	dt_out	;transmission série vers 4015 -> DATA // LCD
	rcall 	impuls
	ret

;----------------------------------------------------------------------
;DISPLAY CLEAR
dspclr:	cbi	portc,2	;E=0
	cbi	portc,3	;R/S=0

	ldi	a,1
	sts	dtlcd,a
	rcall 	dt_out
	rcall 	impuls
	ret
;----------------------------------------------------------------------
;RETURN HOME
home:	clr	a
	out 	portc,a	;clrf portc
	ldi	a,2	;movlw	.2
	sts	dtlcd,a
	rcall 	dt_out
	rcall 	impuls
	ret

;----------------------------------------------------------------------
;ENTRY MODE SET 0
;le curseur se déplace
setmod0:	cbi	portc,2	;E=0
	cbi	portc,3	;R/S=0
	ldi	a,6	;( 4 + 2(sens) + (accompagnement))	
	sts	dtlcd,a
	rcall 	dt_out
	rcall 	impuls
	ret


;----------------------------------------------------------------------
;DISPLAY ON curseur OFF
dsp10c0:	cbi	portc,2	;E=0
	cbi	portc,3	;R/S=0
	ldi	a,12	;( 8+4 )	
	sts	dtlcd,a
	rcall 	dt_out
	rcall 	impuls
	ret
;----------------------------------------------------------------------
;DISPLAY ON curseur ON
dsp10c1:	cbi	portc,2	;E=0
	cbi	portc,3	;R/S=0
	ldi	a,14	;( 8+4+2 )	
	sts	dtlcd,a
	rcall 	dt_out
	rcall 	impuls
	ret

;----------------------------------------------------------------------
;DDRAM ADRESS SET (A)
;a doit contenir l'adresse (position d'affichage. voir doc)
.def b=R20
ddras:	cbi	portc,2	;E=0
	cbi	portc,3	;R/S=0
	ldi	b,128	;addlw	.128
	add	a,b
	sts	dtlcd,a
	rcall 	dt_out
	rcall 	impuls
	ret

;----------------------------------------------------------------------
;ECRIRE
;a doit contenir la valeur ASCII du caractère à afficher
ecrire:	wdr
	cbi	portc,2	;E=0
	sbi	portc,3	;R/S=1
	sts	dtlcd,a
	rcall 	dt_out
	sbi	portc,2		;impuls E à 1 avec RS=1
	rcall 	tp1ms
	sbi	portc,2		;fin impulsion
	rcall 	tp1ms
	ret

;----------------------------------------------------------------------
;impulsion E à 1 avec RS=0
impuls:	wdr
	cbi	portc,3		;R/S=0
	sbi	portc,2		;impulsion E à 1
	rcall 	tp1ms
	cbi	portc,2		;fin impulsion
	rcall 	tp1ms
	ret

;----------------------------------------------------------------------
;SORTIE DATA (8 bits) en série sur PA0 vers CD4015. PA1=Clock 4015

.def	n=r20
dt_out:	ldi	n,8
	lds	a,dtlcd
dtbcl:	rol	a	;bit de poids fort -> dans c 	;rlf	dtlcd,f
	cbi	portc,0	;bcf	portc,0	;bit = 0 (à priori)
	brcc	dt_out1	;btfsc	STATUS,0	;test carry
	sbi	portc,0	;bsf	portc,0	;non,  bit = 0
dt_out1:	sbi	portc,1	;clock 4015
	rcall	tp1ms
	cbi	portc,1	;fin clock
	rcall	tp1ms
	dec	n	;decfsz	n,f
	cpi	n,0
	brne	dtbcl
	ret

;-----------------------------------------------------------------------
;decompose un octet [0..255] -> notation BCD dans variables aff1..4
;unites -> aff1
;dizaines -> aff2
;centaines -> aff3
;milliers (en fait toujours zero) -> aff4
;a doit contenir l'octet à afficher
;ex: a=184

affi_a:	push	AA
	push	BB
	mov	AA,a
	rcall 	cvBDU	;BB=18 et AA=4 ; fractionne les unites et les dizaines
	sts	TAB_AFF8,AA	;aff1=4
	mov	AA,BB	;AA=18
	rcall 	cvBDU	;BB=1 et AA=8 ; si les dizaines sont > 9, fractionne en dizaines et centaines
	sts	TAB_AFF8+1,AA	;aff2=8
	sts	TAB_AFF8+2,BB	;aff3=1
	ldi	a,0
	sts	TAB_AFF8+3,a	;affiche toujours zero
	sts	TAB_AFF8+4,a
	sts	TAB_AFF8+5,a
	sts	TAB_AFF8+6,a
	sts	TAB_AFF8+7,a
	pop	BB
	pop	AA
	ret

;------------------------------------------------------------------------
;CONVERSION BINAIRE --> BCD
;appellee depuis affi_a qui push pop AA et BB
;nombre à convertir dans AA
;resultat dans BB (dizaines) et dans AA (unités)
;ex: AA=237 -> BB=23 et AA=7
;ex2 a=84  -> BB=8  et AA=4
;
cvBDU:	clr	BB
conv2:	cpi	AA,10	;AA:=AA-10
	brcs	conv3	;9 passages au max si nb <= 99
	subi	AA,10
	inc	BB
	rjmp	conv2
conv3:	ret
	
;------------------------------------------------------------------------
;decode un nombre de 5 chiffres (2 octets) en vu de l afficher en notation decimale
;NB = 0...65535
;CONVERSION BINAIRE 2 octets -> Affi5,4,3,2,1
;r20,21 doivent contenir le nombre a convertir. r20=poids faible


affnb:	push	AA
	clr	r22	;byte du dividende non utilisee
	ldi	r23,10	;diviseur

	ldi	r26,LOW(TAB_AFF8)	;registre x = adresse (TAB_AFF8)
	ldi	r27,HIGH(TAB_AFF8)	;registre x

	ldi	AA,5	;compteur de boucle

affnb1:	rcall	Div24_8	;(ne touche pas r26)
	st	x+,r24	;reste de la division par 10

	dec	AA
	brne	affnb1

	pop	AA
	ret

;------------------------------------------------------------------------
;decode un nombre de 8 chiffres (3 octets) en vu de l afficher en notation decimale
;NB = 0...16777215
;CONVERSION BINAIRE 3 octets -> Affi8,7,6,5,4,3,2,1
;r20,21,22 doivent contenir le nombre a convertir. r20=poids faible
;ex: 123456 =1 *256*256 + 226 *256 +64 *256
;r20=64
;r21=226
;r22=1

affnb8:	push	AA
	ldi	r23,10		;diviseur

	ldi	r26,LOW(TAB_AFF8)	;registre x = adresse de (TAB_AFF8)
	ldi	r27,HIGH(TAB_AFF8)	;registre x

	ldi	AA,8		;compteur de boucle

affnb81:	rcall	Div24_8		;(ne touche pas r26)
	st	x+,r24		;reste de la division par 10 - cette instruction incremente x a chaque passage

	dec	AA
	brne	affnb81

	pop	AA
	ret

;------------------------------------------------------------------------
;affichage physique de N chiffres (N=1..8)
;a doit contenir N

affiphyN:	push	AA
	push	BB
	mov	BB,a
	ldi	r26,LOW(TAB_AFF8+8)	;registre x
	ldi	r27,HIGH(TAB_AFF8+8);registre x

	ldi	AA,8		;compteur de boucle
	
affphyN1:	ld	a,-x		;cette instruction decremente x a chaque passage

	ldi	b,48		;code ASCII de zéro
	add	a,b
	cp	BB,AA		;compare AA-BB
	brlo	affphyN2		;defense d'afficher

	rcall 	ecrire
	

affphyN2:	dec	AA
	brne	affphyN1

	pop	BB
	pop	AA
	ret

;----------------------------------------------------------------------
;ADDITION sur 3 octets (1)
;r20,21,22:= r20,21,22 + nombre 1


add24a:	lds	a,nombre1+0
	add	r20,a
	lds	a,nombre1+1
	adc	r21,a
	lds	a,nombre1+2
	adc	r22,a
	ret	

;----------------------------------------------------------------------
;ADDITION sur 3 octets (2)
;nombre1:= nombre 1 +nombre2

add24b:	push	AA
	push	BB
	lds	AA,nombre1+0
	lds	BB,nombre2+0
	add	AA,BB
	sts	nombre1+0,AA

	lds	AA,nombre1+1
	lds	BB,nombre2+1
	adc	AA,BB
	sts	nombre1+1,AA
	
	lds	AA,nombre1+2
	lds	BB,nombre2+2
	adc	AA,BB
	sts	nombre1+1,AA
	pop	BB
	pop	AA
	ret	

;----------------------------------------------------------------------
;MULTIPLICATION 8 bits x 16 bits resultat sur 24 bits
;multiplie r20(poids faible),r21 , r22(poids fort) par 'a'
;produit dans r20,r21,r22

.def produit0=r20	;produit poids faible
.def produit1=r21	;produit
.def produit2=r22	;produit poids fort
.def n1=r23

mul16_8:	ldi	n1,17		;compteur de boucle
		
mul16_81:	ror	produit2
	ror	produit1
	ror	produit0

	brcc	mul16_82		;lecture d'un bit de r20 ; test de ce bit
	add	produit2,a	;si c' est un '1' on ajoute 'a' à A2

mul16_82:	dec	n1
	brne	mul16_81

	ret

;----------------------------------------------------------------------
;DIVISION 24 bits par 8 bits, resultat sur 24 bits
;note; le quotient est stocke dans le dividende; permet de decaller les deux a la fois

;r20,21,22 doivent contenir le dividende (r20=LSB)
;r23 doit contenir le diviseur
;resultat (Quotient) dans r20 (LSB) et r21 et r22
;reste dans r24
;le bit T=1 indique un debordement

.def Dividend0=r20	;pour la routine Div24_8
.def Dividend1=r21	;pour la routine Div24_8
.def Dividend2=r22	;pour la routine Div24_8
.def Diviseur =r23	;pour la routine Div24_8.
.def Aux0=r24	;pour la routine Div24_8
.def Aux1=r25
.def n1=r16	;attention: ecrase r16 (=a)

div24_8:	ldi	n1,24	
	clr	Aux0		;clrf	Aux+0

div24_80:	lsl	Dividend0
	rol	Dividend1
	rol	Dividend2

div24_81:	rol	Aux0	;decalle le dividende dans 'Aux' (passage d'un bit par "c")
	rol	Aux1

	cp	aux0,Diviseur
	brlo	auxPetit
	
auxGrand:	sub	Aux0,Diviseur
	sec
	rjmp	saut1

auxPetit:	clc
	
saut1:	rol	Dividend0	;decalle a gauche en incorporant 'c' comme bit 0
	rol	Dividend1	;decalle a gauche avec passage d'un bit par "c"
	rol	Dividend2 ;decalle a gauche et envoie un bit par 'c' dans 'Aux' (apres le saut)

	dec	n1	;important: ne touche pas a 'c'
	brne	Div24_81
	
	ret

;----------------------------------------------------------------------
;TEMPO 1ms exactement avec un Qx=16.000MHz
;attention: sous reserve de ralentissement par les interruptions...

.def	i1=r20
.def	i2=r21

tp1ms:	push	r20
	push	r21

	ldi	i1,16
bcl2:	ldi	i2,248	
bcl3:	dec	i2
	;cpi	i2,0
	brne	bcl3

	nop		;pour ajuster exactement la duree
	nop
	nop
	dec	i1
	;cpi	i1,0
	brne	bcl2

	nop
	pop	r20
	pop	r21
	ret

;----------------------------------------------------------------------
;tempo 100ms

.def n=r16

tp100ms:	push	r16
	ldi	n,100

bcl4:	rcall	tp1ms
	dec	n
	;cpi	n,0
	brne	bcl4

	pop	R16
	ret

;----------------------------------------------------------------------





