Forum: Mikrocontroller und Digitale Elektronik Atmega 328 Timer 2: Hilfe für Frequenzerzeugung


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Christian J. (Firma: privat) (christianj)


Bewertung
-3 lesenswert
nicht lesenswert
Hallo,

mir raucht schon der Schädel von dem Datenbuch was mir auch nicht 
weiterhilft mit den Timern. Ich will einfach nur

Timer 2: 40khz Frequenz (25us Periode) auf Pin und das war es. Ein 
Ausschalten auch noch dazu.

Hat da jemand vielleicht einfach ein paar Zeilen Code, die ich anpassen 
kann?
Ich blick da nicht mehr durch zwischen Waveform Mode,  PWM Mode, 
Capture, welchen nehme ich denn nun?

Gruss,
Christian

von Der Mensch degeneriert (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> welchen nehme ich denn nun

Am besten einen Arduino :-)

von Christian J. (Firma: privat) (christianj)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Toll... ja, aber das nützt nix, ich muss an die Registerebenr dran! Der 
Arduino Murks bietet da nichts an.

Kann ja nicht so schwer sein, auf dem Cortex alles kein Thema, da bin 
ich schneller fertig als beim Arduino....

40 khz, d.h. 8E6 Hz : 1 : (199+1) = 40.000
Prescaler = 1
Timer Top bei 199

soweit bin ich schon. Da muss er dann zurücksetzen auf 0 und den Pin 
toggeln.

: Bearbeitet durch User
von S. Landolt (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Z.B.: CTC mit doppelter Frequenz, 'Compare Output Mode' auf 'Toggle OC2A 
on Compare Match'.

von Christian J. (Firma: privat) (christianj)


Angehängte Dateien:

Bewertung
-2 lesenswert
nicht lesenswert
Ich kann mit solchen Bruchstück-Sätzen leider nicht viel anfangen. Da 
gibt es noch einiges mehr, was gesetzt werden will. bei jedem anderen uC 
ist das einfacher als bei Atmel.

Wenn eine Periode 25us sind, dann muss er bei 25us schalten und bei 50us 
einen Auto-Reload machen. Dann habe ich 50% Duty Cycle.

: Bearbeitet durch User
von Sebastian R. (sebastian_r569)


Bewertung
0 lesenswert
nicht lesenswert
Nein. Bei jedem Compare alle 25us den Pin OC2 togglen. Also von 0 auf 1 
und von 1 auf 0. Genau das hat S. Landolt gesagt. Geht im TCCR2A mit 
COM2A1  und COM2A0

von Christian J. (Firma: privat) (christianj)


Bewertung
-1 lesenswert
nicht lesenswert
und was mache ich mit diesen Waveform Bits? Wie müssen die gesetztt 
werden?

von S. Landolt (Gast)


Bewertung
2 lesenswert
nicht lesenswert
Wurde doch gesagt: CTC!
WGM21 in TCCR2A.

von Cyblord -. (cyblord)


Bewertung
1 lesenswert
nicht lesenswert
Christian J. schrieb:
> und was mache ich mit diesen Waveform Bits? Wie müssen die gesetztt
> werden?

ProTipp (Von Cyberlord zu Mikrosklaven):
Das Datenblatt hat ja nicht nur diese Tabellen zu bieten, sondern sogar 
auch Prosa welche die verschiedenen Modi erklärt. Und ich fühle dass da 
bei dir etwas Bedarf besteht.

> bei jedem anderen uC ist das einfacher als bei Atmel.

Natürlich. Wenn man nicht schwimmen kann ist die Badehose schuld. AVR 
ist da echt ganz ganz doll kompliziert.

: Bearbeitet durch User
von S. Landolt (Gast)


Bewertung
2 lesenswert
nicht lesenswert
Mann, das kostet mich ein Drittel der Kaffeepause.

So ungefähr:
1
DDRB |= (1<<PB3)
2
TCCR2A = (1<<COM2A0) | (1<<WGM21)
3
OCR2A = 99
4
TCCR2B = (1<<CS20)

Ist aber nicht getestet.

von Christian J. (Firma: privat) (christianj)


Bewertung
-3 lesenswert
nicht lesenswert
S. Landolt schrieb:
> Mann, das kostet mich ein Drittel der Kaffeepause.

Ja, das kommt davon, wenn man auf dem Handy tippt statt am PC :-)
Ist aber schon gut, ich hämmer das heute abend in einen Arduino rein, 
Oszi dazu und üblicherweise ist nach rund 20 Minuten etwas fertig, was 
genaudas macht, ohne dass ich mir die Romane aus dem Datenbuch 
durchlesen muss.

von Karl M. (Gast)


Bewertung
2 lesenswert
nicht lesenswert
Christian J. schrieb:
> die Romane aus dem Datenbuch
> durchlesen muss.

Haha, das ist Lustig - trial and error! Programmierung.

Also ich arbeite streng nach dem Datenblatt und es funktioniert dann 
immer.
Was sollte einem sonst "sagen" wie es geht?

von Cyblord -. (cyblord)


Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:

> Ist aber schon gut, ich hämmer das heute abend in einen Arduino rein,
> Oszi dazu und üblicherweise ist nach rund 20 Minuten etwas fertig, was
> genaudas macht, ohne dass ich mir die Romane aus dem Datenbuch
> durchlesen muss.

Warum machst du dann hier überhaupt so lange rum? Oben war Arduino noch 
Murks. Bist du Wankelmütig?

> Kann ja nicht so schwer sein, auf dem Cortex alles kein Thema, da bin
> ich schneller fertig als beim Arduino....

Wie kommt es das du das angeblich auf einem Cortex ohne in Datenblättern 
zu lesen mal so locker machst und beim popeligen AVR scheiterst? Passt 
doch nicht zusammen.

Ich persönlich habe dich in die Schublade "talentlosen Schwätzer" 
gesteckt.

: Bearbeitet durch User
von Christian J. (Firma: privat) (christianj)


Bewertung
-2 lesenswert
nicht lesenswert
Cyblord -. schrieb:
> Ich persönlich habe dich in die Schublade "talentlosen Schwätzer"
> gesteckt.

Da sind wir schon zwei.... keine Ahnung wieso du meinst noch auf meine 
Beiträge reagieren zu müssen? Na lassen wir das, hier fehlt eindeutig 
der Ignore Filter.

von dremel (Gast)


Bewertung
0 lesenswert
nicht lesenswert
S. Landolt schrieb:
> Mann, das kostet mich ein Drittel der Kaffeepause.
>
> So ungefähr:
>
1
> DDRB |= (1<<PB3)
2
> TCCR2A = (1<<COM2A0) | (1<<WGM21)
3
> OCR2A = 99
4
> TCCR2B = (1<<CS20)
5
>
>
> Ist aber nicht getestet.

OCR2A = 199 ;-)
siehe deinen beitrag von 15:28
Beitrag "Re: Atmega 328 Timer 2: Hilfe für Frequenzerzeugung"

von S. Landolt (Gast)


Bewertung
2 lesenswert
nicht lesenswert
Also ich opfere einen Teil meiner Pause, und ja, musste selbst erst ins 
Datenblatt schauen, dann solche Reaktion - na, ich wünsche weiterhin 
viel Erfolg.

von Cyblord -. (cyblord)


Bewertung
2 lesenswert
nicht lesenswert
S. Landolt schrieb:
> Also ich opfere einen Teil meiner Pause, und ja, musste selbst erst ins
> Datenblatt schauen, dann solche Reaktion - na, ich wünsche weiterhin
> viel Erfolg.

Wundert mich auch. Aber talentlos und arrogant geht leider oft Hand in 
Hand.

Beitrag #5763614 wurde vom Autor gelöscht.
von Chris J. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
S. Landolt schrieb:

> Also ich opfere einen Teil meiner Pause, und ja, musste selbst erst ins
> Datenblatt schauen, dann solche Reaktion - na, ich wünsche weiterhin
> viel Erfolg.

Nun komm runter.... danke Dir doch für Deine Mühen. Es funktioniert ja!

