MEGA328P -> Timer1 Compare Match A

Gast #6043491
Lesenswert?

Guten Nabend,

eine kleine Frage.. Bin noch relativ neu in dem Thema "Timer".

Wenn ich jetzt meinen Timer1_CompA so konfiguriere, dass er jede 
Millisekunde in die ISR läuft..
Wie folgt konfiguriert..:
1
/**< Waveform Generation Mode Bits */
2
#define _TMR0_MODE0          ( ! ( 1 << WGM00 | 1 << WGM01 ) ) // Normal
3
#define _TMR0_MODE2          ( 1 << WGM01 ) // CTC
4

5
#define _TMR1_MODE0          ( ! ( 1 << WGM13 | 1 << WGM12 | 1 << WGM11 | 1 << WGM10 ) ) // Normal
6
#define _TMR1_MODE4          ( 1 << WGM12 ) // CTC
7

8
#define _TMR2_MODE0          ( ! ( 1 << WGM21 | 1 << WGM20 ) ) // Normal
9
#define _TMR2_MODE2          ( 1 << WGM21 ) // CTC
10

11
/**< Prescaler Mode Group Position */
12
#define _PRESCALER_0        ( 0b001 << 0 )
13
#define _PRESCALER_8        ( 0b010 << 0 )
14
#define _PRESCALER_64        ( 0b011 << 0 )
15
#define _PRESCALER_256        ( 0b100 << 0 )
16
#define _PRESCALER_1024        ( 0b101 << 0 ) // Sind für alle Timer (0..2) gleich
17

18
{ .uiCnt = 124     , .uiCSxx = _PRESCALER_64   , .uiWGMxx = _TMR1_MODE4 }, // 1ms   @8MHz
19

20
TCCR1A  = psTab->uiWGMxx & 0x03;
21
TCCR1B  = psTab->uiWGMxx & 0x18;
22
TCCR1B  |= psTab->uiCSxx;
23
OCR1A  = psTab->uiCnt;

Sollte er jede Millisekunde in die ISR laufen.. Nun toggle ich eine LED 
und messe das ich eine Amplitude von ~520us habe..
Was verstehe ich falsch?
Gast #6043512
Lesenswert?

Seltsames Bitgefummel. Was da effektiv bei heraus kommt ist:

> TCCR1A = 0
> TCCR1B = 11  (WGM12, CS11, CS10)
> OCR1A = 124

Das ist der CTC Modus mit Prescaler 64.

> messe das ich eine Amplitude von ~520us habe..
> Was verstehe ich falsch?

Ja, Amplituden haben eine Höhe, nicht Zeit. Die meinst wohl eine 
Pulsbreite.

Bei 16 MHz dauert ein Timer-Takt 1/16000000*64 = 4µs

124 ∙ 4µs = 496µs

Das passt also ungefähr. Oder hast du eine andere Taktfrequenz als 
Systemtakt?
Gast #6043525
Lesenswert?

> Bei 16 MHz dauert ein Timer-Takt 1/16000000*64 = 4µs
> 124 ∙ 4µs = 496µs
> Das passt also ungefähr.

Zum einen sind es 125, zum anderen kämen 16 MHz aus einem Quarz, wären 
also hinreichend genau.
Gast #6043598
Lesenswert?

Also hier ist mal die Initalisierung die ich aufrufe
1
extern inline enum eTimerError Timer1CompAInit( const sTimer16Config_t *psTab , void (*pFncCallback)(void) )
2
{
3
  cli(); /**< Vorsichtshalber Interrupts global sperren */
4

5
  TCCR1A  = psTab->uiWGMxx;
6
  TCCR1B  = psTab->uiWGMxx;
7
  TCCR1B  |= psTab->uiCSxx;
8
  OCR1A  = psTab->uiCnt;
9
  
10
  if ( pFncCallback == NULL )
11
  {
12
    sei();
13
    return ERROR_TIMER_NO_ADDRESS;
14
  }else
15
  {
16
    pvTimerCallback[CALLBACK_TIMER1_COMPA] = pFncCallback;
17
  }
18
  
19
  _ENABLE_OCIE1A;
20

21
  sei();
22
  
23
  return ERROR_TIMER_OK;
24
}

