Pfad: Home => AVR-DE => Anwendungen => ATtiny24-Schrittmotorsteuerung => Quellcode   This page in English: Flag EN Logo
stepper_tn24 Klein Anwendungen von
AVR-Einchip-Prozessoren AT90S, ATtiny, ATmega und ATxmega
Schrittmotorsteuerung mit einem ATtiny24

Software für die Schrittmotorsteuerung 28BYJ-48 mit einem ATtiny24

Assembler-Quellcode (als asm-Quellcode hier)

;
; *************************************
; * Schrittmotorsteuerung ATtiny24    *
; * 16-Bit-Position, Voll/Halbschritt *
; * Version 1, Maerz 2018, V1         *
; * (C)2018 by avr-asm-tutorial.net   *
; *************************************
;
.nolist
.include "tn24adef.inc" ; Define device ATtiny24A
.list
;
; **********************************
;    M O D U S - S C H A L T E R
; **********************************
;
.equ Halfstep = 0 ; 1=Halbschritt, 0=Vollschritt
;
; **********************************
;    D E B U G - S C H A L T E R
; **********************************
;
; Debug ausschalten: alle Schalter auf 0
;
; Teste ADC-Wert-Umrechnung
.equ TestAdc = 0 ; Teste Berechnung Kanal 2
  .equ TestChannel=2 ; Channel zu Simulieren
  .equ TestValue = 255*256
;
; Teste Ausgabe Motor
.equ TestMotor = 0 ; Teste Motorstellung
  .equ TestCurr = 32768 ; aktuelle Stellung
  .equ TestNext = 32767 ; naechste Stellung
