...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;
  }
}
 
						
					
Lesezeichen