Das ist die Konfiguration
1
const sTimer16Config_t sTimer1TovSettings[] = 
2
{
3
  #if (F_CPU == 1000000)
4
    { .uiCnt = 65535   , .uiCSxx = _PRESCALER_0    , .uiWGMxx = _TMR1_MODE0 }, // 1µS   @1MHz  
5
    { .uiCnt = 65526   , .uiCSxx = _PRESCALER_0    , .uiWGMxx = _TMR1_MODE0 }, // 10µS  @1MHz
6
    { .uiCnt = 65436   , .uiCSxx = _PRESCALER_0    , .uiWGMxx = _TMR1_MODE0 }, // 100µS @1MHz
7
    { .uiCnt = 65411   , .uiCSxx = _PRESCALER_8    , .uiWGMxx = _TMR1_MODE0 }, // 1ms   @1MHz
8
  #endif
9

10
  #if (F_CPU == 8000000)
11
    { .uiCnt = 65528   , .uiCSxx = _PRESCALER_0    , .uiWGMxx = _TMR1_MODE0 }, // 1µS   @8MHz
12
    { .uiCnt = 65456   , .uiCSxx = _PRESCALER_0    , .uiWGMxx = _TMR1_MODE0 }, // 10µS  @8MHz
13
    { .uiCnt = 65436   , .uiCSxx = _PRESCALER_8    , .uiWGMxx = _TMR1_MODE0 }, // 100µS @8MHz
14
    { .uiCnt = 65411   , .uiCSxx = _PRESCALER_64   , .uiWGMxx = _TMR1_MODE0 }, // 1ms   @8MHz
15
  #endif
16

17
  #if (F_CPU == 16000000)
18
    { .uiCnt = 65520  , .uiCSxx = _PRESCALER_0    , .uiWGMxx = _TMR1_MODE0 }, // 1µS   @16MHz
19
    { .uiCnt = 65376  , .uiCSxx = _PRESCALER_0    , .uiWGMxx = _TMR1_MODE0 }, // 10µS  @16MHz
20
    { .uiCnt = 65336  , .uiCSxx = _PRESCALER_8    , .uiWGMxx = _TMR1_MODE0 }, // 100µS @16MHz
21
    { .uiCnt = 65286  , .uiCSxx = _PRESCALER_64   , .uiWGMxx = _TMR1_MODE0 }, // 1ms   @16MHz
22
  #endif  
23
};
Gast #6043610
Lesenswert?

Stefan F. schrieb:
> Wir wollten etwas compilierbares haben. Keine Lust mehr, weiter zu
> raten.
>
> Wie hast du denn verifiziert, ob dein Mikrocontroller wirklich auf 8MHz
> läuft?

Was bringt Dir ausführbarer Code wenn Du ihn nicht testen kannst? Ich 
habe genau diese Routine genutzt um den Timer zu initalisieren. Mehr 
steht nicht drin.

Den Takt habe ich in den Fuses nachgeschaut. Dort ist auch kein DIV8 
etc. aktiviert.
Gast #6043612
Lesenswert?

TimerNoob schrieb:

> Also hier ist mal die Initalisierung die ich aufrufe

> extern inline enum eTimerError Timer1CompAInit( const sTimer16Config_t
> *psTab , void (*pFncCallback)(void) )
[...]
>   TCCR1A  = psTab->uiWGMxx;
>   TCCR1B  = psTab->uiWGMxx;

Wer auch immer das verbrochen hat, es kann nur kompletter Bullshit 
sein...
Gast #6043614
Lesenswert?

c-hater schrieb:
> TimerNoob schrieb:
>
>> Also hier ist mal die Initalisierung die ich aufrufe
>
>> extern inline enum eTimerError Timer1CompAInit( const sTimer16Config_t
>> *psTab , void (*pFncCallback)(void) )
> [...]
>>   TCCR1A  = psTab->uiWGMxx;
>>   TCCR1B  = psTab->uiWGMxx;
>
> Wer auch immer das verbrochen hat, es kann nur kompletter Bullshit
> sein...

Achja.. Warum?
Gast #6043623
Lesenswert?

TimerNoob, deine Codefragmente sind immer noch unvollständig und 
widersprechen sich.

c-hater schrieb:
>>   TCCR1A  = psTab->uiWGMxx;
>>   TCCR1B  = psTab->uiWGMxx;
> Wer auch immer das verbrochen hat, es kann nur kompletter Bullshit
> sein...

Das kommt noch dazu.

TimerNoob schrieb:
> Achja.. Warum?

Weil man nicht in zwei unterschiedliche Konfigurationsregister den 
gleichen Wert schreiben will. Das kann so nicht beabsichtigt gewesen 
sein.

Weiter oben wurde psTab->uiWGMxx wenigstens noch mit unterschiedlichen 
Bitmasken gefiltert, was zwar funktioniert, aber auch sehr verwirrend 
ist. Merkt man auch daran, dass du deinen eigenen Code nicht verstehst. 
Das ist bei diesem Code kein Wunder.

Lege die Karten (den Quelltext) offen auf den Tisch oder höre auf, 
unsere Hilfsbereitschaft zu missbrauchen.
Beitrag #6043633 wurde von einem Moderator gelöscht.
Gast #6043926
Lesenswert?

Ich bin den Hinweisen bzw. den Fragen zum Thema Quarz nochmal nach 
gegangen..

