Pfad: Home => AVR-Übersicht => Anwendungen => Steppermotor-Steuerung => Quellcode
Schrittmotor-Steuerung klein

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