;
;        H A R D W A R E
; **********************************
;
; Device: ATtiny24, Package: 14-pin-PDIP_SOIC
;               _________
;            1 /         |14
;      +Ub o--|VCC    GND|--o -Ub
;            2|          |13
; Duo AnRt o--|PB0   ADC0|--o Poti ZU
;            3|          |12
; LED AnGe o--|PB1   ADC1|--o Poti AUF
;            4|          |11
;    RESET o--|RES   ADC2|--o Poti Speed
;            5|          |10
; Schalter o--|PB2    PA3|--o LED Ka Gn
;            6|          |9
;  ULN IN7 o--|PA7    PA4|--o ULN IN4
;            7|          |8
;  ULN IN6 o--|PA6    PA5|--o ULN IN5
;             |__________|
;
; **********************************
;  P O R T S   A N D   P I N S
; **********************************
; Duo-LED-Ansteuerung
.equ pDuoO = PORTB ; Duo-LED-Ausgabeport
.equ pDuoD = DDRB ; Duo-LED-Richtungsport
.equ bDuoAR = PORTB0 ; Rote Anode Portbit
.equ bDuoAY = PORTB1 ; Gelbe Anode Portbit
; Schaltersteuerung
.equ pSwO = PORTB ; Schalter-Ausgabeport
.equ pSwD = DDRB ; Schalter-Richtungsport
.equ pSwI = PINB ; Schalter-Eingabeport
.equ bSwO = PORTB2 ; Schalter-Ausgabepin
.equ bSwD = DDB2 ; Schalter-Richtungspin
.equ bSwI = PINB2 ; Schalter-Eingabepin
; Bereit-LED
.equ pOkO = PORTA ; Bereit-LED-Ausgabeport
.equ pOkD = DDRA ; Bereit-LED-Richtungsport
.equ pOkI = PINA ; Eingabeport
.equ bOkO = PORTA3 ; Bereit-LED-Ausgabepin
.equ bOkD = DDA3 ; Bereit-LED-Richtungspin
.equ bOkI = PINA3 ; Lese-Pin
; Schrittmotor
.equ pStpO = PORTA ; Schrittmotor-Ausgabeport
.equ pStpD = DDRA ; Schrittmotor-Richtungsport
.equ mStpD = 0xF0 ; Maske Schrittmotor-Richtung
;
; **********************************
;   A D J U S T A B L E   C O N S T
; **********************************
;
; Taktgenerator Default (CLKDIV8 gesetzt)
.equ clock=1000000 ; Define clock frequency
;
; Grad maximaler Drehwinkel =
; maximale Getriebewinkel-Aussteuerung):
.equ cAngleMax = 180 ; Grad maximaler Drehwinkel
;
; Startgeschwindigkeit, Default
; bis zur ersten Potentiometermessung
.equ cSecOpenClose = 20 ; 20 Sekunden
;
; Zeit nach letzter Bewegung bis Motor stromlos
;   Minimum: 1 (1 ms), Maximum: 6710 (6,71 s)
.equ cMotOffms = 1000 ; Millisekunden bis Motor aus
;
; **********************************
;  F I X  &  D E R I V.  C O N S T
; **********************************
;
; Motor mit Getriebe 1:64
; Schritte pro Umdrehung Motor 64
; Schritte pro Getriebeumdrehung:
.equ cStepsRound = 64 * 64
; Mittenstellung:
.equ cMiddle = 32768
; Schritte pro Maximalwinkeldrehung:
.equ cStepsAngle = (cStepsRound*cAngleMax+180)/ 360
; Schritte pro halber Maximalwinkeldrehung
; (von Mitte aus nach oben bzw. unten):
.equ cStepsUpDown = (cStepsAngle+1) / 2
;
; Berechnung der Startgeschwindigkeit
.equ cTC0Presc = 64 ; Vorteiler TC0
; TC0Ticks in Mikrosekunden:
.equ cTC0Tick = (1000000*cTC0Presc)/clock
; Dauer in Mikrosekunden fuer volles Oeffnen/
; Schliessen ueber den Maximalwinkel
.equ cUsSwing = (1000000*cSecOpenClose)/cStepsAngle
; CTC-Wert fuer 8-Bit-TC0
.equ cCTCDef = (cUsSwing+cTC0Tick/2)/cTC0Tick
;
; CTC-Wert fuer 16-Bit-TC1 Motor aus
.equ cMotOff = (1000*cMotOffms+512)/1024-1
;
; **********************************
;          T I M I N G
; **********************************
;
; TC0 ist Schrittmotor-Ansteuerung
;   laeuft im CTC-Modus mit Compare A
;   clock               = 1.000.000 Hz
;   Vorteiler           =        64
;   Timer-Tick          =        64 us
; Vollschrittverfahren:
;   Schritte 180 Grad   =     1.024
;   Langsame Bewegung   =        16,78 s
;     Zeit pro Schritt  =    16.384 us
;     CTC-Ticks         =       256
;     Compare-A-Wert    =       255
;   Schnelle Bewegung   =         2,03 s
;     Zeit pro Schritt  =     1.984 us
;     CTC-Ticks         =        31
;     Compare-A-Wert    =        30
;   Berechnung aus MSB ADC-Summe ADC2:
;     Compare A = (ADC-MSB * 225)/256+30
; Halbschrittverfahren:
;   Schritte 180 Grad   =     2.048
;   Langsame Bewegung   =        17,7 s
;     Zeit pro Schritt  =    16.384 us
;     CTC-Ticks         =       135
;     Compare-A-Wert    =       134
;   Schnelle Bewegung   =         1,97 s
;     Zeit pro Schritt  =       960 us
;     CTC-Ticks         =        15
;     Compare-A-Wert    =        14
;   Berechnung aus MSB ADC-Summe ADC2:
;     Compare A = (ADC-MSB * 241)/256+14
;
; TC1 ist Motor-Aus-Schalter
;   laeuft im Normalmodus mit Compare A
;   Clock               = 1.000.000 Hz
;   Vorteiler           =     1.024
;   Timer-Tick          =     1.024 us
;   Maximum bis Ueberl. =    65.536
;   Entspricht Zeit     =         6,7 s
;   Eingestellt auf     =         1 s
;
; AD-Wandler misst Potistellungen 1, 2 und 3
;   Clock               = 1.000.000 Hz
;   Vorteiler           =       128
;   ADC-Tick            =       128 us
;   Wandlertakte/Messung=        14
;   Zeit pro Messung    =     1.792 us
;   64 Messungen        =   114.688 us
;   Drei Kanaele        =   344.064 us
;   Messungen pro Sek.  =         2,9
;
; **********************************
;       R E G I S T E R S
; **********************************
;
; R0, R1, R2, R3 benutzt fuer Multiplikationen etc.
; free: R4
; ADC-Werte-Summierung
.def rAdcL = R5 ; Summe ADC-Wert, LSB
.def rAdcH = R6 ; dto., MSB
; Registerwerte fuer Schrittmotorstellung
  .equ cStepSetS = 7 ; fuer Lesen/Schreiben EEPROM