In den Fuses steht er auf 8MHz, wenn ich ihn auf den internen RC Oszi. 
schalte, läuft er deutlich langsamer und das mit den Timing von einer 
Millisekunde passt.. Das heißt im Endeffekt er steht bei den Fuses auf 
8MHz und wird übertaktet.. (ist ein China Arduino!)..
Auf dem Quarz kann man natürlich keine Frequenz ablesen.
Gast #6043967
Lesenswert?

TimerNoob schrieb:
> Anbei mal ein Foto.

Wo ist jetzt dein Problem?

Du hast 500µs Intervalle programmiert und sie auch bekommen. Das zeigt 
dein Oszilloskop an. immer abwechselnd 500µs LOW und 500µs HIGH.

TimerNoob schrieb:
> In den Fuses steht er auf 8MHz, wenn ich ihn auf den internen RC Oszi.
> schalte, läuft er deutlich langsamer

Moment mal. Der interne Oszillator hat 8 MHz. Mit der CLKDIV8 Fuse kann 
er der Takt (egal ob intern oder extern) durch 8 geteilt werden.

Wenn der Mikrocontroller mit dem internen Oszillator nur halb so schnell 
läuft, wie mit dem externen, dann hat der externe Oszillator 
logischerweise die doppelte Taktfrequenz, also 16 MHz.

16 MHz ist bei Arduino Modulen die übliche Bestückung. Meistens ist das 
bei den billigen Modulen übrigens nur ein Keramik Resonator - weniger 
genau als ein Quarz.

Und das passt zu deinem zuerst genannten Code und deinem Messergebnis.

Ergo: Da ist kein Problem. Wenn du andere Intervalle wolltest, musst du 
wie gesagt den Wert im OCR1A Register ändern.
Gast #6043975
Lesenswert?

TimerNoob schrieb:
> Ich bin den Hinweisen bzw. den Fragen zum Thema Quarz nochmal nach
> gegangen..
>
> In den Fuses steht er auf 8MHz, wenn ich ihn auf den internen RC Oszi.
> schalte, läuft er deutlich langsamer und das mit den Timing von einer
> Millisekunde passt.. Das heißt im Endeffekt er steht bei den Fuses auf
> 8MHz und wird übertaktet.. (ist ein China Arduino!)..
> Auf dem Quarz kann man natürlich keine Frequenz ablesen.
Die Fuses kann man nicht auf 8MHz extern einstellen.
5V Arduinos sind mit 16MHz Resonatoren ausgestattet.
Die billigen China Modelle auch mal mit Quarz.
Gast #6044114
Lesenswert?

Eine korrekte und vor allem vollständige Antwort würde umfangreich, 
sicher nicht viel kürzer als das, was im Datenblatt steht; also dort 
nachlesen.
  Von mir nur soviel: man wählt den Oszillator aus, diverse interne 
RC-Oszillatoren sowie Oszillatoren, die mit extern anzuschließendem 
Quarz (oder Resonator) betrieben werden; bei letzteren gilt es noch, 
hinreichend gut an die Frequenz anzupassen.
Gast #6044147
Lesenswert?

Beo Bachta schrieb:
> Übertakten bedeuted betreiben ausserhalb (oberhalb) der
> spezifizierten Frequenzgrenze (die liegt beim 328P bei
> 16 MHz bzw 20 MHz).

Die "Frequenzgrenze" ist Spannungsabhängig! Im DB befindet sich ein 
schönes Diagramm, das den sicheren Arbeitsbereich veranschaulicht. Die 
Maximal vom Hersteller spezifizierte Frequenz beträgt 20 Mhz. Die 16Mhz 
auf zB. sämtlichen Arduino-boards kann damit erklärt werden, dass viele 
ältere AVRs nur höchstens 16Mhz unterstützen.

TimerNoob schrieb:
> CLK Fuses [...] Was bewirken diese Einstellungen?

Datenblatt!
Vielleicht hilft dir auch eine Gui zum Fuses setzen, wie der im Atmel 
Studio weiter?
Gast #6044212
Lesenswert?

TimerNoob schrieb:
> Wozu stellt man genau die CLK Fuses ein? Wenn man 8MHz eingestellt hat
> ihn dann aber auch mit 16MHz betreiben kann?

Nochmal: Man kann nicht 8MHz einstellen.

Du kannst da drei Sachen einstellen:

1) Die Quelle, das ist entweder der interne 128 kHz Oszillator, oder der 
interne 8 MHz Oszillator oder eine externe Quelle.

2) Die Startup Time (SUT) gibt dem Oszillator Zeit, sich einzuschwingen.

3) Mit CLKDIV8 kann die Taktfrequenz (egal aus welcher Quelle) durch 8 
geteilt werden.

Guck Dir das mal im Engbedded Fuse Calculator an (Anhang).
Angehängte Dateien:

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren