- LiFePO4 Speicher Test         
Seite 4 von 4 ErsteErste ... 234
Ergebnis 31 bis 37 von 37

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

  1. #31
    Neuer Benutzer Öfters hier
    Registriert seit
    07.06.2011
    Beiträge
    6
    Anzeige

    Praxistest und DIY Projekte
    Hi Redbaron,
    wow, nochmal danke.
    Von den beiden Versionen finde ich die erste, einfachere besser, an Sicht- und Bedienelementen völlig ausreichend. Außerdem hat sie den Vorteil, dass man damit (je nach Controller) bipolare und unipolare Motoren antreiben kann.

    Die Deadzone des Joysticks finde ich perfekt so, die LED kriegt einen Widerstand von 470 Ohm.
    Schick mir eine PM, dann überweise ich die Kosten .

    Vielen Dank und viele Grüße,
    Mark

  2. #32
    Neuer Benutzer Öfters hier
    Registriert seit
    07.06.2011
    Beiträge
    6
    Hi,
    noch was zu den Treibern, der Easydriver ist wieder erhältlich und ich habe mir gleich einen geordert.
    Viele Grüße,
    Mark

  3. #33
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    25.10.2005
    Alter
    71
    Beiträge
    157
    sorry für die späte antwort. ich mach dir einen chip übers wochende fertig. melde mich dann.

  4. #34
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    25.10.2005
    Alter
    71
    Beiträge
    157
    Moin,

    hat ein wenig länger gedauert. Ich hatte bei der Umsetzung der Kennlinien einen "Knoten im Kopf".

    So sieht es jetzt aus: Klicke auf die Grafik für eine größere Ansicht

Name:	Kennlinien.png
Hits:	2
Größe:	9,0 KB
ID:	19104

    Die rote Kennlinie ist nicht exponentiell sondern quadratisch. Bei einer exponentiellen Linie, wäre im unteren Bereich zu wenig Dynamik vorhanden. Grund ist die notwendige Diskretisierung. Man hätte zwar mit feineren Schritten arbeiten können, jedoch passt dann die Relation Genauigkeit der Schrittfrequenz, Genauigkeit Ermittlung der Joystick-Stellung, Präzision der Joystick-Führung und Programmaufwand nicht mehr zueinander. Eine quadratische Kennlinie ist ein guter Kompromiss.

    Das Programmteil zur Ermittlung der Joystick-Stellung liefert für den kontinuierlichen Bereich Werte zwischen 1 und etwa 112. Diese werden umgsetzt in Schrittfrequenzen zwischen 2 und etwa 41.

    Fortsetzung folgt...

  5. #35
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    25.10.2005
    Alter
    71
    Beiträge
    157
    ... Fortsetzung.

    Den Schaltplan habe ich ein ein wenig anpassen müssen: Klicke auf die Grafik für eine größere Ansicht

Name:	Schaltplan.jpg
Hits:	9
Größe:	23,0 KB
ID:	19107

    Zum einen sind zwei Abblockkondensatoren notwendig. Das Einschalten der LED hätte sonst zu großen Einfluss auf die Messwerte des ADC. Dies führt beim Übergabg von Zone "Weiß" zu "Rot" (s.u.) zu unangenehmen Schwingungen. Der eine Kondensator muss möglichst nahe an den Stromversorgungspins des Chips angberacht werden, der andere mögichst nahe am Joystick.

    Zum anderen ist es deutlich einfacher, die Kennlinien alternativ anstatt gleichzeitg zu erzeugen. Der Pin "P/Q" schaltet zwischen beiden Kennlinien um. Ist der Pin nicht angeschlossen, wird die quadratische Kennlinie realisiert. Ist er mit GND verbunden, die lineare.

    +5V und GND bekommst du von der Driver-Platine. "DIR" und "STEP" entsprechen den gleichnamigen Pins auf der Driver-Platine. Die Pulslänge für "STEP" ist ca. 0,25 ms.

    Fortsetzung folgt ...
    Geändert von RedBaron (21.06.2011 um 09:29 Uhr)

  6. #36
    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...

  7. #37
    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 22:19 Uhr)

Seite 4 von 4 ErsteErste ... 234

Ähnliche Themen

  1. schrittmotor ansteuern mit RP6
    Von proevofreak im Forum Robby RP6
    Antworten: 17
    Letzter Beitrag: 21.02.2012, 14:32
  2. Schrittmotor ansteuern
    Von sahra im Forum C - Programmierung (GCC u.a.)
    Antworten: 2
    Letzter Beitrag: 25.01.2011, 08:23
  3. Schrittmotor ansteuern
    Von DaveWagner im Forum Motoren
    Antworten: 7
    Letzter Beitrag: 10.03.2009, 20:00
  4. Schrittmotor ansteuern
    Von Decca im Forum C - Programmierung (GCC u.a.)
    Antworten: 6
    Letzter Beitrag: 21.02.2006, 14:06
  5. Schrittmotor mit µC ansteuern?
    Von crowdy im Forum Elektronik
    Antworten: 3
    Letzter Beitrag: 09.02.2005, 05: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
  •  

Labornetzteil AliExpress