;=======================================================================
; VARIATEUR pour moteur BRUSHLESS a 3 fils : variat4.asm
; pour ATMEGA8 et Qx=16,000 Mhz
;derniere mise a jour: 22/05/2006
; Version: 1.00
; Auteur: Silicium628
;=======================================================================
;Cette realisation fait suite a celle utilisant un PIC16F628
;=======================================================================
;PRINCIPE
;=======================================================================
;LISTE DES PARTIES:
;Declaration des Variables
;MACROS
;Declaration 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 references des registres (ATMEGA 8)
;------------------------------------------------------------------------
;Declaration 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
;------------------------------------------------------------------------
;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
;------------------------------------------------------------------------
;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 a
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 a AA +2 donc qui decroit avec AA -> f augmente
dec BB
brne dema2 ;boucle interieure courte, BB fois
dec AA
brne dema1 ;boucle exterieure, 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' 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
;----------------------------------------------------------------------