Servo-Testprogramm Variante 2 mit Timer1-Interrupt:

Wie durch entsprechendes Setzen der Register ein Timer-Interrupt ausgelöst werden kann, findet ihr hier: Timer-Interrupt

Bevor ich das Testprogramm Variante 2 zeige, noch einmal kurz die Vorgangsweise:

  • Der Modus muss im TCCR1B-Register auf CTC-Mode (Clear Timer on Compare Mode) eingestellt werden.
  • Der Inhalt des 16-Bit TCNT1-Register wird mit dem - um den Faktor des Vorteilers (Prescaler) verminderten - Systemtakt erhöht und mit dem Inhalt des 16-Bit OCR1A-Registers verglichen.
  • Bei Übereinstimmung wird, sofern das entsprechende Maskier-Bit im TIMSK1-Register und das globale Interrupt-Enable-Bit gesetzt sind, ein Interrupt ausgelöst.


Vorteiler und Vergleichswert (Inhalt des OCR1A-Register) für eine Periodendauer von 20 ms ermitteln:


Vorgaben:

  • CPU-Frequenz Arduino Uno: 16.000.000 Hz
  • Gewünschte Interruptfrequenz: 50 Hz (= 20 ms Periodendauer)
  • Mögliche Vorteiler: 1, 8, 64, 256 oder 1024


Berechnung des Vergleichswertes:


Vorteiler = 1024:

Vergleichswert = (16.000.000 / (1024 * 50)) - 1 = 311,5

oder Vorteiler = 8: 

Vergleichswert = (16.000.000 / (8 * 50)) - 1 = 39.999

Der errechnete Vergleichswert wird ins OCR1A-Register geschrieben.

Der Vorteiler muss im TCCR1B-Register gesetzt werden.

Achtung: Der errechnete Vergleichswert muss kleiner 65.536 (16-Bit) sein!!

Im nachfolgenden Programm habe ich den (gerundeten) Vergleichswert von 312 (Vorteiler = 1024) gewählt.


Hier nun zusammengefasst, wie die Register gesetzt werden müssen:

cli(); //Loesche globales Interrupt-Enable-Bit


//CTC-Mode aktivieren

TCCR1A = 0; //Loeschen des TCCR1A-Registers

TCCR1B = 0; //Loeschen des TCCR1B-Registers

TCCR1B |= (1 << WGM12);  //Setze CTC-Mode (Waveform Generation Mode)


//Vorteiler (Prescaler) definieren (Vorteiler = 1024)

TCCR1B |= (1 << CS12) | (1 << CS10);  //Setze CS10 und CS12 (Clock Select)


// Timer Counter Register und Output Compare Register setzen

TCNT1 = 0;  //Timer Counter Register loeschen

OCR1A = 312; //Setzen des Vergleichswertes (gerundet)


// Timer/Counter Interrupt Mask Register setzen

TIMSK1 |= (1 << OCIE1A); //Bit Output Compare A Match Interrupt Enable setzen


sei(); //Setze globales Interrupt-Enable-Bit


Wird nun ein Interrupt ausgelöst, springt der Programmablauf in die Interrupt-Serviceroutine "ISR(TIMER1_COMPA_vect)"



Hier nun das vollständige Test-Programm in der Variante 2:

//Servo Testprogramm
//Test_Servo_IRQ_Timer1.ino
//Code fuer Arduino
//Author Retian
//Version 1.0


#define servoPin 2 //Servo auf Pin 2
#define potiPin 2 // Potentiometer auf Pin A2


int pwmTime = 0;
int potiWert = 0;
int pwmTimeMax = 2000; //maximale Impulszeit in Mikrosekunden
int pwmTimeMin = 1000; //minimale Impulszeit in Mikrosekunden


void setup() {
  Serial.begin(115200);
  pinMode(servoPin, OUTPUT);
  digitalWrite(servoPin, 0);
  cli(); // Loeche globales Interruptflag
  TCNT1 = 0; //Timer Counter 1
  TCCR1A = 0; //Timer Counter Controll Register A
  TCCR1B = 0; //Timer Counter Controll Register B
  OCR1A = 312; //Output Compare Register A
  // Setze CS10 und CS12 - Clock Select Bit 10/12 (Prescaler 1024)
  TCCR1B |= (1 << CS12) | (1 << CS10);
  //CTC-Mode ein
  TCCR1B |= (1 << WGM12); // CTC-Mode (Clear Timer and Compare)
  //Timer/Counter Interrupt Mask Register
  TIMSK1 |= (1 << OCIE1A); //Output Compare A Match Interrupt Enable
  sei(); //Setze globales Interruptflag
}


void loop() {
  potiWert = analogRead(potiPin);
  pwmTime = map(potiWert, 0, 1023, pwmTimeMin, pwmTimeMax);
  Serial.print("Potiwert: ");
  Serial.print(potiWert);
  Serial.print(" ");
  Serial.print("Pulslaenge: ");
  Serial.print(pwmTime);
  Serial.println(" us");
}


ISR(TIMER1_COMPA_vect) //Interrupt-Serviceroutine
{
  digitalWrite(servoPin, 1);
  delayMicroseconds(pwmTime);
  digitalWrite(servoPin, 0);
}


Zurück zum Servotest