- fchao-Sinus-Wechselrichter AliExpress         
Ergebnis 1 bis 10 von 37

Thema: Schrittmotor mit 4bit- Up/Downzähler ansteuern

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    25.10.2005
    Alter
    71
    Beiträge
    157
    ...Fortsetzung.

    Die Steuerung erfolgt über einen Zustandsautomaten, der auswertet, in welchen Zonen sich der Joystick befindet: Klicke auf die Grafik für eine größere Ansicht

Name:	tot.png
Hits:	1
Größe:	7,2 KB
ID:	19108

    • Weiß ist die neutrale Zone. Hier passiert nichts.
    • Blau ist die Fehlerzone. Wird diese betreten, stoppt alles. Man muss erst wieder nach Weiß bevor es weitergeht.
    • Rot ist die eine kontinuierliche Zone.
    • Rosa die andere in die entgegengesetzte Richtung.
    • Orange führt zu einem Einzelschritt. Danach muss zurück nach Weiß um ein weiteren Schritt auszulösen. Ob über Blau oder Gelb ist egal.
    • Gelb hat keine Funktion, trennt aber Orange von Weiß.
    • Violett analog zu Orange für die entgegengesetzte Richtung.
    • Grün analog zu Gelb entgegengesetzte Richtung.

    Die Grenzen Weiß/Gelb/Orange bzw. Weiß/Grün/Violett liegen jeweils auf etwa 1/3 des Joystick-Ausschlags.
    Die Grenzen Weiß/Rot bzw. Weiß/Rosa liegen bei 1/6 des Ausschlags.

    Fortsetzung folgt...

  2. #2
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    25.10.2005
    Alter
    71
    Beiträge
    157
    ...zuletzt der Code.

    Mark, ich melde mich noch einmal per E-Mail bei dir.

    Code:
    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    
    //**************************************************************
    //Hardware-Konfiguration ATtiny45
    //**************************************************************
    #define LRChannel 2    // ADC für Links/Rechts-Poti
    #define UDChannel 3    // ADC für Auf/Ab-Poti
    
    #define PORT      PORTB  // I/O-Port Output-Register)
    #define DDR       DDRB   // Data Direction Register
    #define PIN       PINB   // I/O-Port (Input-Register)
    
    #define PIN_DIR   _BV(2) // Pin für Richtungsausgabe (Direction, CW/CCW)
    #define PIN_CLK   _BV(0) // Pin für Takt-Ausgabe
    #define PIN_QUAD  _BV(1) // Pin für Kennlinie (linear, quadratrisch)
    #define PIN_LED   _BV(5) // Pin für LED-Anzeige
    
    
    //**************************************************************
    //*** Daten des Joysticks
    //**************************************************************
    //Mittelstellung liegt bei einem Messwert von etwa 128 (+/-10)
    //Minimum bei 3 (der Unterschied zu 0 ist vernachlässigbar)
    //Maximum liegt bei 255
    //**************************************************************
    uint8_t LRZero = 0;  //Null-Wert für LR-Kanal
    uint8_t UDZero = 0;  //Null-Wert für UD-Kanal
    uint8_t LR = 0;      //aktueller Messwert LR-Kanal
    uint8_t UD = 0;      //aktueller Messwert UD-Kanal
    
    //**************************************************************
    //*** Definitionen der Zonen
    //**************************************************************
    typedef enum 
    { green,   //beginnt bei etwa 1/3 des Ausschlags (128/3 = ca. 42, also 128-42=86, Nullpunktkorrektur nicht notwendig)
      violett, //beginnt bei etwa 2/3 des Ausschlags (44)
      yellow,  //beginnt bei etwa 1/3 des Ausschlags (170)
      orange,  //beginnt bei etwa 2/3 des Ausschlags (212)
      red,     //beginnt bei etwa 1/6 des Ausschlags (1/8 = UDZero + 16 (Nullpunktskorrektor notwendig))
      pink,    //beginnt bei etwa 1/6 des Ausschlags (1/8 = UDZero - 16 (Nullpunktskorrektor notwendig))  
      white,   //endet bei etwa 1/3 des LR-Ausschlags und 1/6 des UD-Ausschlags (s.o.)
      blue     //der Rest 
    } Zones;
    
    // Beginn (ADC-Wert) der Zonen:
    #define StartGreen     86
    #define StartViolett   44
    #define StartYellow   170
    #define StartOrange   212
    #define StartContZone  16
    
    //**************************************************************
    //*** Globale Variablen
    //**************************************************************
    volatile int8_t   Direction = 0;  // Richtung der Drehung (-1: links, 0: Stopp, 1: rechts) für kontinuierlichen Takt
    volatile uint16_t LedCnt    = 0;  // ISR zählt auf 0 und schaltet dann LED aus.
    volatile uint8_t  OldSpeed  = 0;  // Merker für alte Geschwindigkeit (0 falls vorher Stopp)
    volatile uint16_t OvfsCnt   = 0;  // Zähler für Geschwindigkeit. ISR zählt auf 0 und startet dann wieder mit OvfsFill.
                                      // Bei 0 wird jewiels ein Taktimpuls von 0,256 ms Dauer erzeugt.
    volatile uint16_t OvfsFill  = 0;  // Nach Ablauf einer Zählperiode wird wieder bei diesem Wert gestartet.
    
    
    //**************************************************************
    //*** Prototypen
    //**************************************************************
    uint8_t readADC(uint8_t channel);            // ADC auslesen
    Zones   GetZone(void);                       // Zone ermitteln in der der Joystick steht
    void    HandleZones(void);                   // Statemachine für den Joystick
    void    DoSingleStep(int8_t Direction);      // erzeugt einzelnes Clock-Signal
    void    SetSpeed(uint8_t Speed, int8_t Dir); // ermittelt die Timer-Paramter bei kontinuierlichem Takt
    
    inline void LedOn(uint16_t ms)               // Schaltet die LED für ms Millisekunden an
    { cli();
      LedCnt = ms * 4;
      sei();
    }
    
    inline void LedOff()                         // Schaltet die LED vorzeitig wieder aus
    { cli();
      LedCnt = 0;
      sei();
    }
    
    
    
    //**************************************************************
    //*** Hauptprogramm
    //**************************************************************
    int main(void)
    { DDR  |= PIN_DIR | PIN_CLK | PIN_LED;  //Pins auf Output
      PORT |= PIN_QUAD;                     //Pullup einschalten
      
      //LED für ca. 1/2 Sec. an
      _delay_ms(500);
      PORT |= PIN_LED; //LED aus
    
      TCCR0B |= _BV(CS01);  //Timer aktivieren. Prescaler: 8. OVF-Int erfolgt alle 256µs (3.9 kHz) bei 8MHz Systemtakt
    #if defined (__AVR_ATmega1284P__)
      TIMSK0 |= _BV(TOIE0); //OVF-Interrupt freigeben
    #else
      TIMSK  |= _BV(TOIE0); //OVF-Interrupt freigeben
    #endif
      sei(); // enable Interrupts
    
      // ADC-Werte in Mittelstellung ermitteln
      LRZero = readADC(LRChannel);
      UDZero = readADC(UDChannel);
    
      while(1) // immer wieder den Zustandsautomaten aufrufen
      { HandleZones();  
      }
    
    }
    
    //**************************************************************
    //*** Zustandsautomat für Joystick-Bewegungen
    //**************************************************************
    void HandleZones(void)
    { Zones Zone = GetZone();
    
      if((Zone != red) && (Zone != pink)) //Motor abschalten
      { Direction = 0;
        OldSpeed  = 0;
      }
    
      if(Zone == blue)
      { while (GetZone() != white); //Blau kann nur durch weiß aufgelöst werden.
        return;
      }
    
      if(Zone == orange)
      { //SingleStep +
        LedOn(150);
        DoSingleStep(1);
        while (GetZone() != white); //Weiß muss erreicht werden, bevor es weitergeht
        LedOff();
        return;
      }
    
      if(Zone == violett)
      { //SingleStep -
        LedOn(150);
        DoSingleStep(-1);
        while (GetZone() != white); //Weiß muss erreicht werden, bevor es weitergeht
        LedOff();
        return;
      }
    
      if(Zone == red)
      { //SingleStep +
        SetSpeed(UD - UDZero - StartContZone, 1);
        return;
      }
    
      if(Zone == pink)
      { //SingleStep -
        Direction = -1;
        SetSpeed((UDZero - StartContZone) - UD, -1);
        return;
      }
    }
    
    //**************************************************************
    //*** berechnet die Paramter für die Timer-ISR
    //**************************************************************
    //Speed: 0..112, proportional zur Auslenkung in den Zonen "Rot" und "Rosa" (256/2-StartContZone).
    void SetSpeed(uint8_t Speed, int8_t Dir)
    { uint16_t SchrittFrequenz;
      uint16_t OVFs;
    
      if(Speed == 0)
        Speed=1;
      if(Speed > 112)
        Speed = 112;
    
      if(PIN & PIN_QUAD)
      { // quadratischer Verlauf
        // Schrittfrequenz = 0,003 * Speed ^ 2 + 0,025 * Speed + 2
        SchrittFrequenz = (uint32_t)3 * (uint32_t)Speed * (uint32_t)Speed / (uint32_t)1000 + (uint32_t)25 * (uint32_t)Speed / (uint32_t)1000 + 2;
      }
      else
      { // linearer Verlauf
        // Schrittfrequenz = 0,36 * Speed + 2
        SchrittFrequenz = (uint16_t) 36 * (uint16_t) Speed / (uint16_t)100 + 2;
      }
    
      //OVFs = Anzahl OVF-Interrupts für Periodendauer = 1.000.000 / 256 / Schrittfrequenz
      OVFs = (uint16_t)3900 / SchrittFrequenz;
    
      cli();
    
      OvfsFill = OVFs;
    
      if(OldSpeed)
      { if(OldSpeed > Speed)  // soll langsamer werden
        {/* if(OvfsCnt < OvfsFill)
            OvfsCnt = OvfsFill; // Zeit verkürzen
          Das würde dazu führen, dass bei zunehmender Verlangsamung OvfsCnt immer wieder mit neuen Werten geladen würde
          und nie auf 0 kommen würde. Dass dies im gegengesetzen Fall (siehe nächstes "if") funktioniert, liegt am
          asymetrischen Algorithmus. Der Timer zählt herunter!
         */
        }
        if(OldSpeed < Speed)  // soll schneller werden
        { if(OvfsCnt > OvfsFill)
            OvfsCnt = OvfsFill; // Zeit verkürzen
        }
      }
      else
      { OvfsCnt = 1;  // Bewirkt, dass nach einem Stopp der erste Takt unmittelbar erfolgt.
      }
      Direction = Dir;
      sei();
      OldSpeed = Speed;
    }
    
    
    
    //**************************************************************
    //*** Ermittlung der Zone, in der der Joystick steht
    //**************************************************************
    Zones GetZone()
    { LR = readADC(LRChannel);
      UD = readADC(UDChannel);
    
      if((UD < UDZero + StartContZone) && (UD > UDZero - StartContZone)) // Test auf violett, grün, gelb und orange
      { if(LR < StartViolett)
          return violett;
        if(LR < StartGreen)
          return green;
        if(LR > StartOrange)
          return orange;
        if(LR > StartYellow)
          return yellow;
        return white;
      }
    
      if ((LR > StartGreen) && (LR < StartYellow))
      { if (UD >= UDZero + StartContZone)
          return red;
        else
          return pink;
      }
      return blue;
    }
    
    //**************************************************************
    //*** ADC auslesen
    //**************************************************************
    uint8_t readADC(uint8_t channel)
    { uint8_t i;
      uint16_t result = 0;
        
      // Den ADC aktivieren und Teilungsfaktor auf 64 stellen
      ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);
    
      // Kanal des Multiplexers wählen
      // VCC als Referenzspannung verwenden (also ca. 5V)
      ADMUX = channel | (0<<REFS1) | (0<<REFS0);
      // Den ADC initialisieren und einen sog. Dummyreadout machen
      ADCSRA |= (1<<ADSC);
      while(ADCSRA & (1<<ADSC));
        
      // Jetzt 3x die analoge Spannung and Kanal channel auslesen
      // und dann Durchschnittswert ausrechnen.
      for(i=0; i<3; i++)
      { //Eine Wandlung
        ADCSRA |= (1<<ADSC);
         // Auf Ergebnis warten...
         while(ADCSRA & (1<<ADSC));
            
         result += ADCW/4;
      } // for
        
      // ADC wieder deaktivieren
      ADCSRA &= ~(1<<ADEN);
        
      result /= 3;
        
      return (uint8_t)result;
    } // readADC
    
    //**************************************************************
    // EinzelSchritt durchführen
    //**************************************************************
    void DoSingleStep(int8_t Direction)
    { //Direction setzen
      if(Direction > 0)
        PORT |= PIN_DIR;
      else
        PORT &= ~PIN_DIR;
      _delay_us(10);
     
      //Puls für Schritt ausgeben (Pulslänge 0.256 ms)
      PORT |= PIN_CLK;
      _delay_us(256);
      PORT &= ~PIN_CLK;
      _delay_us(10);
    }
    
    //**************************************************************
    //Die ISR regelt folgende zeitabhängigen Funktion
    //Takterzeugung
    //LED-Steuerung
    //**************************************************************
    ISR(TIMER0_OVF_vect)
    { if(LedCnt)
      { PORT &= ~PIN_LED;
        LedCnt--;
      } 
      else
        PORT |= PIN_LED;
    
      if(!Direction) //Direction ist 0, also Stopp. Keine Takte notwendig
        return;
    
      if(Direction > 0) //Direction Pin setzen
        PORT |= PIN_DIR;
      else
        PORT &= ~PIN_DIR;
    
      if(OvfsCnt == 0) //Puls für Schritt ausgeben (Pulslänge 0.256 ms = 1 OVF)
      { OvfsCnt = OvfsFill;
        PORT |= PIN_CLK;
        LedOn(50);
      }
      else
      { OvfsCnt--;  
        PORT &= ~PIN_CLK;
      }
    }
    Geändert von RedBaron (23.06.2011 um 21:19 Uhr)

Ähnliche Themen

  1. schrittmotor ansteuern mit RP6
    Von proevofreak im Forum Robby RP6
    Antworten: 17
    Letzter Beitrag: 21.02.2012, 13:32
  2. Schrittmotor ansteuern
    Von sahra im Forum C - Programmierung (GCC u.a.)
    Antworten: 2
    Letzter Beitrag: 25.01.2011, 07:23
  3. Schrittmotor ansteuern
    Von DaveWagner im Forum Motoren
    Antworten: 7
    Letzter Beitrag: 10.03.2009, 19:00
  4. Schrittmotor ansteuern
    Von Decca im Forum C - Programmierung (GCC u.a.)
    Antworten: 6
    Letzter Beitrag: 21.02.2006, 13:06
  5. Schrittmotor mit µC ansteuern?
    Von crowdy im Forum Elektronik
    Antworten: 3
    Letzter Beitrag: 09.02.2005, 04:55

Benutzer, die dieses Thema gelesen haben: 0

Derzeit gibt es keine Benutzer zum Anzeigen.

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

LiFePO4 Speicher Test