Pfad:
Home =>
AVR-Übersicht =>
Anwendungen =>
Steppermotor-Steuerung => Quellcode
(This page in English:
)
Quellcode der Schrittmotor-Steuerung mit ATtiny13
; ***************************************************
; * Schrittmotor-Steuerung mit ATtiny13 - Version 1 *
; * (C)2007 by http://www.avr-asm-tutorial.net *
; ***************************************************
;
; Debugging switches
;
.equ debug_calc = 0
.equ debug_const = 0
.equ debug_out = 0
;
.nolist
.include "tn13def.inc"
.list ; ______
; / |
; Hardware: | |
; _______ . . +12V schwarz
; ___ / | | | ___ |
; +5V-|___|--|RES VCC|--+5V B3-|I4 O4|-|___|-+Q4 rot
; | | | | ___ |
; B3--|PB3 PB2|---------|I5 O5|-|___|-+Q2 braun
; | | | | ___ |
; Analog-In--|PB4 PB1|---------|I6 O6|-|___|-+Q3 gruen
; | | | | ___ |
; |--|GND PB0|---------|I7 O7|-|___|-+Q1 weiss
; |________| | | |
; ATtiny13 |-|GND CD|-------+
; |_______|
; ULN2003
;
; Funktionsweise:
; Ein Schrittmotor wird mit einer analogen Eingangs-
; spannung an Pin 3 gesteuert. Die Eingangsspannung
; liegt zwischen Null und der Betriebsspannung. Die
; Anzahl Einzelschritte des Motor fuer Vollausschlag
; sind mit der Konstanten cSmSteps einstellbar (1...
; 65535 Schritte).
; Ansteuerung Schrittmotor:
; Portbit PB0 PB2 PB1 PB3 | |
; Farbe ws bn gn rt | Port | Byte
; Schritt Q4 Q3 Q2 Q1 | 3 2 1 0 |
; ------------------------+---------+------
; 1 1 1 0 0 | 0 1 0 1 | 05
; 2 0 1 1 0 | 0 1 1 0 | 06
; 3 0 0 1 1 | 1 0 1 0 | 0A
; 4 1 0 0 1 | 1 0 0 1 | 09
; entspricht: .dw 0x0605,0x090A
;
; Timer TC0:
; Timer läuft bei einem Prozessortakt von 1,2 MHz mit
; einem Vorteiler von 1024 im CTC-Modus mit CompareA
; als TOP-Wert. Interrupt bei CompareA bzw. beim
; CTC-Reset.
; Bei CompareA wird der Soll- und Ist-Wert des
; Schrittmotors verglichen. Ist der Ist-Wert zu
; hoch, wird ein Schritt zurueck gefahren, ist
; der Ist-Wert zu niedrig, wird ein Schritt vor-
; waerts gefahren. Stimmen Soll- und Ist-Wert
; ueberein, werden nach einer einstellbaren Verzoe-
; gerung die Magnete des Schrittmotor abgeschaltet
; Timing: 1,2 MHz / 1024 / CompA,
; bei CompA = 255: f(Schrittmotor) = 4,57 Hz
; bei CompA = 8 : f(Schrittmotor) = 146 Hz
; ADC:
; Umwandlung der an Pin 3 / PB4 /ADC2 anliegenden
; Analogspannung, Aufsummieren von 64 Messungen
; zur Mittelung, Umrechnung in die Sollstellung
; des Schrittmotors
; Timing: 1,2 MHz / 128 = 9,375 kHz = 106,7 us
; Conversion = 13 cycles = 1,387 ms / Konversion
; = 721 Konversionen pro Sekunde
; Mittelung ueber 64 Konversionen = 88,75 ms = 11,3 / s
;
; Konstanten
;
.equ cSmSteps = 1276 ; 2552/2, Anzahl Schritte pro Umdrehung
.equ cSmFreq = 145 ; Frequenz Schrittmotorgeschwindigkeit
; ; Minimum: 5 Hz, Maximum: 1171 Hz
.equ cSmDelay = 390 ; Anzahl Takte vor Abschalten der Magnete
;
; Abgeleitete Konstanten
;
.equ clock = 1200000 ; Taktfrequenz Tiny13
.equ Tc0Ctc = 1024 ; Vorteiler TC0
.equ cCmpA = clock / 1024 / cSmFreq
;
; Ueberpruefung der Konstanten
;
.IF cCmpA > 255
.ERROR "Schrittmotor zu langsam!"
.ENDIF
.IF cCmpA < 1
.ERROR "Schrittmotor zu schnell!"
.ENDIF
;
; SRAM
;
; Register
;
; benutzt: R0 fuer Tabellenlesen
; benutzt: R8:R1 fuer Rechnen
; frei: R10:R8
.def rAdcCL = R11 ; ADC Rechenwert LSB
.def rAdcCH = R12 ; dto., MSB
.def rAdcRL = R13 ; ADC Uebergabe LSB
.def rAdcRH = R14 ; dto., MSB
.def rSreg = R15 ; Status Sicherungs-Register
.def rmp = R16 ; Multipurpose outside Int
.def rimp = R17 ; Multipurpose inside Int
.def rFlg = R18 ; Flaggen
.equ bAdc = 0 ; Adc conversion complete flag
.def rAdcC = R19 ; ADC Zaehler (64 Adc-Werte)
.def rAdcL = R20 ; ADC Addier-Register LSB
.def rAdcH = R21 ; dto., MSB
.def rSmSL = R22 ; Stepmotor-Sollwert LSB
.def rSmSH = R23 ; dto., MSB
.def rSmIL = R24 ; Stepmotor-Istwert LSB
.def rSmIH = R25 ; dto., MSB
; benutzt: X fuer Nachlauf der Magnete
; frei: Y
; benutzt: Z fuer Tabellenwert-Zugriff
;
; **********************************
; Code Segment Start, Int - Vektor
; **********************************
;
.cseg
.org $0000
;
rjmp Main ; Reset Vektor
reti ; INT0 Vektor
reti ; PCINT0 Vektor
reti ; TIM0_OVF Vektor
reti ; EE_RDY Vektor
reti ; ANA_COMP Vektor
rjmp Tc0IntCA ; TIM0_COMPA Vektor
reti ; TIM0_COMPB Vektor
reti ; WDT Vektor
rjmp AdcInt ; ADC Vektor
;
; **********************************
; Interrupt Service Routinen
; **********************************
;
; Timer-Counter 0 Compare A Interrupt Service Routine
;
Tc0IntCA:
in rSreg,SREG ; rette Status
cp rSmIL,rSmSL ; vergleiche Ist mit Soll
cpc rSmIH,rSmSH
breq Tc0IntCA0
brcs Tc0IntCAF ; Ist < Soll
sbiw rSmIL,1 ; Ist > Soll, ein Schritt rueckwaerts
rjmp Tc0IntCAS
Tc0IntCAF:
adiw rSmIL,1 ; ein Schritt vorwaerts
Tc0IntCAS:
mov rimp,rSmIL ; kopiere Zaehlerstand
andi rimp,0x03 ; isoliere unterste zwei Bits
ldi ZH,HIGH(2*SmTab) ; Zeige auf Tabelle
ldi ZL,LOW(2*SmTab)
add ZL,rimp
ldi rimp,0
adc ZH,rimp
lpm ; lese Wert aus Tabelle
.IF debug_out == 0
out PORTB,R0 ; schreibe auf Port
.ENDIF
ldi XH,HIGH(cSmDelay) ; Delay-Zaehler-Restart
ldi XL,LOW(cSmDelay)
out SREG,rSreg ; Stelle Status wieder her
reti
Tc0IntCA0:
sbiw XL,1 ; Delay-Zaehler verringern
brne Tc0IntCAD ; noch nicht Null
ldi rimp,0 ; Magnete ausschalten
out PORTB,rimp ; an Ausgangstreiber
ldi XH,HIGH(cSmDelay) ; Delay-Zaehler-Restart
ldi XL,LOW(cSmDelay)
Tc0IntCAD:
out SREG,rSreg ; stelle Status wieder her
reti
;
SmTab:
.dw 0x0605,0x090A
;
; Adc Conversion Complete Interrupt Service Routine
;
AdcInt:
in rSreg,SREG ; rette Status
in rimp,ADCL ; lese LSB Ergebnis
add rAdcL,rimp ; addiere zum Ergebnis
in rimp,ADCH ; lese MSB Ergebnis
adc rAdcH,rimp ; addiere zum Ergebnis
dec rAdcC ; Erniedrige Zaehler
brne AdcInt1
mov rAdcRL,rAdcL ; Kopiere Ergebnis
mov rAdcRH,rAdcH
clr rAdcH ; Loesche Summe
clr rAdcL
ldi rAdcC,64 ; Setze Zaehler neu
sbr rFlg,1<<bAdc ; Setze Flagge
AdcInt1:
ldi rmp,(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)
out ADCSRA,rmp
out SREG,rSreg ; stelle Status wieder her
reti
;
; **********************************
; Hauptprogramm Init und Loop
; **********************************
;
Main:
; Stack Init
ldi rmp, LOW(RAMEND)
out SPL,rmp
; Init Register
clr rFlg ; Flag-Register auf Null
clr rSmIL ; Ist-Zaehler Stepmotor auf Null
clr rSmIH
clr rSmSL ; Soll-Wert Stepmotor auf Null
clr rSmSH
ldi XH,HIGH(cSmDelay) ; Delay-Zaehler-Restart
ldi XL,LOW(cSmDelay)
; Init Output-Port
ldi rmp,0x0F ; Ausgabe auf Port 0 is 3
out DDRB,rmp
ldi rmp,0x05 ; Schrittmotor auf Schritt 1 setzen
out PORTB,rmp
; Debugging session
.IF debug_calc
.equ adc_result = 128
ldi rmp,HIGH(adc_result)
mov rAdcRH,rmp
ldi rmp,LOW(adc_result)
mov rAdcRL,rmp
rjmp dcalc
.ENDIF
.IF debug_const
.equ const = cMSteps
ldi rmp,HIGH(const)
mov rSmSH,rmp
ldi rmp,LOW(const)
mov rSmSL,rmp
.ENDIF
; Init ADC
ldi rAdcC,64 ; Setze Zaehler neu
clr rAdcL ; Setze Ergebnis auf Null
clr rAdcH
ldi rmp,1<<ADC2D ; Digital Input Disable
out DIDR0,rmp
ldi rmp,1<<MUX1 ; ADC auf Kanal 2
out ADMUX,rmp
ldi rmp,(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)
out ADCSRA,rmp
; TC0 initiieren
ldi rmp,cCmpA ; CTC-Wert setzen
out OCR0A,rmp
ldi rmp,1<<WGM01 ; CTC-Mode
out TCCR0A,rmp
ldi rmp,(1<<CS02)|(1<<CS00) ; Prescaler = 1024
out TCCR0B,rmp
ldi rmp,1<<OCIE0A ; Interrupt Compare Match A enable
out TIMSK0,rmp
; Sleep Mode und Int Enable
ldi rmp,1<<SE ; Schlafen Enable
out MCUCR,rmp
sei ; Int Enable
Loop:
sleep ; schlafen
nop ; Dummy fuer Aufwachen
sbrc rFlg,bAdc ; ADC-Flagge?
rcall AdcRdy ; wandle ADC-Ergebnis um
rjmp Loop
;
; **********************************
; Rechenroutinen
; **********************************
;
; ADC Umwandlungs-Egebnis fertig
;
AdcRdy:
cbr rFlg,1<<bAdc ; setze Flagge zurueck
.IF debug_const
ret
.ENDIF
dcalc:
mov rAdcCH,rAdcRH ; kopiere Messwert
mov rAdcCL,rAdcRL
ldi rmp,LOW(cSmSteps) ; Anzahl Schritte in R4:R3:R2:R1
mov R1,rmp
ldi rmp,HIGH(cSmSteps)
mov R2,rmp
clr R3
clr R4
clr R5 ; Ergebnis in R8:R7:R6:R5 loeschen
clr R6
clr R7
clr R8
AdcRdy1:
lsr rAdcCH ; ein Bit herausschieben
ror rAdcCL
brcc AdcRdy2 ; nicht addieren
add R5,R1 ; addieren
adc R6,R2
adc R7,R3
adc R8,R4
AdcRdy2:
lsl R1 ; Multiplikator mal zwei
rol R2
rol R3
rol R4
mov rmp,rAdcCL ; = Null?
or rmp,rAdcCH
brne AdcRdy1 ; weiter multiplizieren
ldi rmp,0x80 ; aufrunden
add R5,rmp
adc R6,rmp
ldi rmp,0
adc R7,rmp
adc R8,rmp
cli ; Interrupts aus
mov rSmSL,R7 ; Stepmotor-Sollwert LSB
mov rSmSH,R8 ; dto., setze MSB
.IF debug_out
out PORTB,rSmSL
.ENDIF
sei ; Interrupts wieder an
ret
;
; Ende Source Code
;
©2007 by http://www.avr-asm-tutorial.net