.def rMark1 = R7
.def rCloseL = R8
.def rCloseH = R9
.def rOpenL = R10
.def rOpenH = R11
.def rCurrValL = R12
.def rCurrValH = R13
.def rMark2 = R14
  .equ cStepSetE = 15 ; Ende des Datensets
.def rSreg = R15 ; Save/Restore status port
.def rmp = R16 ; Define multipurpose register
.def rimp = R17 ; Multipurpose Interrupts
.def rFlag = R18 ; Flaggen
  .equ bWrite = 0 ; Datenset in EEPROM schreiben
  .equ bAdc = 1 ; 64 Messwerte sind aufsummiert
.def rAdc = R19 ; ADC-Summierungszaehler
.def rSetValL = R20 ; Sollwert, LSB
.def rSetValH = R21 ; Sollwert, MSB
; free: R22 to R29
; used: R27:R26 = X Zeiger ausserhalb Interrupts
; used: R29:R28 = Y Zeiger fuer EEPROM-Schreiben
; used: R31:R30 = Z Zeiger Vielzweck, fuer LPM
;
; **********************************
;           S R A M
; **********************************
;
.dseg
.org SRAM_START
; (Nicht benutzt, nur fuer den Stapel)
;
; **********************************
;         C O D E
; **********************************
;
.cseg
.org 000000
;
; **********************************
; R E S E T  &  I N T - V E C T O R S
; **********************************
	rjmp Main ; Reset vector
	rjmp Int0Isr ; EXT_INT0
	reti ; PCI0
	reti ; PCI1
	reti ; WATCHDOG
	reti ; ICP1
	rjmp OC1AIsr ; OC1A
	reti ; OC1B
	reti ; OVF1
	rjmp OC0AIsr ; OC0A
	reti ; OC0B
	reti ; OVF0
	reti ; ACI
	rjmp AdcIsr ; ADCC
	rjmp EepIsr ; ERDY
	reti ; USI_STR
	reti ; USI_OVF
;
; **********************************
;  I N T - S E R V I C E   R O U T .
; **********************************
;
; INT0 Interrupt Service Routine
;   Schalter-Aktionen loesen INT0 aus
;   bei steigenden und fallenden Flanken
Int0Isr:
  set ; Update-Flagge fuer Sollwert
  reti
;
; OC0A Interrupt Service Routine
;   bedient Schrittmotor
OC0AIsr:  in rSreg,SREG ; rette SREG
  cp rCurrValL,rSetValL ; LSB rIst = rSoll?
  brne OC0AIsr1 ; LSB ungleich
  cp rCurrValH,rSetValH
  breq OC0AIsr8 ; gleich, tue nichts
  cp rCurrValL,rSetValL ; LSB-Vergleichen
OC0AIsr1:
  ; rIst ungleich rSoll, Motorbewegung
  cpc rCurrValH,rSetValH ; MSB testen
  brcs OC0AIsr4 ; rIst kleiner rSoll
  tst rCurrValL ; Pruefe auf Null
  brne OC0AIsr2 ; LSB nicht Null
  dec rCurrValH ; MSB eins abwaerts