von Christian J. (Firma: privat) (christianj)


Bewertung
0 lesenswert
nicht lesenswert
Ich hänge es hier nochmal drunter

Die unten stehende Kombination von Bits ist die einzige, die mir eine 
Frequenz von 40khz erzeugt. Alle denkbar anderen haben eine fixe 
Frequenz von 15.x khz (8 Mhz Takt). Das AVR Datenblatt ist teils schwer 
verständlich, auch nach x Mal durchlesen blicke ich teilweise nicht 
durch. Wie man in Foren sieht viele andere allerdings auch nicht.

Ich habe ein Rechteck an Pin B3 (Arduino = 11), also an OC2A. Hätte es 
zwar lieber gern an OC2B aber das habe ich nicht hin gekriegt. Falls es 
überhaupt möglich ist. zB mit OCRB. Aber bei CTC steht nur OCRA in der 
Tabelle.

Die Frage ist: Was hat dieses WGM22 Bit für eine Bewandnis? Eigentlich 
sollte es doch gelöscht sein für CTC Mode, oder? Könnte ja auch sein, 
dass ich den Fast PWM Mode erwischt habe. Auch der hat bei OCRA = TOP 
seinen Match.

In Tabelle 17-8 steht

Mode 2: WGM2 = 0, WGM1 = 1, WGM0 = 0   (CTC Mode), Top = OCRA.

Wenn man diese "Verallgemeinerung" anlegt steht da für Timer 2 doch
WGM22 = 0; WGM21 = 1, WGM20 = 0

Ob da ein x fehlt für die Timer Nummer?


Nur kommt da dann nichts aus dem Pin raus. Da ich eine IR Diode dran 
habe muss sicher gestellt sein, dass beim Abschalten der Pin auf 0 geht. 
Das scheint nicht immer der Fall zu sein, wenn man den Pin nicht in den 
Normalmode zurück stellt.
1
/* Startet oder stoppt den Timer 2 */
2
void Timer2Enable(bool stat)
3
{
4
  /* OC2B Pin = INT 1 Pin (PD 3)
5
     OC2A Pin = MOSI Pin (PB 3)
6
  */
7
8
  cli();  
9
  if (stat) {
10
    OCR2A  = 50;              // Compare Match A Register auf 40khz
11
    TCCR2A = (1 << COM2A0) | (1 << WGM20); 
12
    TCCR2B = (1 << WGM22)  | (1 << CS20);   // Mode 2 CTC Prescaler 1 und Timer starten  
13
  }
14
  else {
15
    TCCR2B  = 0;         // Prescaler 1 und Timer stoppen
16
    TCCR2A  = 0;     
17
    digitalWrite(11,LOW);  // Pin auf 0 setzen
18
  }
19
  sei();
20
}

: Bearbeitet durch User
von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> OCR2A  = 50;
> TCCR2A = (1 << COM2A0) | (1 << WGM20);
> TCCR2B = (1 << WGM22)  | (1 << CS20);

In der Reihenfolge steckt ein Problem und lauert nur darauf einen 
Wahnsinnig zu machen.

Ich habe nicht alles geprüft.
Aber dieses ist mir aufgefallen!
Ob Timer2 davon betroffen ist, weiß ich auch nicht genau.
Aber viele AVR Timer sind es.

Prüfe also selber die folgenden Aussagen !


Folgende Situation:

Der Timer befindet nach dem Reset in Mode0
Der Arduino Startup Code bereitet ihn für PWM vor.

Im PWM Mode wird OCR2A gelatscht.
Im CTC Mode nicht.

Du schreibst also 50 in das Latch.
Stellst dann den Mode um.
Folge: Der Latchinhalt landet nie im Register.

Mit einigen Timern(allen?) führt das zur Totalblockade des AVR

von Christian J. (Firma: privat) (christianj)


Bewertung
0 lesenswert
nicht lesenswert
Arduino Fanboy D. schrieb:
> Folge: Der Latchinhalt landet nie im Register.

Dass er es doch tut lässt sich auf dem Oszi einwandfrei nachvollziehen. 
Jede Veränderung des Wertes ändert die Frequenz um n * 1/8E6 Schritte. 
39,95xx khz erziele ich. Das reicht auch. Nur die Frage: Bin ich 
überhaupt im CTC Mode ??? Habe noch stur alle relevanten Bits 
durchprobiert, nur mit dieser Kombination funzt es.

: Bearbeitet durch User
von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Nein bist du nicht!
> Phasenrichtige PWM

Darum betrifft dich das auch nicht.

: Bearbeitet durch User
von Christian J. (Firma: privat) (christianj)


Bewertung
0 lesenswert
nicht lesenswert
Arduino Fanboy D. schrieb:
> Phasenrichtige PWM

Und womit würde man dann den Duty Cycle einstellen? Bei mir ist der fix 
50% mit "Toggle OCRA". PWM heisst ja Puls Weiten Modulation. Für IR sind 
ca 30% besser als 50% weil weniger Energie verbraucht wird.

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Bewertung
1 lesenswert
nicht lesenswert
Christian J. schrieb:
> Die unten stehende Kombination von Bits ist die einzige, die mir eine
> Frequenz von 40khz erzeugt.

 Nein, mit OCR2A = 50 bestimmt nicht.

 Dein 328 läuft mit 8MHz, d.h. eine Clockperiode dauert 125ns.
 Du willst alle 25us Pin OC2A toggeln.
1
  DDRB |= (1<<PB3);
2
  TCCR2A = (1 << WGM21) | (1 << COM2A0); // CTC (MODE_2) + Toggle OC2A
3
  TCCR2B = (1 << CS20);                  // Clock(125ns) => Timer2
4
  OCR2A = 199;                           // 125ns * (199+1) = 25000ns = 25us
5
  TCNT2 = 0;                             // Reset Timer2 Counter

 Und das war es schon, funktioniert bestimmt, 1000 Mal erprobt.

: Bearbeitet durch User
von Christian J. (Firma: privat) (christianj)


Bewertung
0 lesenswert
nicht lesenswert
Marc V. schrieb:
> Und das war es schon, funktioniert bestimmt, 1000 Mal erprobt.

Der einzige Unterschied bei dir ist doch das WGM22 Bit weg und dafür das 
WGM21 rein und der Matchwert 199.

Danke, ich probiere es aus!. Aber doch... 40khz kommen bei mir raus, 
ganz sicher nach gemessen :-) Nur warum das so ist war nicht klar.... 50 
ist 200 / 4... also schon mal ein Vielfaches.

: Bearbeitet durch User
von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Und womit würde man dann den Duty Cycle einstellen?
Willst du doch gar nicht....

Das ist alles gar nicht ganz so schwer...
Nur ausprobieren, dass ist hier die schlechteste aller Lösungswege.
Denn die Anzahl der möglichen Permutationen ist erstaunlich groß.

Es bleibt dabei:
Datenblatt lesen und das so oft und so lange, bis es verstanden ist.

Hier eine 16MHz Version.
Für 8MHz Arduinos könntest du OCR2A verdoppeln
Oder eine passendere Vorteiler/OCR2A Kombination ermitteln.
1
#include <util/atomic.h>
2
#define AtomicSection ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
3
4
5
void setTimer()
6
{
7
  AtomicSection
8
  {
9
    TCCR2A = _BV(COM2A0) |_BV(WGM21);
10
    TCCR2B = _BV(CS21);
11
    OCR2A  = 24;
12
    TCNT2  = 0;
13
  }
14
}
15
16
17
18
19
void setup() 
20
{
21
 Serial.begin(9600);
22
 Serial.println("Start");
23
 setTimer();
24
}
25
26
void loop() 
27
{
28
  pinMode(11, OUTPUT); // Burst
29
  delay(100);
30
  pinMode(11, INPUT);  // Pause
31
  delay(1000);
32
}

von Marc V. (Firma: Vescomp) (logarithmus)


Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Danke, ich probiere es aus!. Aber doch... 40khz kommen bei mir raus,
> ganz sicher nach gemessen :-) Nur warum das so ist war nicht klar....

Christian J. schrieb:
> TCCR2B = (1 << WGM22)  | (1 << CS20);   // Mode 2 CTC Prescaler 1
> und Timer starten

 Nein, du hast MODE 5 eingeschaltet und das ist laut DaBla:
 PWM, Phase Correct

von Christian J. (Firma: privat) (christianj)


Bewertung
0 lesenswert
nicht lesenswert
Arduino Fanboy D. schrieb:
> #define AtomicSection ATOMIC_BLOCK(ATOMIC_RESTORESTATE)

Ok. Bringt das hier Vorteile gegenüber sei und cli? Soll ja wohl 
heissen, dass da kein Int zwischenfunken darf denke ich mal.

von Christian J. (Firma: privat) (christianj)


Bewertung
0 lesenswert
nicht lesenswert
Marc V. schrieb:
> Nein, du hast MODE 5 eingeschaltet und das ist laut DaBla:
>  PWM, Phase Correct

Ich glaube es euch! Es kam ja das Gewünschte heraus. Nur warum war die 
Frage.... kriegt man das Signal auch auf dem INT 1 Pin hin?

: Bearbeitet durch User
Beitrag #5783044 wurde vom Autor gelöscht.
von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Arduino Fanboy D. schrieb:
>> #define AtomicSection ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
>
> Ok. Bringt das hier Vorteile gegenüber sei und cli? Soll ja wohl
> heissen, dass da kein Int zwischenfunken darf denke ich mal.

Ja, es löscht erst das Flag und erzwingt dann, am Ende des Blocks, dass 
Interrupt Enable Flag wieder auf den alten Stand gesetzt wird.

Händisch ist oft/meist fehlerträchtiger, als ein erprobter Automatismus.

: Bearbeitet durch User
von Harry L. (mysth)


Bewertung
0 lesenswert
nicht lesenswert
Arduino Fanboy D. schrieb:
> Händisch ist oft/meist fehlerträchtiger, als ein erprobter Automatismus.

Was ist daran fehlerträchtig?
1
void blabla(void)
2
{
3
uint8_t sreg;
4
  sreg = SREG;
5
  cli();
6
...
7
...
8
...
9
  SREG = sreg;
10
}

genau so wird das in einer Microchip-App-Note beschrieben.

von Christian J. (Firma: privat) (christianj)


Bewertung
0 lesenswert
nicht lesenswert
Harry L. schrieb:
> Was ist daran fehlerträchtig?

Da bei einem Arduino eh dauernd ein INT läuft ist es auch wumpe den aus 
und wieder ein zu schalten. Schaltet man ihn ab funktioniert einiges 
nicht mehr, zb die Serielle nicht, delay usw. usw.

von Harry L. (mysth)


Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Harry L. schrieb:
>> Was ist daran fehlerträchtig?
>
> Da bei einem Arduino eh dauernd ein INT läuft ist es auch wumpe den aus
> und wieder ein zu schalten. Schaltet man ihn ab funktioniert einiges
> nicht mehr, zb die Serielle nicht, delay usw. usw.

Ja und?
Man schaltet den ja deshalb auch nicht dauerhaft aus, sondern nur für 
kritische Abschnitte, die selten länger als wenige µs dauern.

"Wumpe" ist das ganz und gar nicht!

von Oliver S. (oliverso)


Bewertung
0 lesenswert
nicht lesenswert
Arduino Fanboy D. schrieb:
> Im PWM Mode wird OCR2A gelatscht.
> Im CTC Mode nicht.
>
> Du schreibst also 50 in das Latch.
> Stellst dann den Mode um.
> Folge: Der Latchinhalt landet nie im Register.

Äh, warum nicht?

> Mit einigen Timern(allen?) führt das zur Totalblockade des AVR

Äh, warum?

Oliver

von Arduino Fanboy D. (ufuf)


Bewertung
1 lesenswert
nicht lesenswert
Oliver S. schrieb:
> Äh, warum nicht?
Weil der Latchinhalt erst in das Register geschrieben wird, wenn der 
Zähler TOP erreicht.

Oliver S. schrieb:
> Äh, warum?
Tja.....
Das Problem ist das Latch, in Verbindung mit dem Moduswechsel von PWM 
auf Compare Match


Hier kann ich dir ein Beispiel für eine solche Blockade liefern.
Nur Timer init und ISR
(es stammt nicht aus meiner Feder, Kritik am Stil wird verpuffen)

Geschrieben für Arduino Mega, also ATMEGA2560
1
// diese Version funktioniert     
2
void set_Timer2()         // CTC, Mode 2
3
{
4
  cli();                  // Interrupts ausschalten
5
  TCCR2A = (1<<WGM21);    // set Mode
6
  TCCR2B = (1<<CS22);     // Prescaler 64
7
  TCNT2 = 0;              // Reset Register                 
8
  OCR2A = 249;            // Compare
9
  TIMSK2 = (1<<OCIE2A);   // Compare Match A
10
  sei();                  // Interrupts einschalten
11
}  
12
    
13
/*  
14
// diese Version versagt, totale µC Blockade 
15
void set_Timer2()         // CTC, Mode 2
16
{
17
  cli();                  // Interrupts ausschalten
18
  TCNT2 = 0;              // Reset Register                 
19
  OCR2A = 249;            // Compare
20
  TIMSK2 = (1<<OCIE2A);   // Compare Match A
21
  TCCR2A = (1<<WGM21);    // set Mode
22
  TCCR2B = (1<<CS22);     // Prescaler 64
23
  sei();                  // Interrupts einschalten
24
}  
25
*/ 
26
27
28
ISR(TIMER2_COMPA_vect)          // Timer 2 Interrupt 
29
{  
30
  static bool state = LOW;
31
  state = !state;
32
  digitalWrite(pin_T2, state);                    
33
}

: Bearbeitet durch User
von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Harry L. schrieb:
> Arduino Fanboy D. schrieb:
>> Händisch ist oft/meist fehlerträchtiger, als ein erprobter Automatismus.
>
> Was ist daran fehlerträchtig?void blabla(void)
> {
> uint8_t sreg;
>   sreg = SREG;
>   cli();
> ...
> ...
> ...
>   SREG = sreg;
> }
>
> genau so wird das in einer Microchip-App-Note beschrieben.

Kann ja sein!
Tausend Fliegen beweisen: Scheiße schmeckt gut!

Im Ernst:

  cli();
...
...
...
  SREG = sreg;

Man könnte das ein oder andere cli() oder SREG = sreg, versehentlich 
löschen, falsch platzieren.

Bei Blockklammern fallen fehlende Klammern sofort auf.
Der Compiler jault erzürnt ....

Und durch die (hoffentlich vorhandene) Einrückung sieht man klar und 
deutlich was zusammen gehört.

Also:
Es ist grundsätzlich egal, welche Methode man verwendet.
Mir, ist allerdings die Block Methode lieber!

Und ja, natürlich kann man auch über diese Geschmacksfrage, 
Glaubenskriege anzetteln.

: Bearbeitet durch User
von Oliver S. (oliverso)


Bewertung
0 lesenswert
nicht lesenswert
Arduino Fanboy D. schrieb:
> Hier kann ich dir ein Beispiel für eine solche Blockade liefern.

Kannst du nicht. "Totale Blockade" gibt es beim ATMega schlicht gar 
nicht. Das Programm macht nicht das, was der Programmierer sich 
vorgestellt hat, aber laufen tut das immer.

Zudem setzt du in der angeblich fehlerhaften Version 2 Register OCRA vor 
allen anderen. Das Latch-Problem kann da also gar nicht auftreten.

Natürlich kann das ein Problem sein, wenn man eins der gelatchten 
Register erts nach der Anwahl des Timermodus schreibt. Der Wert wird 
dann erst beim nächsten BOTTOM/TOP geupdated, oder wann auch immer in 
dem Modus das Register geupdated wird. Je nachdem, was man da vorher in 
die Register geschrieben hat, passiert das eventuell gar nicht, wobei 
mir dazu beim OCR jetzt erst einmal kein Fall einfallen will.

