; *************************************************** ; * 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 laeuft 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<