OC0AIsr2:
  dec rCurrValL ; Ein Schritt zurueck
  sbi pDuoO,bDuoAY ; gelbe LED an
  cp rCurrValL,rSetValL
  breq OC0AIsr3 ; nicht gelb blinken
  sbrc rCurrValL,3
  cbi pDuoO,bDuoAY ; gelbe LED blinkt
OC0AIsr3:
  cbi pDuoO,bDuoAR ; Kathode gelbe LED Low
  rjmp OC0AIsr7 ; Schrittmotor verstellen
  ; rIst kleiner rSoll
OC0AIsr4:
  inc rCurrValL ; Ein Schritt vorwaerts
  brne OC0AIsr5 ; LSB nicht Null
  inc rCurrValH ; MSB erhoehen
OC0AIsr5:
  sbi pDuoO,bDuoAR ; rote LED an
  cp rCurrValL,rSetValL
  breq OC0AIsr6 ; nicht rot blinken
  sbrc rCurrValL,3
  cbi pDuoO,bDuoAR ; rote LED blinken
OC0AIsr6:
  cbi pDuoO,bDuoAY ; Kathode rote LED Low
OC0AIsr7:
  push ZH ; rette Z
  push ZL
  mov rimp,rCurrValL ; Ist-Wert kopieren
.if Halfstep == 1
  ldi ZH,High(2*StepTab8) ; Z auf 8-Step-Tabelle
  ldi ZL,Low(2*StepTab8)
  andi rimp,0x07 ; die untersten drei Bit
  .else
  ldi ZH,High(2*StepTab4) ; Z auf 4-Step-Tabelle
  ldi ZL,Low(2*StepTab4)
  andi rimp,0x03 ; die untersten zwei Bit
  .endif
  add ZL,rimp ; zur Tabellenadresse addieren
  ldi rimp,0
  adc ZH,rimp
  lpm rimp,Z ; Tabellenbyte lesen
  in ZL,pStpO ; Port lesen
  andi ZL,0x0F ; unterste drei Bit erhalten
  or ZL,rimp ; Motor- und Bereit-Led-Bits setzen
  out pStpO,ZL ; an Stepmotorausgang, Bereit-LED aus
  pop ZL ; stelle Z wieder her
  pop ZH
  clr rimp ; Motor-Aus-Zaehler neu starten
  out TCNT1H,rimp
  out TCNT1L,rimp
OC0AIsr8:
  out SREG,rSreg ; stelle SREG wieder her
  reti
;
.if Halfstep == 1
  ; Schrittfolge-Tabelle Halbschrittmodus
  StepTab8:
  .db 0x18,0x38,0x28,0x68,0x48,0xC8,0x88,0x98
  .else
  ; Schrittfolge-Tabelle Vollschrittmodus
  StepTab4:
  .db 0x18,0x28,0x48,0x88
  .endif
;
; OC1A-ISR schaltet Motormagnete aus
;
OC1AIsr:
  in rSreg,SREG ; SREG sichern
  sbic pOkO,bOkO ; gruene LED schon an? Wenn nicht...
  sbr rFlag,1<<bWrite ; Schreibe Position ins EEP
  in rimp,pStpO ; Lese Motor-Port Output
  andi rimp,0x07 ; Untere drei Bits erhalten
  out pStpO,rimp ; Motor aus, gruene LED an
  cbi pDuoO,bDuoAR ; rote/gelbe LED aus
  cbi pDuoO,bDuoAY
  out SREG,rSreg ; SREG wieder herstellen
  reti
;
; ADC complete Interrupt
AdcIsr:
  in rSreg,SREG ; rette Status
  in rimp,ADCL ; Lese LSB Ergebnis
  add rAdcL,rimp ; addiere zur Summe
  in rimp,ADCH ; lese MSB Ergebnis
  adc rAdcH,rimp
  dec rAdc ; Zaehler abwaerts
  brne AdcIsr1 ; noch nicht 64 Werte
  sbr rFlag,1<<bAdc ; setze Flagge
  rjmp AdcIsr2 ; nicht neu starten
AdcIsr1:
  ldi rimp,(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)
  out ADCSRA,rimp