Eine Blockade tritt da aber niemals auf.

Oliver

: Bearbeitet durch User
von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Oliver S. schrieb:
> Das Latch-Problem kann da also gar nicht auftreten.
Irgendwas hast du da noch nicht ganz verstanden.

Oliver S. schrieb:
> Eine Blockade tritt da aber niemals auf.
Getestet?
Warum nicht?
Die genannten Bedingungen eingehalten?

von Oliver S. (oliverso)


Bewertung
0 lesenswert
nicht lesenswert
Arduino Fanboy D. schrieb:
> Oliver S. schrieb:
>> Das Latch-Problem kann da also gar nicht auftreten.
> Irgendwas hast du da noch nicht ganz verstanden.

Äh, doch.


>
> Oliver S. schrieb:
>> Eine Blockade tritt da aber niemals auf.
> Getestet?
> Warum nicht?
> Die genannten Bedingungen eingehalten?

Natürlich. Es passiert - nix. Der Prozessor läuft in seiner 
Programmende-Endlosschleife fröhlich vor sich hin. Der Timer macht halt, 
was man ihm sagt, und nicht, was sich der Programmierer wünscht. Von 
totaler Blockade aber keine Spur.

Oliver

von Füllwortfan (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Oliver S. schrieb:

> Äh, warum nicht?
>
>> Mit einigen Timern(allen?) führt das zur Totalblockade des AVR
>
> Äh, warum?

>> Irgendwas hast du da noch nicht ganz verstanden.

> Äh, doch.

Äh stört Dich dieser Sprachfehler nicht?

Äh  mir würde das maximal auf's Schwein gehen!

SCNR

von Oliver S. (oliverso)


Bewertung
0 lesenswert
nicht lesenswert
Oliver S. schrieb:
> Natürlich. Es passiert - nix.

Ok, das nix nehme ich zurück. avrlibc baut ein cli vor die 
Endlosschliefe. Mit einem while(1) im main wird in beiden Verisonen die 
ISR angesprungen.

Oliver

von Christian J. (Firma: privat) (christianj)


Bewertung
0 lesenswert
nicht lesenswert
Marc V. schrieb:
> Und das war es schon, funktioniert bestimmt, 1000 Mal erprobt.

Ja, es funzt,. mit 20.3 khz :-) Mit 99 passt es, 39,97khz.

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Ja, es funzt,. mit 20.3 khz :-)

 Mein Fehler, für 40KHz am OC2A muss der Pin alle 12,5us toggeln,
 nicht alle 25us.
 Demzufolge muss OCR2A 99 und nicht 199 sein.

