;======================================================================= ; Fichier : capacimetre.asm ; Titre: Capacimetre numerique ATMEGA8 - NE555 - Afficheur LCD 2x16 ; Version: 1.0 ; Auteur: Fred ; Date: 05/12/2005 ; ; ;======================================================================= ;Déclaration des Variables ;Déclaration 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 références des registres (ATMEGA 8) ;------------------------------------------------------------------------ ;Déclaration 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 ;------------------------------------------------------------------------ ;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 ;------------------------------------------------------------------------ EXT_INT0: reti ;------------------------------------------------------------------------ EXT_INT1: reti ;------------------------------------------------------------------------ TIM2_COMP: reti ;------------------------------------------------------------------------ TIM2_OVF: reti ;------------------------------------------------------------------------ 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 à 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 fréquence de pré-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 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 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 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 ; rcall tp1ms sbi portc,2 ;fin impulsion rcall tp1ms ; 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 ; rcall tp1ms cbi portc,2 ;fin impulsion rcall tp1ms ; 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 ; 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 à 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 à 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 ;------------------------------------------------------------------------ ;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 zéros non significatif ldi b,48 ;code ASCII de zéro 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 zéro add a,b rcall ecrire affi3: lds a,aff3 ldi b,48 ;code ASCII de zéro 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 zéro 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 zéro 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' à 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 ;----------------------------------------------------------------------