AdcIsr2:
  out SREG,rSreg ; stelle Status wieder her
  reti
;
; EEPROM Interrupt
EepIsr:
  in rSreg,SREG ; SREG retten
  in rimp,EEARL ; Lese LSB Adresse
  inc rimp ; naechste Adresse
  out EEARL,rimp
  ld rimp,Y+ ; Lese naechstes Byte
  out EEDR,rimp
  sbi EECR, EEMPE ; EEPROM-Schreiben starten
  sbi EECR, EEPE
  cpi YL,cStepSetE ; Letztes Byte?
  brcs EepIsr1
  cbi EECR,EERIE ; Keine Interrupts mehr
  cbr rFlag,1<<bWrite ; Schreibflagge loeschen
EepIsr1:
  out SREG,rSreg ; SREG wieder herstellen
  reti
;
; **********************************
;  M A I N   P R O G R A M   I N I T
; **********************************
;
Main:
  ldi rmp,Low(RAMEND)
  out SPL,rmp ; Init LSB stack pointer
;
; Debugschalter auswerten
.if TestAdc == 1
  ; Teste Berechnung ADC
  ldi rmp,High(TestValue)
  mov rAdcH,rmp
  ldi rmp,Low(TestValue)
  mov rAdcL,rmp
  ldi rmp,TestChannel
  out ADMUX,rmp
  rcall AdcFlag
  TestAdcLoop:
  rjmp TestAdcLoop
  .endif
.if TestMotor == 1 ; Teste Motorstellung
  ldi rmp,High(TestCurr) ; aktuelle Stellung
  mov rCurrValH,rmp
  ldi rmp,Low(TestCurr)
  mov rCurrValL,rmp
  ldi rmp,High(TestNext)
  mov rSetValH,rmp
  ldi rmp,Low(TestNext)
  mov rSetValL,rmp
  TestMotorLoop:
    rcall OC0AIsr
    rjmp TestMotorLoop
  .endif
  ;
  ; Neujustierung?
  cbi pOkD,bOkD
  sbi pOkO,bOkO ; Pull-up einschalten
  sbic pOkI,bOkI ; Pin auf Null?
  rjmp LeseEeprom ; Nein
  ldi rmp,High(32768)
  mov rSetValH,rmp
  mov rCurrValH,rmp
  mov rOpenH,rmp
  mov rCloseH,rmp
  ldi rmp,Low(32768)
  mov rSetValL,rmp
  mov rCurrValL,rmp
  mov rOpenL,rmp
  mov rCloseL,rmp
  sbr rFlag,1<<bWrite
WaitRestart:
  ldi ZH,High(16667) ; 100 ms warten
  ldi ZL,Low(16667)
WaitInactive:
  sbis pOkI,bOkI ; Ueberspringe wenn Pin high
  rjmp WaitRestart ; Pin ist auf Null
  sbiw ZL,1 ; Abwaerts zaehlen
  brne WaitInactive ; Noch nicht 100 ms
  rjmp NoEpromRead ; Fertig gewartet
  ; Lese EEPROM-Inhalt
LeseEeprom:
  rcall ReadEep ; Lese den Datenset im EEPROM