: Bearbeitet durch User
von S. Landolt (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ohne Kommentar.

von Christian J. (Firma: privat) (christianj)


Bewertung
0 lesenswert
nicht lesenswert
Marc V. schrieb:
> Mein Fehler, für 40KHz am OC2A muss der Pin alle 12,5us toggeln,
>  nicht alle 25us.

Hast du auch ne Lösung für schnelle Stop/Starts? Den Takt abklemmen mit 
CS0. Für IR muss aber auf jeden Fall dann  PB3 auf low gehen.

von Christian J. (Firma: privat) (christianj)


Bewertung
0 lesenswert
nicht lesenswert
S. Landolt schrieb:
> Ohne Kommentar.

Ja, PWM Mode.... kein CTC. Siehe WGM22. Kommt aber das Gleiche bei rum.

von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Und genau der Kommentar ist falsch: "fast PWM mit top=OCR2A" muss das 
heißen.

von Christian J. (Firma: privat) (christianj)


Bewertung
0 lesenswert
nicht lesenswert
Landholts Lösung ist für mich besser, da ich damit den DC absenken kann 
denke ich. 30% reichen.
TCCR2A = 0;
   TCCR2B = 0;

Kannst noch rauswerfen, die nächsten Befehle sind ja Zuweisungen,.

: Bearbeitet durch User
von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ich habe keine Ahnung vom Arduino, wegen dieser Latch-Geschichte nach 
dem Arduino-Setup wollte ich sicher sein, dass es funktioniert.

von Christian J. (Firma: privat) (christianj)


Bewertung
0 lesenswert
nicht lesenswert
Ich will dich nicht schocken aber dein Code, copy & paste grad 
ausprobiert erzeugt leider nichts. Nacktes Pro Mini Board aus der Tüte. 
Nur einen High Pegel auf dem PB3 Pin. Nehme ich WGM22 wieder rein kommt 
40khz aber OCR2B hat keinerlei Auswirkungen.

Ok, Fehler suche ich jetzt aber nicht mehr, muss noch bügeln.....

von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wer, bitte, redet von PB3? Sie wollten OC2B = D3.

von Christian J. (Firma: privat) (christianj)


Bewertung
0 lesenswert
nicht lesenswert
S. Landolt schrieb:
> Wer, bitte, redet von PB3? Sie wollten OC2B = D3.

Ok..... da kommt dann auch was.

von Marc V. (Firma: Vescomp) (logarithmus)


Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Hast du auch ne Lösung für schnelle Stop/Starts? Den Takt abklemmen mit
> CS0. Für IR muss aber auf jeden Fall dann  PB3 auf low gehen.

 Was heißt schnell ?
 Nachdem du einmal Init gemacht hast:

 STOP:
1
 TCCR2B = 0;
2
 PORTB &= ~(1<<PB3);
 Das braucht selbst beim GCC nur 2+2 Takte, da meistens r1 dazu
 genommen wird und dessen Inhalt ist normallerweise immer 0.

 Erneuter START:
1
   TCCR2B = (1 << CS20);
 Das braucht 3 Takte.

: Bearbeitet durch User
von Christian J. (Firma: privat) (christianj)


Bewertung
1 lesenswert
nicht lesenswert
Arduino Fanboy D. schrieb:

> cli();                  // Interrupts ausschalten
>   TCNT2 = 0;              // Reset Register
>   OCR2A = 249;            // Compare
>   TIMSK2 = (1<<OCIE2A);   // Compare Match A
>   TCCR2A = (1<<WGM21);    // set Mode
>   TCCR2B = (1<<CS22);     // Prescaler 64
>   sei();

Schießt den uC tatsächlich völlig ab. Der ist nirgendwo mehr. Öfter mal 
was Neues.... beim ARM käme wohl eine "Hard Fault Exception" aber beim 
AVR328P eher nicht. Die nachfolgende Blink Routine wird gar nicht mehr 
erreicht und ein Reboot Findet auch nicht statt. Nur der WDT holt ihn 
wieder raus.

: Bearbeitet durch User
von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Kein schöner Anlass..
Aber dennoch herzlichen Dank, für die Rückkopplung.

von Oliver S. (oliverso)


Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Schießt den uC tatsächlich völlig ab. Der ist nirgendwo mehr.

Mal rein interessehalber: Woran siehst du das?

Oliver

von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
> Schießt den uC tatsächlich völlig ab.

Sagen wir lieber "den Arduino" statt "den uC"; und wenn die 
Arduino-Umgebung nicht einen ganz ungewöhnlichen Kunstgriff in der ISR 
für OCIE2A verwendet, so läuft das Hauptprogramm sehr wohl weiter, aber 
extrem langsam, immer nur ein einziger Befehl pro ISR-Aufruf.

von spess53 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hi

>Schießt den uC tatsächlich völlig ab. Der ist nirgendwo mehr.

Dann macht entweder die Arduino-Software total Mist oder du hast einen 
anderen Fehler.

Wenn ich die Initialisierung mit diese Werten in Assembler mache, 
springt der Controller wie gewünscht in den TIMER2_COMPA-Interrupt und 
gibt eine Frequenz von 250Hz aus.

MfG Spess

von Oliver S. (oliverso)


Bewertung
0 lesenswert
nicht lesenswert
Arduino Fanboy D. schrieb:
> Das Problem ist das Latch, in Verbindung mit dem Moduswechsel von PWM
> auf Compare Match

Kannst du mal für mein Verständnis ein vollständiges Programm zeigen? 
Denn in deinem Beispiel sehe ich gar kein PWM-Mode, da wird der Timer 
von was auch immer auf CTC Mode (nur WGM21=1) eingestellt.

"Was auch immer" war bei meinem Test Normal-Mode nach Reset.

Oliver

: Bearbeitet durch User
von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
an Spess:
1
  sbi     DDRB,0              ; Blink-LED
2
3
  ldi     tmp0,(1<<WGM20)
4
  sts     TCCR2A,tmp0         ; hier auskommentieren
5
6
  ldi     tmp0,249
7
  sts     OCR2A,tmp0
8
  ldi     tmp0,(1<<OCIE2A)
9
  sts     TIMSK2,tmp0
10
  ldi     tmp0,(1<<WGM21)
11
  sts     TCCR2A,tmp0
12
  ldi     tmp0,(1<<CS20)
13
  sts     TCCR2B,tmp0
14
  sei
15
16
main_loop:
17
  rcall   wait100ms
18
  sbi     PINB,0
19
  rjmp      main_loop

Lassen Sie dies hier mal laufen, und anschließend das erste 'sts 
TCCR2A,tmp0' auskommentieren.

von Christian J. (Firma: privat) (christianj)


Bewertung
0 lesenswert
nicht lesenswert
S. Landolt schrieb:
> Sagen wir lieber "den Arduino" statt "den uC"; und wenn die
> Arduino-Umgebung nicht einen ganz ungewöhnlichen Kunstgriff in der ISR
> für OCIE2A verwendet,

Ich habe da keine wiss. Untersuchung gemacht. Ein Dauer INT Feuer, weil 
ein Bit nicht zurück gesetzt wurde legt auch jede CPU lahm, auch den 
ARM. Und die Arduino IDE setzt hauptsächlich den Frame über den Code 
namens setup und loop. Zudem wird Timer 0 für Millis gebrauchtr. Alles 
was aber in den Routinen steht, da ist nur der GCC für zuständig. Ich 
kenne auch den Startup Code nicht, geschweige denn weiss ich nicht, ob 
da Default INT Handler installiert sind.

Möge sich damit jemand befassen, der Spass daran hat. zb mit AVR Studio 
und einem echten Debugger am JTAG Port. Das habe ich alles nicht.

: Bearbeitet durch User
von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Aber Sie verstehen nun, weshalb ich vorsichtshalber das Nullsetzen von 
TCCR2A und B voranstellte.

von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
an Spess:
Pardon, da fehlte natürlich noch so etwas wie
1
.org  OC2Aaddr
2
    reti

von Christian J. (Firma: privat) (christianj)


Bewertung
0 lesenswert
nicht lesenswert
S. Landolt schrieb:
> Aber Sie verstehen nun, weshalb ich vorsichtshalber das Nullsetzen von
> TCCR2A und B voranstellte.

Nein. Nur wenn da Mechanismen am Werk sind, die irgendein Schaltwerk 
bedienen. Register sind ja keine RAM Variablen, sondern Hardware Latches 
mit Leitungen dran von und zu irgendwelchen Peripherien. Auch beim ARM 
gibt es solche, die in einer bestimmten Reihenfolge gesetzt werden 
müssen, obwohl dieses im ersten Moment unsinnig erscheint. Um das zu 
ergründen müsste man den VHDL Code des AVR haben und den im Simulator 
laufen lassen. Und ich nehme an, dass der nicht Open Source ist.

Errata steht nix drin:
https://www.kitronik.co.uk/pdf/46101_atmega328_summary.pdf

: Bearbeitet durch User
von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Mit dem Nullsetzen der TCCR2_ wird der Timer2 in den Normalmodus 
zurückversetzt, damit ist das Problem aus der Welt.

von spess53 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hi

>Lassen Sie dies hier mal laufen, und anschließend das erste 'sts
>TCCR2A,tmp0' auskommentieren.

Mit dem sts kommen ca. 165kHz und ohne ca. 16kHz heraus. Und weiter?

MfG Spess

von Oliver S. (oliverso)


Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Errata steht nix drin:
> https://www.kitronik.co.uk/pdf/46101_atmega328_summary.pdf

So isses. Da das Datenblatt zu dem Thema Reihenfolge auch nichts weiter 
sagt, kann das höchstens eine Fehler im Prozessor sein, aber kein 
genrelles Latch-Problem.

Und nochmals meine Frage: Woran hast du gesehehn, daß der Prozessor 
"nirgends mehr" ist?

Oliver

von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
an Spess:

Das Problem besteht darin, dass im einen Fall der Wert für OCR2A nie 
übernommen wird, folglich permanent die ISR aufgerufen wird.

Beitrag #5784244 wurde vom Autor gelöscht.
von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Dieses Thema wurde vor geraumer Zeit hier schon einmal diskutiert, aber 
ich bin unfähig, das wiederzufinden.

von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Ok....

Ich glaube ich muss einen kleinen Rückzug machen!
Denn das Problem ist gerade auch bei mir nicht reproduzierbar.

Schade eigentlich, den original Testcode habe/finde ich nicht mehr.
Den mit der Totalblockade.
Hinter der Totalblockade muss ich jetzt also ein deutliches Fragezeichen 
platzieren.

Was allerdings weiterhin gültig bleibt:

Der OCR2A Wert wird nicht übernommen.
Das gilt auf jeden Fall für den Timer2 vom ATMEga328P und ATMega2560
1
OCR2A  = 50;
2
TCCR2A = (1<<WGM21);   
3
TCCR2B = (1<<CS22);
>
> In der Reihenfolge steckt ein Problem und lauert nur darauf einen
> Wahnsinnig zu machen.
>
> .... Folgende Situation:
>
> Der Timer befindet sich nach dem Reset in Mode0
> Der Arduino Startup Code bereitet ihn für PWM vor.
>
> Im PWM Mode wird OCR2A gelatscht.
> Im CTC Mode nicht.
>
> Du schreibst also 50 in das Latch.
> Stellst dann den Mode um.
> Folge: Der Latchinhalt landet nie im Register.

von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
> TCCR2B = (1<<CS22);

Was passiert, wenn statt des Vorteilers 64 (CS22) der Vorteiler 1 (CS20) 
genommen wird?

von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Oliver S. schrieb:
> Kannst du mal für mein Verständnis ein vollständiges Programm zeigen?
> Denn in deinem Beispiel sehe ich gar kein PWM-Mode, da wird der Timer
> von was auch immer auf CTC Mode (nur WGM21=1) eingestellt.
>
> "Was auch immer" war bei meinem Test Normal-Mode nach Reset.

Den komplett blockierenden Code finde ich gerade nicht.
Ist allerdings auch ein Arduino Programm gewesen, weiß nicht ob dir das 
dann helfen würde.

Der Arduino Startupcode erzeugt folgenden Timer2 Zustand:
1
    // Arduino Startup Code Fragment
2
    TCCR2A = 1;
3
    TCCR2B = 4;
4
    TCNT2  = 51; // ca. zaehlerstand zum Zeitpunkt des Eintritts in die Main loop
5
    TIMSK2 = 0;
6
    OCR2A  = 0;
Gilt für Mega2560 und 328P,
TCNT2 unterscheidet sich geringfügig

von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
S. Landolt schrieb:
>> TCCR2B = (1<<CS22);
>
> Was passiert, wenn statt des Vorteilers 64 (CS22) der Vorteiler 1 (CS20)
> genommen wird?

Ja, so sieht es stehend aus

Die Serielle Ausgabe kann sich gerade noch eine 0 abquetschen, dann 
nichts mehr.

Auch wieder Mega2560 und 328P identisches Verhalten.
1
   
2
void setTimer2()         // CTC, Mode 2
3
{
4
  cli();                  // Interrupts ausschalten
5
  TCNT2 = 0;              // Reset Register                 
6
  OCR2A = 249;            // Compare
7
8
  TIMSK2 = (1<<OCIE2A);   // Compare Match A
9
  TCCR2A = (1<<WGM21);    // set Mode
10
  TCCR2B = (1<<CS20);     // Prescaler 1
11
  //TCCR2B = (1<<CS22);     // Prescaler 64
12
  sei();                  // Interrupts einschalten
13
}  
14
15
16
17
18
void setup(void) 
19
{
20
  Serial.begin(9600);
21
  DDRB |= (1 << PB7); // LED an ArduinoMega Pin 13
22
  setTimer2();   
23
}
24
25
void loop(void) 
26
{
27
  Serial.println(millis());
28
  delay(500);
29
}
30
31
32
 
33
ISR(TIMER2_COMPA_vect)          // Timer 2 Interrupt 
34
{  
35
   PINB = (1 << PB7); // toggle
36
}

: Bearbeitet durch User
von Oliver S. (oliverso)


Bewertung
0 lesenswert
nicht lesenswert
Kannst du mal

  TCNT2 = 0;              // Reset Register

auskommentieren?

Oliver

von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Oliver S. schrieb:
> auskommentieren
Done!
Resultat: Kein Änderung.

> Ja, so sieht es stehend aus

An dem Toggel Pin stehen 250kHz Rechteck an

: Bearbeitet durch User
von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Nachtrag

So wie ich es jetzt sehe:

Die Interrupt Priorität von Timer 2 ist höher als die die von Timer0 
(delay,millis) und auch höher als die von der UART.
Also kommen beide nicht mehr dran.

So entsteht der Eindruck des völligen Stillstands.

Richtig so?

: Bearbeitet durch User
von Tim T. (tim_taylor) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Arduino Fanboy D. schrieb:
> ISR(TIMER2_COMPA_vect)          // Timer 2 Interrupt
> {
>    PINB = (1 << PB7); // toggle
> }

Aha...

: Bearbeitet durch User
von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Tim T. schrieb:
> Aha...

Was, "Aha" ?
Datenblatt nicht gelesen?

: Bearbeitet durch User
von Oliver S. (oliverso)


Bewertung
1 lesenswert
nicht lesenswert
Arduino Fanboy D. schrieb:
> Richtig so?

Das ist zwar richtig, aber wie Tim schon anmerkte, müsste der PB7 
trotzdem togglen. Die ISR sollte ja aufgerufen werden.

Oliver

: Bearbeitet durch User
von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Oliver S. schrieb:
> wie Tim schon anmerkte, müsste der PB7
> trotzdem togglen. Die ISR sollte ja aufgerufen werden.

Ja, das ist auch so...
Welches bei 16MHz Takt zu einem ca. 250kHz Rechteck am Pin führt.

Der LA zeigt es.

Der LED_BULITIN (an PB7) sieht man es nicht an.
Schätze mal, dass der Operationsverstärker da nicht mit kommt.
Ja, der Arduino Mega und UNO hat einen  Operationsverstärker zwischen 
LED und Prozessor Pin, damit die LED das Signal nicht belastet, wenn der 
Pin als Eingang genutzt werden soll.
Was den Eindruck des Stillstands verstärkt.

: Bearbeitet durch User
von Oliver S. (oliverso)


Bewertung
0 lesenswert
nicht lesenswert
Was insofern gut ist, als daß es tatsächlich keinen "Stillstand" gibt. 
Passiert das auch mit Timer 3?

Oliver

von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Oliver S. schrieb:
> Passiert das auch mit Timer 3?

Bisher nicht getestet...

Timer0 bis Timer2 sind betroffen.
Also vermutlich auch Timer 3

Einfach ins Datenblatt schauen. Dürfte reichen.
Wenn OCRXY gelatched ist, wird es ihn auch betreffen.

: Bearbeitet durch User
von Oliver S. (oliverso)


Bewertung
0 lesenswert
nicht lesenswert
Wenn es nur Timer 2 gewesen wäre, könnte das auch noch mit dessen 
Asynchron-Funktionalität zusammenhängen. Aber wenn 0 und 1 auch 
betroffen snd, dann wirds bei allen Timer so sein.

Ist aber m.E. immer noch ein Fehler, der in die Errata gehört, und kein 
generelles Latch-Problem.

Oliver

Beitrag #5784378 wurde von einem Moderator gelöscht.
Beitrag #5784387 wurde vom Autor gelöscht.
von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Wie auch immer...

Meinen Dank an euch!

Vorher war mir klar:
Initialisierungsreihenfolge beachten, sonst evtl. derbe Probleme.

Jetzt habe ich ein deutlicheres Bild davon, was wirklich passiert.
Und warum es diese Probleme gibt.

Danke!

: Bearbeitet durch User
von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
> Fehler, der in die Errata gehört

Was sollte Atmel/Microchip dort schreiben?
Für mich ist es ein typischer Programmierfehler, der nur deshalb leicht 
tückisch ist, weil hier zwei "Programmierer" arbeiten, einmal die 
Arduino-Umgebung und dann der eigentliche Programmierer.

von Oliver S. (oliverso)


Bewertung
0 lesenswert
nicht lesenswert
Das ist kein Programmierfehler, und es hat nichts mit Arduino zu tun.

Das Datenblatt gibt keine Reihenfolge der Initialisierung vor. Natürlich 
sollte beim Umschalten von einem gelatchten auf einen ungelachten Modus 
das entsprechend Register aus dem Latch geupdated werden, wenn da ein 
noch nicht geschriebener Wert drinsteht.

Das ist ein klarer Implementierungsfehler (wenn es denn ohne Reihenfolge 
funktionieren sollte), oder ein Fehler im Datenblatt, wenn es eine 
bestimmte Reihenfolge benötigt.

Oliver

von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
> beim Umschalten von ... Modus ... geupdated

Zugegeben, das wäre eine Möglichkeit. Trotzdem bin ich der Meinung, dass 
das etwas viel verlangt ist von der Hardware, nur wegen eines solchen 
Sonderfalles. Und aus dem Datenblatt lässt es sich herauslesen, mit ein 
wenig Mühe.

von Oliver S. (oliverso)


Bewertung
0 lesenswert
nicht lesenswert
S. Landolt schrieb:
> Und aus dem Datenblatt lässt es sich herauslesen, mit ein
> wenig Mühe.

Na ja, man kann da alles mögliche hineininterpretieren. Da steht:

"The OCR2x Register access may seem complex, but this is not case. When 
the double buffering is enabled, the
CPU has access to the OCR2x Buffer Register, and if double buffering is 
disabled the CPU will access the OCR2x
directly."

Da steht natürlich nicht, daß bei einem Mode-Wechsel (der ein Normal- 
und kein Sonderfall ist) Buffer und Register synchronisiert werden, es 
steht aber auch nicht da, daß dies nicht geschieht. Das wäre aber 
durchaus erwähnenswert.

Statt dessen stehen breit und ausführlich die eigentlich nicht 
erwähnenswerten Fälle drin, daß ein Compare-Match bei einen Wert größer 
TOP niemals triggert, oder daß ein ein neuer Top-Wert kleiner als der 
aktuelle Zählerstand erst im nächsten Timerzyklus triggert.

Oliver

von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
S. Landolt schrieb:
> Und aus dem Datenblatt lässt es sich herauslesen, mit ein
> wenig Mühe.

Mit am erstaunlichsten finde ich daran, dass der OCR2A Wert (falsch?) 
auslesbar ist!

OCR2A  = 0;
PWM mode aktivieren
OCR2A  = 200;
Compare Match aktivieren

Danach:
Beim  OCR2A auslesen bekommt man die 200 gereicht.
Obwohl der Timer mit einem OCR2A == 0 arbeitet.

Das scheint mir dann doch schon sehr gemein zu sein.
Und hätte ein Sprüchlein im Datenblatt verdient.

: Bearbeitet durch User
von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
> hätte ein Sprüchlein im Datenblatt verdient

Vielleicht dieses hier?
"When the double buffering is enabled, the CPU has access to the OCR2x 
Buffer Register ..."
Betonung auf 'Buffer-'.

"Gemein" oder nicht, ich kann nichts dafür und kann's auch nicht ändern.

von Oliver S. (oliverso)


Bewertung
0 lesenswert
nicht lesenswert
Arduino Fanboy D. schrieb:
> Compare Match aktivieren

Offiziell heisst der CTC.

S. Landolt schrieb:
> "Gemein" oder nicht, ich kann nichts dafür und kann's auch nicht ändern.

Sacht ja keiner. Aber im CTC-Modus hat die CPU direkten Zugriff aufs 
Register, liest da 200, der Timer arbeitet aber mit 0. Das ist nicht 
einfach nur im Datenblatt ungünstig beschrieben oder gemein, daß ist ein 
Fehler.

Oliver

: Bearbeitet durch User
von S. Landolt (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Okay, eben ausprobiert, und - Arduino Fanboy & Oliver S., ich sei, 
gewährt mir die Bitte ...: Dass im CTC-Modus, also einem ungepufferten, 
beim Auslesen nicht der aktuelle Stand von OCR2A zurückgegeben wird, 
betrachte auch ich als (gemeinen) Fehler.

von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
S. Landolt schrieb:
> gewährt mir
Gewährt!

---------

Ich beantrage den Namen "Ugly timer trap" für diesen doch sehr seltsamen 
Effekt.

: Bearbeitet durch User
Beitrag #5784863 wurde von einem Moderator gelöscht.
von Christian J. (Firma: privat) (christianj)


Bewertung
0 lesenswert
nicht lesenswert
Weiss von euch Arduino Experten jemand wie man den Serial.print auf eine 
andere Funktion umleitet? Der geht ja auf die Hardware Uart. Oder eine 
vergleichbare Funktion aufsetzt? Ich verwende nur 2 Möglichkeiten

serial.print("Text...");
und
serial.print(buffer);

Ich habe aber eine IR Diode. Und das F Makro funktioniert nicht, wenn 
man zb nimmt

SendIRString(char* text)

Gibt es da einen Trick?

Bisher sieht es so aus


/* Sende einen 0 terminierten String per IR */
void SendIRString(char* text)
{
  while (*text)
    SendIRByte(*text++);

  SendIRByte(0);
}

IRLED ist mit einer Handykamera so eben zu sehen, die dimmt auch munter
drauf los.

ich könnte alles auf sprintf_P umschreiben aber das wäre eine irre 
Arbeit. Mache ich nur bei komplexen Ausgaben.

: Bearbeitet durch User
von Arduino Fanboy D. (ufuf)


Bewertung
1 lesenswert
nicht lesenswert
1
#include <Streaming.h> // findest du schon... ;-)
2
// ist nicht unbedingt nötig, erlaubt allerdings das Streaming
3
4
5
6
7
8
struct IrZeugs: Print
9
{
10
  virtual size_t write(uint8_t value)
11
  {
12
     SendIRByte(value);
13
     return 1;
14
  } 
15
};
16
17
18
IrZeugs ir;
19
20
21
22
23
void setup() 
24
{
25
26
 // Streaming
27
 ir << F("sende dieses ") << "jenes" << 42  << '\0';
28
29
30
 // alternativ:
31
 ir.print(F("sende dieses "));
32
 ir.print("jenes");
33
 ir.print(42);
34
 ir.write(0);
35
}
36
37
void loop() 
38
{
39
40
}

: Bearbeitet durch User
von Christian J. (Firma: privat) (christianj)


Bewertung
0 lesenswert
nicht lesenswert
Arduino Fanboy D. schrieb:
> #include <Streaming.h> // findest du schon... ;-)
> // ist nicht unbedingt nötig, erlaubt allerdings das Streaming

Funzt :-)
Nur ein Prototypen Problem. Arduino braucht ja keine und mich ärgert das 
etwas dass das System .h und .c da nicht so läuft. Ins .h kommt das 
Interface rein, ins .c der private Code.

: Bearbeitet durch User
von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Nur ein Prototypen Problem. Arduino braucht ja keine und mich ärgert das
> etwas dass das System .h und .c da nicht so läuft. Ins .h kommt das
> Interface rein, ins .c der private Code.

> Arduino braucht ja keine
Das stimmt so nicht wirklich!
Es macht sich selber welche, wenn du keine baust.
Das betrifft aber nur *.ino Dateien.

Keine *.c, *.cpp und *.h Dateien, die stehen in deiner Verantwortung.

Wieso überhaupt *.c?
Nimm *.cpp, dann musst du nicht die Extrawürste backen um mit dem C++ 
Rest klar zu kommen.

: Bearbeitet durch User
von Christian J. (Firma: privat) (christianj)


Bewertung
0 lesenswert
nicht lesenswert
C++.... ne, alter Hase bleibt bei C.

struct IrZeugs: Print
{
  virtual size_t write(uint8_t value)
  {
     SendIRByte(value);
     return 1;
  }
};

Aber dieses zweifach verschachtelte Konstrukt hier .... für mich nicht 
so ganz verstehbar. Funktioniert aber. irgendwie verwurstelt das 
Zeichenweise den Stream. Eine Funktion ist einem Struct, öfter mal was 
Neues.

Wie würde das aussehen, wenn in einem Rutsch die IR Ausgabe erfolgen 
soll und die normale Print Ausgabe dahinter? Ich baue mir einige 
komplexe Ausgaben mit sprintf_P zusammen und schiebe die nach buf rein. 
Wäre gut, wenn die Ausgabe meiner Bastelei auf Seriell und IR kommen 
würde. Einen Nachteil sehe ich nur darin, dass serial.print die Ausgabe 
per INT erledigt und dadurch IR beeinflusst würde, weil ich da zwingend 
die INT abschalten muss, damit die Zeiten stimmen. Aber man kann ja auch 
serial.flush() vorher aufrufen oder die IR Ausgabe vorziehen.

Die EEPROM Ausgabe liesse sich sicher auch verstreamen, nur müsste da 
dann ein zeiger mitlaufen aus das aktuelle Element.

Wäre schwer?

: Bearbeitet durch User
von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> C++.... ne, alter Hase bleibt bei C.
Dann musst du wohl von Arduino weg, oder deine Einstellung ändern.

Denn:
> Aber dieses zweifach verschachtelte Konstrukt hier .... für mich nicht
> so ganz verstehbar. Funktioniert aber.
Das ist naives, aber dennoch lupenreines C++.
Siehe: https://playground.arduino.cc/Code/Printclass/
So wie vieles, sehr vieles, SEHR *SEHR* vieles in der Arduino Welt.
Alles? Nee, aber sehr vieles!

Aber wenn du willst, dann mache dir deine Problem!
Soviele du möchtest.


Christian J. schrieb:
> Wäre schwer?
Nein, quasi nur ein Fingerschnippen...
;-) aber nicht für C++ Verweigerer ;-)

