mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Arduino: Timer 1: Problem mit Output Compare Register


Autor: Werner M. (wmauss)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Zusammen,

ich habe den nachfolgenden Sketch für den Arduino Nano V3 programmiert.
Dabei dient das brücken gleichgerichtete und rechteckgewandelte 50Hz 
Netzspgssignal als Taktsignal.
Während eines Zykluses (der im Beispiel unten aus 10 Rechteckperioden 
besteht) bleibt das Ausgangssignal auf High bis die voreingestellte 
Anzahl von Halbwellen gezählt wurde, dann schaltet der µC den GPO auf 
Low.
Also quasi nichts anderes als eine PWM, die halt synchron zur 
Netzfrequenz läuft.

Grundsätzlich funktioniert das auch. Das einzige Problem besteht darin, 
daß der GPO frühestens nach zwei Taktzyklen auf Low geht, obwohl die 
Vergleichszahl in OCR1B nur um 1 größer ist als die über TCNT1 
definierte Startzahl des Zählers.
Ich hätte erwartet dass unter diesen Bedingungen der OCR1B Interrupt 
nach einem Taktzyklus kommt, sprich der GPO nach einem Takt auf Low 
wechselt.

Hat jemand eine Idee wieso das so ist und wie ich das korrigieren kann?

Vielen Dank und viele Grüße

Werner
#define osziPin 4            // Pin zum prüfen ob Wellenpaketsteuerung funzt
#define taktPin 5            // 100Hz Rechtecksignal Eingang 

void setup() 
{
  pinMode(osziPin, OUTPUT); // Pin an dem das Signal für die Wellenpaketsteuerung (WPS) ansteht
  pinMode(taktPin, INPUT);  // 100Hz Rechtecksignal aus Netzspg. erzeugt liegt hier an

  // Timer1: 
  noInterrupts();           // Alle Interrupts temporär abschalten
  // Es folgen Einstellungen der Timer/Counter Control Register
  TCCR1A = 0;               // Keine weitere Programmierung von TCCR1A -> Alle bits =0, kein PWM, keine IR Ausgabe über IO Pins 
  TCCR1B = 0;               // TCCR1B bestimmt die Taktquelle (int/ext.: Pin D5) und die Prescaler Einstellung 
  // Konfiguration über die drei Bits CS10..CS12=1. Bedeutet: 1. Kein prescaling, 2. ext. Taktquelle auf 3. steigende Flanke
  TCCR1B |= (1 << CS10);
  TCCR1B |= (1 << CS11);
  TCCR1B |= (1 << CS12);

  TIMSK1 |= (1 << OCIE1B); // Timer compare IR aktivieren
  TIMSK1 |= (1 << TOIE1);  // Overflow IR aktivieren
  
  TCNT1 = 65526;             // Register mit 65526 initialisieren, so dass 10 Zyklen bis Überlauf (65.536) verbleiben
  OCR1B = 65527;             // Output Compare Register B vorbelegen, so dass für Test 6 Zyklen bis Überlauf. Wert wird später dynamisch eingestellt.  
  digitalWrite(osziPin, HIGH);  // Zu Beginn wird WPS Steuerungssignal high gesetzt.  
  interrupts();             // Alle Interrupts einschalten
}
// Interrupt Behandlungsroutine für den Timer Overflow
ISR(TIMER1_OVF_vect)
{
  TCNT1 = 65526;             // Register wieder auf Startwert setzen (10 unter overflow)
  digitalWrite(osziPin, HIGH);    
}

// Interrupt Behandlungsroutine für den OCR1B compare match Fall
  ISR(TIMER1_COMPB_vect)
 {
  digitalWrite(osziPin, LOW);   
} 

void loop() {
  // put your main code here, to run repeatedly:
}

Autor: S. Landolt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Hat jemand eine Idee wieso das so ist ...

"If TCNT equals OCR1x the comparator signals a match. A match will set 
the Output Compare Flag (OCF1x) at the next timer clock cycle."

> ... und wie ich das korrigieren kann?

Indem Timer1 auf einen PWM-Modus gesetzt wird?

Autor: Werner M. (wmauss)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo S. Landolt,

vielen Dank für den Hinweis, den habe ich offensichtlich überlesen.
Dann werde ich mir den PWM Mode mal näher anschauen. Ich bin bisher 
davon ausgegangen dass eine PWM Zyklusdauer von 1s zu niedrig sein wird. 
1s wäre nötig, um Sinuswellen im Nulldurchgang schalten und dabei eine 
Auflösung von 2% realisieren zu können (Wellenpaket Steuerung).
Allerdings habe ich das noch nicht konkret im Datenblatt nachgelesen, 
womöglich ist das kein Problem.

