;======================================================================= ; VARIATEUR pour moteur BRUSHLESS à 3 fils : variat4.asm ; pour ATMEGA8 et Qx=16,000 Mhz ;dernière mise à jour: 22/05/2006 ; Version: 1.00 ; Auteur: Silicium628 ;======================================================================= ;Cette realisation fait suite a celle utilisant un PIC16F628 ;======================================================================= ;PRINCIPE ;======================================================================= ;LISTE DES PARTIES: ;Déclaration des Variables ;MACROS ;Déclaration des Vecteurs d'interruptions ;Routines de traitement des interruptions ;Programme de RESET ;initialisation des ports ;PROGRAMME PRINCIPAL ;ROUTINES ;STOP ;pasMoteur ;demarre ;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 n_pas = r0 .def SAUVREG = r15 ; registre de sauvegarde de SREG .def a=r16 .def AA=r17 .def BB=r18 .def Flags1 = r19 ;"mesflags1" ;Flags1[0]= incrementation demande ;Flags1[1]= ;Flags1[2]= ;Flags1[3]= MODE : (actuellement inutilise) ;Flags1[4]= Attente relachement des touches demande ;r20..25 reserve pour les variables locales ;r26,27 reserve comme registre d'adresse d'indexation (X) ;r30,31 reserve comme registre d'adresse d'indexation (Z) permet la lecture en memoire de programme .DSEG 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 ;------------------------------------------------------------------------ ;declenchee par les signaux de BEMF ;fait avancer le moteur d'un pas EXT_INT0: in sauvreg,sreg push sauvreg push a rcall pasMoteur fin_int0: pop a pop sauvreg out sreg,sauvreg reti 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 ;------------------------------------------------------------------------ cli texte: .DB 'V','A','R','I','A','T','E','U','R' ;Pour reperer facilement le bon .ASM dans PonyProg! ;(evite de grosses meprises lorsque je travaille sur plusieurs softs en meme temps...) 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 ;PORT A: ldi a,0b00000000 ;toutes en entree out ddrd,a ldi a,0b11111111 ;R de tirage out portd,a ;PORT B: ldi a,0b11111111 ;toutes en sorties out ddrb,a ;PORT C: 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 - voir Tavernier p:96 ; 76543210 ldi a,0b00010001 ;Timer1 Output Compare A Match Interrupt Enable ;Timer0 Overflow Interrupt Enable out TIMSK,a ;------------------------------------------------------------------------ ;TCCR0 ;definit le mode de fonctionnement du Timer0 ;bits7a3 = non utilise ;bits2,1,0 = taux de predivision de l'horloge voir Tavernier p:87 ;16MHz/1024 = 15625 Hz ; 76543210 ldi a,0b00000101 ;1/1024 (voir tableau Tavernier p:88) out TCCR0,a ;------------------------------------------------------------------------ ;TCCR1A ;definit le mode de fonctionnement du Timer1 ;voir Tavernier p:93 ;bit7 (COM1A1) ;definit le comportement de la sortie OC1A ;bit6 (COM1A0) ;bit5 (COM1B0) ;bit4 (COM1B1) ;bit3,2 NC ;bit1 (PWM11) ;bit0 (PWM10) ; 76543210 ldi a,0b00000000 ;voir tableau Tavernier p:93 out TCCR1A,a ;------------------------------------------------------------------------ ;TCCR1B ;definit le mode de fonctionnement du Timer1 ;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,0b00001110 ;horloge externe pour le Timer1, RAZ du compteur (TCNT1) lors de comparaison OK out TCCR1B,a ;------------------------------------------------------------------------ ;MCUCR ;voir datasheet p:31 ;bits[3,2] -> 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. ;bits[1,0] -> ISC01 ISC00 Description ;0 0 The low level of INT0 generates an interrupt request. ;0 1 Any logical change on INT0 generates an interrupt request. ;1 0 The falling edge of INT0 generates an interrupt request. ;1 1 The rising edge of INT0 generates an interrupt request. ; 76543210 ldi a,0b00000001 ;Any logical change on INT0 generates an interrupt request. 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 ; 76543210 ldi a,0b01000000 ;INT0 enable out GICR,a ;------------------------------------------------------------------------ initvar: ldi Flags1,0b00000000 clr n_pas rcall STOP ;chargement du registre de comparaison (A) du Timer1 ; cli ; ldi r20,LOW(59) ;588 ; ldi r21,HIGH(59) ;588 ; out OCR1AH,r21 ; out OCR1AL,r20 ; sei ;Sets the Global Interrupt flag (I) in SREG (status register) ;------------------------------------------------------------------------ ;zone de tests de procedures ;------------------------------------------------------------------------ ;PROGRAMME PRINCIPAL ;------------------------------------------------------------------------ sei ;Sets the Global Interrupt flag (I) in SREG (status register) rcall demarre ;------------------------------------------------------------------------ ;BOUCLE PRINCIPALE bcl0: nop rcall tp1ms rjmp bcl0 ;------------------------------------------------------------------------ ;ROUTINES ;------------------------------------------------------------------------ STOP: cli clr a out pinc,a ret ;------------------------------------------------------------------------ pasMoteur:inc n_pas mov a,n_pas cpi a,6 brlo int0b clr n_pas int0b: mov a,n_pas rcall lire_Ph out portc,a ret ;------------------------------------------------------------------------ demarre: cli ldi AA,20 ;2 dema1: ldi BB,10 ;8 dema2: rcall pasMoteur ldi a,1 ;2 add a,AA rcall tx1ms ;delai proportionnel à AA +2 donc qui décroit avec AA -> f augmente dec BB brne dema2 ;boucle intérieure courte, BB fois dec AA brne dema1 ;boucle extérieure, AA fois cli rcall STOP ;moteur en roue libre ldi a,10 rcall tx1ms sei ;re-autorie les INTs ret ;------------------------------------------------------------------------ ;tableau des valeurs des bits de commande des phases (en memoire de programme) ;'a' doit contenir la position dans le tableau (0..7) ;la routine retourne la valeur lue dans 'a' lire_Ph: ldi ZH, high(Table_1<<1);Initialize Z pointer (le shift gauche because le LSB est reserve. voir doc) ldi ZL, low(Table_1<<1) andi ZL,0b11111110 ;RAZ LSB pour acceder aux octets de poids faible lsl a ;shift gauche aussi add ZL,a ;decallage dans le tableau (voir plus bas) clr a adc ZH,a lpm a, Z ;Load constant from program ret Table_1: .DB 0b00000110 ;phase 0 .DB 0b00100100 ;phase 1 .DB 0b00100001 ;phase 2 .DB 0b00001001 ;phase 3 .DB 0b00011000 ;phase 4 .DB 0b00010010 ;phase 5 ;------------------------------------------------------------------------ EE_write: cli ;stop INT sbic EECR,EEWE rjmp EE_write ; Wait for completion of previous write out EEARH, r18; Set up address (r18:r17) in address register out EEARL, r17 out EEDR,a ; Write data (r16) to data register sbi EECR,EEMWE; Write logical one to EEMWE sbi EECR,EEWE ; Start eeprom write by setting EEWE sei ;INT ON ret ;------------------------------------------------------------------------ EE_read: sbic EECR,EEWE rjmp EE_read ; Wait for completion of previous write out EEARH, r18; Set up address (r18:r17) in address register out EEARL, r17 sbi EECR,EERE ; Start eeprom read by writing EERE in a,EEDR ; Read data from data register ret ;---------------------------------------------------------------------- ;ADDITION de registres sur 3 octets ;r20,21,22:= r20,21,22 + r0,r1,r2 add24r: add r20,r0 adc r21,r1 adc r22,r2 ret ;---------------------------------------------------------------------- ;ADDITION sur 3 octets (1) ;r20,21,22:= r20,21,22 + nombre1 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:= nombre1 +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 brne bcl3 nop ;pour ajuster exactement la duree nop nop dec i1 brne bcl2 nop pop r20 pop r21 ret ;---------------------------------------------------------------------- ;tempo a * 1ms tx1ms: push r16 .def n=r16 mov n,a bcl7: rcall tp1ms dec n brne bcl7 pop r16 ret ;---------------------------------------------------------------------- ;tempo a * 100ms ;a qui contient le nb de fois 100ms est affecte .def n=r16 tx100ms: push r16 ldi n,100 bcl6: rcall tp1ms dec n brne bcl6 pop r16 dec a brne tx100ms ret ;----------------------------------------------------------------------