Tipp:
Von der EEPROM Klasse erben und das Print Interface implementieren.
Und ja, einen Index wird man mitführen müssen, und auch ein bisschen um 
die Grenzen kümmern, damit da keine ganz gruseligen Dinge passieren.
Oder besser sofort Stream implementieren... dann klappts auch mit dem 
Lesen.

: Bearbeitet durch User
von Christian J. (Firma: privat) (christianj)


Bewertung
0 lesenswert
nicht lesenswert
struct IrSend_t: Print {
  virtual size_t write(uint8_t value) {
     SendIRByte(value);
     Serial.write(value);
     return 1;
  }
};

von Oliver S. (oliverso)


Bewertung
0 lesenswert
nicht lesenswert
Arduino Fanboy D. schrieb:
> Auch wieder Mega2560 und 328P identisches Verhalten.

Hm....

Ich habe jetzt dann doch mal meinen Arduino Mega und den Logikanalysator 
aus dem Keller gekramt, um das mal nachzuvollziehen.
Alledings ohne Arduino-Framework, und ohne serielle Ausgabe.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
void setTimer2()         // CTC, Mode 2
5
{
6
  cli();
7
  // Interrupts ausschalten
8
  TCNT2 = 0;              // Reset Register
9
  OCR2A = 249;            // Compare
10
11
  TIMSK2 = (1 << OCIE2A);   // Compare Match A
12
  TCCR2A = (1 << WGM21);    // set Mode
13
  TCCR2B = (1 << CS20);     // Prescaler 1
14
  //TCCR2B = (1<<CS22);     // Prescaler 64
15
  sei();
16
  // Interrupts einschalten
17
}
18
19
ISR(TIMER2_COMPA_vect)          // Timer 2 Interrupt
20
{
21
  PINB = (1 << PB7); // toggle
22
}
23
24
int main(void)
25
{
26
  DDRB = 1 << PB7;
27
  setTimer2();
28
  while (1)
29
  {}
30
}

