;=======================================================================
; Fichier : capacimetre.asm
; Titre: Capacimetre numerique ATMEGA8 - NE555 - Afficheur LCD 2x16
; Version: 1.0
; Auteur: Fred
; Date: 05/12/2005
;
;
;=======================================================================
;Declaration des Variables
;Declaration des Vecteurs d'interruptions
;Routines de traitement des interruptions
;Programme de RESET
;PROGRAMME PRINCIPAL
;PROCEDURES
;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 references des registres (ATMEGA 8)
;------------------------------------------------------------------------
;Declaration des Variables
;------------------------------------------------------------------------
.def gamme=r2
.def type_aff=r3
.def SAUVREG = r16 ; registre de sauvegarde de SREG
.def a=r17
.def AA=r18
.def BB=r19
.def AL=r18 ;idem AA volontairement
.def AH=r19 ;idem BB volontairement
;registres [20..25] pour les variables locales
.DSEG
dtlcd: .BYTE 1
bitn: .BYTE 1
aff1: .BYTE 1
aff2: .BYTE 1
aff3: .BYTE 1
aff4: .BYTE 1
aff5: .BYTE 1
dividende: .BYTE 3
nbr: .BYTE 2
periode: .BYTE 2
offset: .BYTE 1
numerateur: .BYTE 1
denominateur: .BYTE 1
;------------------------------------------------------------------------
;Declaration des Vecteurs d'interruptions
;------------------------------------------------------------------------
.CSEG
.ORG 0x0000 ;debut zone memoire programme
rjmp RESET ;RESET
rjmp EXT_INT0 ;Interruption externe INT0
rjmp EXT_INT1 ;Interruption externe INT1
rjmp TIM2_COMP ;Interrution comparaison reussie TIMER2
rjmp TIM2_OVF ;Interrution debordement compteur TIMER2
rjmp TIM1_CAPT ;Interrution entree capture TIMER1
rjmp TIM1_COMPA ;Interrution comparateurA TIMER1
rjmp TIM1_COMPB ;Interrution comparateurB TIMER1
rjmp TIM1_OVF ;Interrution debordement compteur TIMER1
rjmp TIM0_OVF ;Interrution debordement compteur TIMER0
rjmp SPI_STC ;Interrution transmissions SPI terminee
rjmp UART_RXC ;Interrution reception UART termine RX
rjmp UART_DRE ;Interrution UART vide
rjmp UART_TXC ;Interrution emission UART termine TX
rjmp ADC_ok ;Interrution Conversion A/D terminee
rjmp EE_RDY ;Interrution EEPROM prete
rjmp ANA_COMP ;Interrution comparaison analogique effectuee
;------------------------------------------------------------------------
;Routines de traitement des interruptions
;------------------------------------------------------------------------
EXT_INT0: reti
;------------------------------------------------------------------------
EXT_INT1: reti
;------------------------------------------------------------------------
TIM2_COMP: reti
;------------------------------------------------------------------------
TIM2_OVF: reti
;------------------------------------------------------------------------
;The Input Capture is updated with the counter (TCNT1) value each time an event occurs
;on the ICP1 pin (par le signal dont on veut mesurer la periode))
;TCNT1 est incremente par l'horloge / prescaler
TIM1_CAPT: in sauvreg,sreg
push sauvreg
push a
cli
in a,ICR1L ;lit le registre de capture
sts periode+0,a
in a,ICR1H
sts periode+1,a
clr a
out TCNT1H,a ;raz TCNT1, registre de comptage
out TCNT1L,a
sbic portb,0
sei
pop a
pop sauvreg
out sreg,sauvreg
reti
;------------------------------------------------------------------------
TIM1_COMPA: reti
;------------------------------------------------------------------------
TIM1_COMPB: reti
;------------------------------------------------------------------------
;si debordement de la mesure
TIM1_OVF: in sauvreg,sreg
push sauvreg
push a
sbi portd,6
ldi a,2
mov gamme,a
pop a
pop sauvreg
out sreg,sauvreg
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 a
ldi a,high(RAMEND) ; l'adresse haute de la SRAM
out SPH,a
ldi a,0b11111110 ; PB0 (=ICP1) en entree
out ddrb,a
ldi a,0b01111111 ; PD7(switch) en entree
out ddrd,a
ldi a,0b10000000 ; R de tirage validee pour PD7
out portd,a
ldi a,0b11111111
out ddrc,a
clr a
out portc,a ; sorties = 0
; 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)
ldi a,1
mov gamme,a
ldi a,5
mov type_aff,a
; ldi a,0b01000000 ; enable INT0(externe) sur front montant
; out GICR,a ; General Interrupt Control Register
;------------------------------------------------------------------------
;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,0b00101110 ;TICIE1 =1
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
mov a,gamme
cpi a,1
breq gam1a
cpi a,2
breq gam2a
;------------------------------------------------------------------------
; 76543210
gam1a: ldi a,0b11000001 ; horloge/1 ;(/1 pour gamme 10nF)
rjmp suite0
;------------------------------------------------------------------------
; 76543210
gam2a: ldi a,0b11000011 ; horloge/64 ;(/64 pour gamme 1uF)
suite0: 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:65 du datasheet.pdf et Tavernier p:30
;------------------------------------------------------------------------
initvar: clr a
sts aff1,a
sts aff2,a
sts aff3,a
sts aff4,a
sts aff5,a
ldi a,28
sts offset,a
ldi a,1
sts numerateur,a
ldi a,1
sts denominateur,a
wdr ; raz Watchdog
; ldi a,$01
; out timsk,a ; Validation de l'interruption.
; ldi a,156 ; chargement de la valeur 156
; out tcnt0,a ; dans le registre du compteur
; ldi a,$04 ;
; out tccr0,a ; Selection de la frequence de pre-division
;------------------------------------------------------------------------
;zone de tests de procedures
;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
; ldi r20,LOW(123)
; ldi r21,HIGH(123)
; ldi r22,0
; ldi r23,246
; rcall Div24_8
;
; ldi r20,LOW(65535)
; ldi r21,HIGH(65535)
; ldi a,255
; rcall mul16_8
; ldi r20,LOW(15000)
; ldi r21,HIGH(15000)
; rjmp gam1c
;------------------------------------------------------------------------
;PROGRAMME PRINCIPAL
wdr
;cli ;arret des interruptions (interdite pendant l'affichage qui utilise une tempo)
clr a
sts periode+0,a
sts periode+1,a
zero: rcall dspclr ;efface LCD
rcall home
rcall fset
rcall setmod0
rcall dsp10
ldi a,1
mov gamme,a
ldi a,0
rcall ddras
ldi a,'i'
rcall ecrire
rcall tp100ms
rcall mesure
;doit-on paser en gamme1 ?
; lds a,periode+1
; cpi a,10
; brsh suite3
; ldi a,1
; mov gamme,a
;ajustement de l'offset
suite3: lds a,periode+0
sts offset,a
rcall tp100ms
bcl0: wdr
;cli ;arret des interruptions
ldi a,0
rcall ddras
lds r20,periode+0
lds r21,periode+1
cbi portd,6
sbis pind,7
rjmp zero
mov a,gamme
cpi a,1
breq gam1b
cpi a,2
breq gam2b
gam1b: ldi a,0b11000001 ; horloge/1 ;(/1 pour gamme 10nF)
out TCCR1B,a
ldi a,100 ;(100 pour gamme 10nF)
sts numerateur,a
ldi a,27 ;( 27 pour gamme 10nF)
sts denominateur,a
rjmp saut01
gam2b: ldi a,0b11000011 ; horloge/64 ;(/64 pour gamme 1uF)
out TCCR1B,a
ldi a,24 ;( 24 pour gamme 1uF)
sts numerateur,a
ldi a,100 ;(100 pour gamme 1uF)
sts denominateur,a
rjmp saut01
saut01: lds a,offset ;charge l'offset dans 'a'
ldi AA,2 ;ajustement qui augmente la justesse
add a,AA
clr r22
cp r20,a ;teste si l'offset n'est pas superieur a la mesure (poids faible)
brcc saut02 ;non
cpi r21,0 ;oui, r21=0 ?
brne saut02 ;non
clr r20 ;oui, on affichera zero
clr r21
ldi a,1
mov gamme,a
rjmp saut03
saut02: sub r20,a ;retranche l'offset a la valeur de la mesure dans r20
sbci r21,0 ;report de la retenue sur l'octet de poids fort
lds a,numerateur
rcall mul16_8
;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
lds r23,denominateur
rcall div24_8
cpi r22,0 ;test si resultat sur plus de deux octets: on passe alors en gamme2
breq saut4
ldi a,2
mov gamme,a
ldi a,0b11000011 ; horloge/64 ;(/64 pour gamme 1uF)
out TCCR1B,a
rjmp saut5
;ici r20, r21 contiennent la valeur a afficher
;----------------------------------
;determination de la tranche d'affichage (types T1 a T5)
saut4: mov a,gamme
cpi a,1
breq gam1c ;traitement different suivant la gamme de mesure
cpi a,2
breq gam2c
;traitement pour la gamme1
gam1c: ldi a,1
cpi r21,HIGH(999) ;rd-k
brlo suite10 ;si r21>=999
ldi a,2
cpi r21,HIGH(9999)
brlo suite10
ldi a,3
rjmp suite10
;----------------------------------
;traitement pour la gamme2
gam2c: ldi a,4
cpi r21,HIGH(9999) ;rd-k
brlo suite10 ;si r21>=999
ldi a,5
rjmp suite10
;----------------------------------
suite10: mov type_aff,a
saut03: rcall affnb
rcall affiphy5
saut5: rcall tp100ms
; lds a,mesflags
; sbrc a,0 ;saute l'ins suivante si bit0 =0
; rcall depass
; cbi portd,6 ;LED
rcall mesure
rjmp bcl0
;------------------------------------------------------------------------
;PROCEDURES
;------------------------------------------------------------------------
mesure: sei ;enable interruptions
rcall tp100ms
rcall tp100ms
rcall tp100ms
;cli ;arret des interruptions
ret
;------------------------------------------------------------------------
depass: ldi a,'-'
rcall ecrire
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 ;movlw .56 ;(32+16+8)
sts dtlcd,a ;movwf dtlcd
rcall dt_out ;transmission serie 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 deplace
setmod0: cbi portc,2 ;E=0
cbi portc,3 ;R/S=0
ldi a,6 ;( 4+2 sens inverse si 4+0 )
sts dtlcd,a
rcall dt_out
rcall impuls
ret
;----------------------------------------------------------------------
;DISPLAY ON OFF
dsp10: 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
;----------------------------------------------------------------------
;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 caractere a 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 a 1 avec RS=1
rcall tp1ms
; rcall tp1ms
sbi portc,2 ;fin impulsion
rcall tp1ms
; rcall tp1ms
ret
;----------------------------------------------------------------------
;impulsion E a 1 avec RS=0
impuls: wdr
cbi portc,3 ;R/S=0
sbi portc,2 ;impulsion E a 1
rcall tp1ms
; rcall tp1ms
cbi portc,2 ;fin impulsion
rcall tp1ms
; rcall tp1ms
ret
;----------------------------------------------------------------------
;SORTIE DATA (8 bits) en serie 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 (a 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
; rcall tp1ms
cbi portc,1 ;fin clock
rcall tp1ms
; 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 a afficher
;ex: a=184
affi_a: mov AA,a
rcall cvBDU ;BB=18 et AA=4 ; fractionne les unites et les dizaines
sts aff1,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 aff2,AA ;aff2=8
sts aff3,BB ;aff3=1
ldi a,0
sts aff4,a ;affiche toujours zero
ret
;------------------------------------------------------------------------
;CONVERSION BINAIRE --> BCD
;nombre a convertir dans AA
;resultat dans BB (dizaines) et dans AA (unites)
;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
;------------------------------------------------------------------------
;CONVERSION BINAIRE 2 octets -> Affi5,4,3,2,1
;r20,21 doivent contenir le nombre a convertir. r20=poids faible
;ex: nb1,0 = 6215 =24*256 + 71
;r20 =71
;r21= 24
affnb: clr r22 ;dividende
ldi r23,10 ;diviseur
ldi r26,LOW(aff1) ;registre x
ldi r27,HIGH(aff1) ;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
ret
;------------------------------------------------------------------------
affdeci: push BB
rcall cvBDU
sts aff1,AA
sts aff2,BB
pop AA ;voir push BB plus haut
rcall cvBDU
sts aff3,AA
sts aff4,BB
ret
;------------------------------------------------------------------------
;affichage physique de 5 chiffres
;Types_aff: (Gamme-Type)
;G1-T1 -> 2.7pF 15.6pF on est en gamme1 On affiche tout avec un point
;G1-T2 -> 102pF 335pF on est en gamme1 On n'affiche pas le point ni le premier digit
;G1-T3 -> 1.518nF 4.725nF on est en gamme1. On n'affiche pas le 1er digit. le point est deplace
;G2-T4 -> 22.31nF on est en gamme2 On n'affiche pas le 1er digit. le point est deplace
;G2-T5 -> 101.2nF on est en gamme2
affiphy5: lds a,aff5 ;positionne z si nul
; cpi a,0
; breq affi4 ;pour ne pas afficher le zeros non significatif
ldi b,48 ;code ASCII de zero
add a,b
rcall ecrire
mov a,type_aff
cpi a,3 ;pour T3 afficher le point
breq affi4b
cpi a,5 ;pour T5 afficher le point
breq affi4b
rjmp affi4 ;
affi4b: ldi a,'.'
rcall ecrire
affi4: lds a,aff4
ldi b,48 ;code ASCII de zero
add a,b
rcall ecrire
affi3: lds a,aff3
ldi b,48 ;code ASCII de zero
add a,b
rcall ecrire
mov a,type_aff
cpi a,5 ;pour T5 ne pas afficher la suite
breq affi0
affi2: lds a,aff2
ldi b,48 ;code ASCII de zero
add a,b
rcall ecrire
mov a,type_aff
cpi a,2
breq affi0
cpi a,3
breq affi0
ldi a,'.'
rcall ecrire
affi1: lds a,aff1
ldi b,48 ;code ASCII de zero
add a,b
rcall ecrire
affi0: mov a,type_aff ;REMARQUE: choix de type "case of"
cpi a,1
breq aff_p
cpi a,2
breq aff_p
cpi a,3
breq aff_n
cpi a,4
breq aff_n
cpi a,5
breq aff_u
aff_p: ldi a,'p'
rjmp suite1
aff_n: ldi a,'n'
rjmp suite1
aff_u: ldi a,'u'
rjmp suite1
suite1: rcall ecrire
ldi a,'F'
rcall ecrire
ldi a,' '
rcall ecrire
ldi a,' '
rcall ecrire
rjmp finaff
finaff: ret
;----------------------------------------------------------------------
;mul16_8 ;mutiplication 8 bits x 16 bits resultat sur 24 bits
;multiplie r20(poids faible),r21(poids fort) par 'a'
;produit dans r22,r21,r20
.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' 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=r17
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 retard 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=R20
tp100ms: push R17
ldi n,100
bcl4: rcall tp1ms
dec n
;cpi n,0
brne bcl4
pop R17
ret
;----------------------------------------------------------------------