Grüße
Werner

Autor: Dieter F. (jim_quakenbush)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Werner M. schrieb:
> Dann werde ich mir den PWM Mode mal näher anschauen.

Schau Dir besser mal den externen Interrupt an :-)

Autor: S. Landolt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Zyklusdauer von 1s

Bei diesen langen Zeiten könnte man es auch komplett 'von Hand' machen, 
also sogar ohne Timer (das war es vielleicht, was Dieter F. meinte), 
einfach eine Variable im Interrupt hochzählen und entsprechend schalten.
  Trotzdem würde ich einen PWM-Modus vorziehen (d.h. ganz ohne 
Interrupt), z.B. 14 mit Top=ICR1; allerdings erreicht man dabei nicht so 
ohne weiteres einen der Randwerte, es fehlt 0 % oder 100 % - kommt jetzt 
auf die genauen Anforderungen an.

Autor: Werner M. (wmauss)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke S. Landolt.
Ich habe das Kapitel External Interrupts überflogen aber erst Dank 
Deines Hinweises verstehe ich was Dieter F. gemeint haben könnte.

Manuell programmieren hatte ich zuallererst vor, als ich noch keinen 
Arduino besaß und noch nicht ins Datenblatt geschaut habe. Jetzt ist mir 
der ATmega mit seinen Countern dafür eigentlich zu schade.

Eben ist mir zudem klar geworden dass die kleine Unschönheit von zwei 
Taktzyklen minimaler Einschaltdauer oberhalb vom Auszustand kein Problem 
ist.
Wegen des brücken gleichgerichteten Sinussignals mit anschließender 
Rechteckwandlung wird eine 50Hz Sinusschwingung ja von zwei 100Hz 
Rechteckperioden repräsentiert. Somit kann ich trotzdem minimal eine 
50Hz Periode schalten.

Ich möchte ein elektrisches Heizkabel steuern und dazu nur volle 
Sinuswellen nutzen (Phasenan-/-abschnitt finde ich old School:-), 
außerdem habe ich gelesen dass viele EVUn keine leistungsstarken 
Phasenanschniitssteuerungen mehr erlauben).
Eine Änderung in 1% Schritten ist dafür vermutlich eh over the Top.

Vielen Dank für Eure hilfreichen Hinweise!

Viele Grüße
Werner

Autor: Dieter F. (jim_quakenbush)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
S. Landolt schrieb:
> das war es vielleicht, was Dieter F. meinte

Nach dem externen Interrupt x (interne 16 oder so MHz Takte / Prescaler 
z ) warten, bis y passiert.

Autor: Dieter F. (jim_quakenbush)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Werner M. schrieb:
> Eben ist mir zudem klar geworden dass die kleine Unschönheit von zwei
> Taktzyklen minimaler Einschaltdauer oberhalb vom Auszustand kein Problem
> ist.

Dein Fehler ist, das Du Dich auf den externen Takt (50 Hz ?) stützt um 
damit/danach (als Counter) zu schalten - ergo bist Du viel zu langsam.

: Bearbeitet durch User
Autor: Werner M. (wmauss)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du meinst, ich erwische den Nulldurchgang der Sinuswelle nicht mehr?
Das ist egal, dann erwische ich eben die nächste. Denselben Verzug gibt 
es ja auch beim nächsten schalten, so dass die Schaltvorgänge konstant 
versetzt sind.
Ich verwende ein Solid-State Relais mit Nullspannungsdetektor, das 
schaltet ohnehin nur im Nulldurchgang.

Autor: S. Landolt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Solid-State Relais mit Nullspannungsdetektor

Also dann löst sich ja ohnehin alles in Wohlgefallen auf, dieser externe 
Netztakt wird überflüssig, einfach den Timer1 mit einer PWM laufen 
lassen.

Autor: S. Landolt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PS:
Keinerlei Interrupt; für eine Heizanwendung kann man den maximalen 
Vorteiler, d.h. 1024, nehmen.

Autor: S. Landolt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Arduino Nano läuft mit 16 MHz, oder? Also Vorschlag: Timer1 im Modus 
14, um auf die gewünschte Zeit von 1.0 s zu kommen, den Vorteiler auf 
1024 und ICR1 auf 15625-1 setzen (ich selbst würde 4.0 s vorziehen, 
folglich ICR1=62500-1).  Den Tastgrad, wie gehabt, mit OCR1A oder B 
einstellen, Ausgang ist dann OC1A oder B.

Autor: Werner M. (wmauss)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ähem, hüstel, ja, da lässt sich wenig dagegen einwenden. Genau genommen 
gar nichts.

Vielen Dank nochmal an Euch!

Viele Grüße
Werner

: Bearbeitet durch User

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.