Ergebis: PB7 toggelt nicht mit 250kHz, sondern brav mit 32khz, so wie es 
auch sein sollte.

Oliver

von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Oliver S. schrieb:
> sondern brav mit 32khz, so wie es
> auch sein sollte.

Deinen Code habe ich jetzt nicht überprüft, kann ich mir aber lebhaft 
vorstellen.
Denn der Timer kommt im Mode 0 aus dem Reset.
Dann klappt das auch alles.

Lass den Timer mal kurze Zeit in einem PWM Mode laufen...
Und dann schalte um.
Du wirst sehen.....

: Bearbeitet durch User
von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
> Alledings ohne Arduino-Framework
Aber genau das war doch der springende Punkt! Dass nämlich der Timer ein 
'Vorleben' hatte, von dem man erstmal nichts weiß.

von Oliver S. (oliverso)


Bewertung
0 lesenswert
nicht lesenswert
Arduino Fanboy D. schrieb:
> Lass den Timer mal kurze Zeit in einem PWM Mode laufen...

Bitte sehr:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
5
void setTimer2_PWM()         // PWM, Mode 5
6
{
7
  cli();
8
  // Interrupts ausschalten
9
  TCNT2 = 0;              // Reset Register
10
  OCR2A = 249/4;            // Compare
11
12
  TIMSK2 = (1 << OCIE2A);   // Compare Match A
13
  TCCR2A = (1 << WGM20);    // set Mode
14
  TCCR2B = (1 << WGM22) | (1 << CS20);     // Prescaler 1
15
  sei();
16
  // Interrupts einschalten
17
}
18
19
void setTimer2_CTC()         // CTC, Mode 2
20
{
21
  cli();
22
  // Interrupts ausschalten
23
  TCNT2 = 0;              // Reset Register
24
  OCR2A = 249;            // Compare
25
26
  TIMSK2 = (1 << OCIE2A);   // Compare Match A
27
  TCCR2A = (1 << WGM21);    // set Mode
28
  TCCR2B = (1 << CS20);     // Prescaler 1
29
  sei();
30
  // Interrupts einschalten
31
}
32
33
ISR(TIMER2_COMPA_vect)          // Timer 2 Interrupt
34
{
35
  PINB = (1 << PB7); // toggle
36
}
37
38
int main(void)
39
{
40
  DDRB = (1 << PB6) | (1 << PB7);
41
  setTimer2_PWM();
42
  _delay_ms(100.0);
43
  PORTB |= (1 << PB6);
44
  setTimer2_CTC();
45
  while (1)
46
  {}
47
}