NoEpromRead:
  ; Init Duo-LED
  sbi pDuoD,bDuoAR ; Richtung rote Anode Ausgang
  sbi pDuoD,bDuoAY ; Richtung gelbe Anode Ausgang
  cbi pDuoO,bDuoAR ; rote Anode auf Low
  cbi pDuoO,bDuoAY ; gelbe Anode auf Low
  ; Init Bereit-LED
  sbi pOkD,bOkD ; Bereit-LED Richtung Ausgang
  sbi pOkO,bOkO ; Bereit-LED aus
  ; Init Schalter
  cbi pSwD,bSwD ; Schalter Richtung auf Input
  sbi pSwO,bSwO ; Schalter Pull-Up An
  ; Init AD-Wandler
  clr rmp ; Mit Kanal 0 beginnen, URef=UB
  out ADMUX,rmp
  ldi rAdc,64 ; 64 Messungen
  ldi rmp,(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)
  out ADCSRA,rmp ; Starte erste Wandlung mit Interrupts
  ; Init Schrittmotor
  ; Schrittmotor
  ; .equ pStpO = PORTA ; Schrittmotor-Ausgabeport
  ; .equ pStpD = DDRA ; Schrittmotor-Richtungsport
  ; .equ mStpD = 0xF0 ; Maske Schrittmotor-Richtung
  in rmp,pStpO ; Output-Port lesen
  andi rmp,0x0F ; Unterste Bits erhalten, oberste = Null
  out pStpO,rmp ; in Output-Port schreiben
  in rmp,pStpD ; Richtungsregister lesen
  ori rmp,mStpD ; mit Richtungsmaske odern
  out pStpD,rmp ; Richtung Ausgang
  ; Init TC1 als Motormagnet-Abschaltung bei inaktiv
  ldi rmp,High(cMotOff) ; Zeit bis Abschaltung
  out OCR1AH,rmp
  ldi rmp,Low(cMotOff)
  out OCR1AL,rmp
  clr rmp ; Normal Mode
  out TCCR1A,rmp
  ldi rmp,(1<<CS12)|(1<<CS10) ; Prescaler=1024
  out TCCR1B,rmp
  ldi rmp,1<<OCIE1A ; Compare Match A Interrupt
  out TIMSK1,rmp
  ; Init TC0 als Schrittmotor-Steuerung
  ldi rmp,cCtcDef ; niedrige Anfangsgeschwindigkeit
  out OCR0A,rmp ; CTC-Wert setzen
  ldi rmp,1<<WGM01 ; No OC output, WGM01 fuer CTC
  out TCCR0A,rmp
  ldi rmp,(1<<CS01)|(1<<CS00) ; CTC, Presc=64
  out TCCR0B,rmp
  ldi rmp,1<<OCIE0A ; Compare Match A Interrupt
  out TIMSK0,rmp
  ; Sleep, externe ints und int enable
  ldi rmp,(1<<ISC00)|(1<<SE) ; Externer INT0, Schlafmodus
  out MCUCR,rmp
  ldi rmp,1<<INT0 ; Ext INT0 enable
  out GIMSK,rmp
  sei ; Enable interrupts
;
; **********************************
;    P R O G R A M   L O O P
; **********************************
;
Loop:
  sleep
  nop
  sbrc rFlag,bAdc
  rcall AdcFlag
  sbrc rFlag,bWrite
  rcall WriteEep
  brtc Loop ; Kein Update Sollwert
  clt
  sbis pSwI,bSwI ; Ueberspringe bei Schalter offen
  rjmp SetOpen
  cli
  mov rSetValL,rCloseL ; Sollwert = ZU
  mov rSetValH,rCloseH
  sei
  rjmp Loop
SetOpen:
  cli
  mov rSetValL,rOpenL ; Sollwert Offen-Stellung
  mov rSetValH,rOpenH
  sei
  rjmp loop
;
; ADC-Flagge gesetzt, 64 Messungen fertig
AdcFlag:
  cbr rFlag,1<<bAdc ; Loesche Flagge
  in rmp,ADMUX ; Lese Wandlerkanal
  cpi rmp,1 ; Kanal ADC1?
  breq AdcFlag1
  brcs AdcFlag0
  rjmp AdcFlag2
AdcFlag0:
  ; Kanal 0 auswerten
  ; ADC-Ergebnissumme MSB invertieren und mit vier malnehmen
  ; ADCH(MSB) ADCL(LSB)
  ; xxxx.xxxx.xx(xx.xxxx)
  ; MSB nach R0, die beiden oberen
  ;   Bits vom LSB von rechts
  ;   einschieben
  ; R1        R0
  ; 0000.00xx.xxxx.xxxx
  mov R0,rAdcH ; MSB ADC-Ergebnis
  com R0 ; Potentiometer-Umkehr
  clr R1 ; Loeschen obere Bits
  rol rAdcL
  rol R0 ; in LSB einschieben
  rol R1 ; in MSB schieben
.if HalfStep == 1
  lsl R0 ; in LSB rotieren
  rol R1 ; in MSB rotieren
  .endif
  ; Ergebnis zu 32.768 addieren
  ldi ZH,High(32768)
  ldi ZL,Low(32768)
  sub ZL,R0
  sbc ZH,R1
  mov rOpenH,ZH ; Wert in rOpen kopieren
  mov rOpenL,ZL
  ldi rmp,1 ; auf Kanal 1 weitermessen
  out ADMUX,rmp
  set ; T-Flagge update Sollwert
  rjmp AdcFlag9
AdcFlag1:
  ; Kanal 1 auswerten
  ; ADC-Ergebnis mit vier malnehmen
  ; ADCH(MSB) ADCL(LSB)
  ; xxxx.xxxx.xx(xx.xxxx)
  ; MSB nach R0, die beiden oberen
  ;   Bits vom LSB von rechts
  ;   einschieben
  ; R1        R0
  ; 0000.00xx.xxxx.xxxx
  mov R0,rAdcH ; MSB ADC-Ergebnis in LSB
  com R0 ; Invertieren
  clr R1 ; Loeschen obere Bits
  rol rAdcL
  rol R0 ; in LSB einschieben
  rol R1 ; in MSB schieben
.if Halfstep == 1
  lsl R0 ; in LSB einschieben
  rol R1 ; in MSB schieben
  .endif
  ; Wert von 32.768 abziehen
  ldi ZH,High(32768)
  ldi ZL,Low(32768)
  add ZL,R0
  adc ZH,R1
  mov rCloseH,ZH ; Und in rClose ablegen
  mov rCloseL,ZL
  ldi rmp,2 ; mit Kanal 2 weitermachen
  out ADMUX,rmp
  set ; T-Flagge fuer Sollwert setzen
  rjmp AdcFlag9
AdcFlag2:
  ; Kanal 2 auswerten
.if Halfstep == 1
  ldi rmp,120 ; Multiplikator halb
  ldi ZH,14 ; Minimum CTC-Wert
  .else
  ldi rmp,225 ; Multiplikator ganz
  ldi ZH,30 ; Minimum CTC-Wert
  .endif
  clr ZL
  mov R0,rAdcH
  clr R1
AdcFlag21:
  lsr rmp ; Multiplikator rechts in Carry
  brcc AdcFlag22 ; Null, nicht addieren
  add ZL,R0 ; Eins, Multiplikator addieren
  adc ZH,R1
AdcFlag22:
  ; Multiplikator mal zwei
  lsl R0
  rol R1
  tst rmp ; Alle Einsen multipliziert?
  brne AdcFlag21 ; nein, weiter
  out OCR0A,ZH ; in Compare A schreiben
  ldi rmp,0 ; auf Kanal 0 weitermessen
  out ADMUX,rmp
AdcFlag9:
  clr rAdcH ; Loeschen der Summen
  clr rAdcL
  ldi rAdc,64 ; 64 Messungen neu starten
  ldi rmp,(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)
  out ADCSRA,rmp ; Messung starten
  ret
;
; *************************************
;    E E P R O M - S T E U E R U N G
; *************************************
;
; Schreibe aktuellen Datenset in das EEPROM
;
; Datenstruktur:
  ; .equ cStepSetS = 7 ; fuer Lesen/Schreiben EEPROM
  ; .def rMark1 = R7
  ; .def rCloseL = R8
  ; .def rCloseH = R9
  ; .def rOpenL = R10
  ; .def rOpenH = R11
  ; .def rCurrValL = R12
  ; .def rCurrValH = R13
  ; .def rMark2 = R14
  ; .equ cStepSetE = 15 ; Ende des Datensets