Tut, was es soll.

Oliver

: Bearbeitet durch User
von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Schreiben Sie mal in setTimer2_CTC
1
  OCR2A = 39;//249;            // Compare
Sehen Sie dann 200 kHz?

von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Oliver S. schrieb:
> void setTimer2_PWM()         // PWM, Mode 5
> {
>   cli();
>   // Interrupts ausschalten
>   TCNT2 = 0;              // Reset Register
>   OCR2A = 249/4;            // Compare
>
>   TIMSK2 = (1 << OCIE2A);   // Compare Match A
>   TCCR2A = (1 << WGM20);    // set Mode
>   TCCR2B = (1 << WGM22) | (1 << CS20);     // Prescaler 1
>   sei();
>   // Interrupts einschalten
> }
Hier mogelst du!
> OCR2A = 249/4;

Der Problemzustand ist
 OCR2A = 0;
Versuchs mal damit.

von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Das trifft es nicht ganz - der Trick ist, OCRA2 beim vorlaufenden PWM- 
größer zu machen als im späteren CTC-Modus, dann bleibt der zweite Wert 
im Pufferregister stecken.

von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
#include <util/atomic.h>
5
6
#define AtomicSection ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
7
8
9
void setTimer2_Arduino_PWM()         
10
{
11
  AtomicSection
12
  {
13
  // Arduino Startup Code Fragment
14
    TCCR2A = 1;
15
    TCCR2B = 4;
16
    TCNT2  = 51; // ca. zaehlerstand zum Zeitpunkt des Eintritts in die Main loop
17
    TIMSK2 = 0;
18
    OCR2A  = 0;
19
  }
20
}
21
22
void setTimer2_Reset()         
23
{
24
  AtomicSection
25
  {
26
    TCCR2A = 0;
27
    TCCR2B = 0;
28
    TCNT2  = 0; 
29
    TIMSK2 = 0;
30
    OCR2A  = 0;
31
  }
32
}
33
34
void setTimer2_CTC()         // CTC, Mode 2
35
{
36
  AtomicSection
37
  {
38
      TCNT2 = 0;              // Reset Register
39
      OCR2A = 249;            // Compare
40
    
41
      TIMSK2 = (1 << OCIE2A);   // Compare Match A
42
      TCCR2A = (1 << WGM21);    // set Mode
43
      TCCR2B = (1 << CS20);     // Prescaler 1
44
  }
45
}
46
47
ISR(TIMER2_COMPA_vect)          // Timer 2 Interrupt
48
{
49
  PINB = (1 << PB7); // toggle
50
}
51
52
int main(void)
53
{
54
  sei();
55
  DDRB = (1 << PB6) | (1 << PB7);
56
57
58
  PORTB |= (1 << PB6);
59
60
  while (1)
61
  {
62
    setTimer2_Arduino_PWM();
63
    _delay_ms(20.0);
64
    setTimer2_CTC(); // ca 250kHz
65
    _delay_ms(20.0);
66
    
67
    setTimer2_Reset();
68
    _delay_ms(20.0);
69
    setTimer2_CTC(); //ca 32kHz
70
    _delay_ms(20.0);
71
  }
72
}

von Oliver S. (oliverso)


Bewertung
0 lesenswert
nicht lesenswert
S. Landolt schrieb:
> Das trifft es nicht ganz - der Trick ist, OCRA2 beim vorlaufenden
> PWM-
> größer zu machen als im späteren CTC-Modus, dann bleibt der zweite Wert
> im Pufferregister stecken.

Scheint auch nicht ganz zuzutreffen, in meinem Beispiel oben ist er ja 
im PWM-Modus kleiner als im CTC-Modus. Mit viel kleineren Werten, nicht 
nur bei 0, wird er nicht übernommen. Vermutlich, wenn der Wert kleiner 
als der aktuelle Zählerstand ist.

Der Arduino-Code initialisiert den Timer 2 auf PWM 8 Bit mit OCRA=0. 
Warum die überhaupt da dran rumfummeln, keine Ahnung.

Ich muß mir das die Tage nochmals genauer anschauen. Dafür war mir der 
Sonntag Nachmittag dann doch zu schade.

Oliver

von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Oliver S. schrieb:
> Der Arduino-Code initialisiert den Timer 2 auf PWM 8 Bit mit OCRA=0.
> Warum die überhaupt da dran rumfummeln, keine Ahnung.

Im Startcode vorbereiten für PWM, damit das nicht in analogWrite() 
gemacht werden muss.
So wie auch andere Vorbereitungen für andere Arduino Features, wie 
millis(), delay() usw durchgeführt werden.

Das muss man hinnehmen, wenn man in der Welt unterwegs ist.

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]
  • [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.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

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