;
WriteEep:
  sbic EECR, EEPE ; warte bis EEPROM bereit
  rjmp WriteEep ; noch nicht bereit
  cbr rFlag,1<<bWrite
  ldi ZH,High(EepAdrs) ; Z auf EEPROM-Adresse
  ldi ZL,Low(EepAdrs)
  ldi YH,High(cStepSetS) ; Y auf Register
  ldi YL,Low(cStepSetS)
  out EEARH,ZH ; in EEPROM-Adressport
  out EEARL,ZL
  ld rmp,Y+ ; Lese erstes Byte
  out EEDR,rmp ; in EEPROM Datenport
  cli ; Interrupts disablen
  sbi EECR, EEMPE ; EEPROM-Schreiben starten
  sbi EECR, EEPE
  sei ; Interrupts wieder enablen
  sbi EECR,EERIE ; EEP-Interrupts einschalten
  ret
;
; Lese EEPROM-Werte ein
; Datenstruktur:
  ; .equ cStepSetS = 7 ; fuer Lesen/Schreiben EEPROM
  ; .def rMark1 = R7
  ; .def rCloseL = R8
  ; .def rCloseH = R9
  ; .def rOpenL = R10
  ; .def rOpenH = R11
  ; .def rCurrValL = R12
  ; .def rCurrValH = R13
  ; .def rMark2 = R14
  ; .equ cStepSetE = 15 ; Ende des Datensets
ReadEep:
  ldi ZH,High(EepAdrs) ; Z auf EEPROM-Werte
  ldi ZL,Low(EepAdrs)
  ldi XH,High(cStepSetS) ; X auf Step-Register
  ldi XL,Low(cStepSetS)
  ldi rmp,cStepSetE-cStepSetS ; Anzahl Bytes
  mov R0,rmp
ReadEep1:
  sbic EECR, EEPE ; warte bis EEPROM bereit
  rjmp ReadEep1
ReadEep2:
  out EEARH,ZH ; Setze Lese-Adresse EEPROM
  out EEARL,ZL
  sbi EECR, EERE ; Lese-Befehl EEPROM
  in rmp, EEDR ; Lese Byte
  st X+,rmp ; speichere in Register
  adiw ZL,1 ; naechste Adresse
  dec R0 ; alle Bytes?
  brne ReadEep2 ; nein, weiter
  mov rmp,rMark1 ; Pruefe Werte
  eor rmp,rMark2 ; Exclusiv-Oder
  cpi rmp,0xFF ; Korrekt?
  breq ReadEep3 ; Ja, korrekte Kennungen
  ; Falsche Kennungen, Ignoriere EEPROM-Daten
  ldi rmp,High(32768) ; Setze Default
  mov rOpenH,rmp ; auf Mitte
  mov rCloseH,rmp
  mov rCurrValH,rmp
  clr rOpenL
  clr rCloseL
  clr rCurrValL
ReadEep3:
  ret
;
; EEPROM-Inhalte Default
;
; Datenstruktur:
  ; .equ cStepSetS = 7 ; fuer Lesen/Schreiben EEPROM
  ; .def rMark1 = R7
  ; .def rCloseL = R8
  ; .def rCloseH = R9
  ; .def rOpenL = R10
  ; .def rOpenH = R11
  ; .def rCurrValL = R12
  ; .def rCurrValH = R13
  ; .def rMark2 = R14
  ; .equ cStepSetE = 15 ; Ende des Datensets
.eseg
.org 0x0010 ; EEPROM-Segment ab 0x10
EepAdrs:
; Defaultwerte: Kennung (0xAA), ZU-Wert, Auf-Wert, IST-Wert,
;   SOLL-Wert, Kennung (0x55)
.db 0xAA ; Kennung 1
.dw 32768 ; Close-Wert
.dw 32768 ; Open-Wert
.dw 32768 ; Aktuelle Position Mitte
.db 0x55 ; Kennung 2
;
; Ende Quellcode
;



Lob, Tadel, Fehlermeldungen, Genöle und Geschimpfe oder Spam bitte über das Kommentarformular an mich.

©2018 by http://www.avr-asm-tutorial.net