Timer zählt nur bis zu Hälfte

OP #1538951
Lesenswert?

Hallo,

ich habe mich heute ein bisschen in die Timer in Verbindung mit 
Interruptfunktionen beschäftigt. Ich würde gerne eine Softwarelösung zum 
generieren von zwei PWM Signale realisieren. Ich habe dazu die CTC 
Methode verwändet. Der Code hänge ich unten an.

Im Einsatz ist ein ATMEGA8 an einem 16MHz Quarz.
Zum Berechnen des OCR Wertes habe ich folgende Formel benutzt:

OCRnx = e ^ (0,00330082*iBit+5,86166)

Wobei iBit für einen Wert vom AD Wandler steht und somit zwischen 
0-1024bit liegt. Die Formel habe ich über Gnumeric ermittelt um den 
Bereich von 1,5kHz bis 4,5kHz abzudecken. Über die Formel zum Berechnen 
der Freqenzen mit Hilfe folgender Formel hat auch in Exel exakt 
gestimmt. Jedoch bekomme ich bei dem unten angehängten Programm exakt 
die hälfte der Frequenz. Obwohl der Prescaler auf 1 eingestellt ist.

Freq = (F_CPU/(Prescaler*(OCRnx+1)))

Wie man sie auch hier findet: 
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR#CTC-Betriebsart_.28Clear_Timer_on_Compare_Match.29

Mir ist kein offensichtlicher Fehler aufgefallen vielleicht habt ihr ja 
noch einen Tipp für mich.
1
volatile uint8_t flag;
2

3
int OCR(int iBit)
4
{
5
  float f_e, f_func_var1, f_func_var2, f_OCR_res, f_OCR_zres;
6
  int i_OCR_res;
7
  f_e = 2.718282;
8
  f_func_var1 = 0.00330082;
9
  f_func_var2 = 5.86166;
10
  f_OCR_zres  = ((f_func_var1 * iBit) + f_func_var2);
11
  f_OCR_res   = (float) pow(f_e, f_OCR_zres);
12
  f_OCR_res  += 0.5;
13
  i_OCR_res   = (int) f_OCR_res;
14
  return i_OCR_res;
15
}
16

17
float frequenz(int i_OCR)        
18
{
19
  float f_freq_res;  
20
  f_freq_res = (CPU_T/(PRESCALE*(i_OCR+1)));
21
  f_freq_res = (f_freq_res / 1000);
22
  return f_freq_res;
23
}
24

25

26
ISR (TIMER1_COMPB_vect)//(SIG_OUTPUT_COMPARE1B)
27
{
28
  if (flag == 1) {
29
    flag = 0;
30
    PORTB |= (1<<PB1);
31
    PORTB &= ~(1<<PB2);
32
  }
33
  else {
34
    flag = 1;
35
    PORTB &= ~(1<<PB1);
36
    PORTB |= (1<<PB2);
37
  }
38
}
39
int main(void)
40

41
{
42
        ...
43
        //PortB Einstellen
44
  DDRB |= (1 << DDB1) | (1 << DDB2); //PIN PB1 und PB2 als Ausgang
45
  //Timer Einstellen
46
  TCCR1B = 0x00;
47
  TCCR1B |= (1<<WGM12); //Timer1 mit Auflösung 2¹⁶ in CTC Modus
48
  TCCR1B |= (1<<CS10);  //Prescaler auf 1
49
  TIMSK  |= (1<<OCIE1B);// Output Compare Match Interrupt Enable
50
  sei();
51
        ...
52
        //Hauptprogramm starten
53

54
  while(1){
55
        ...
56
        cli();
57
        OCR1A = (uint16_t) iOCR;
58
        sei();
59
        ...
60
}
Gast #1538973
Lesenswert?

Vermutung: Pro ISR erzeugst du nur eine Halbperiode deines Signals. Die 
ISR müsste also doppelt so oft aufgerufen werden, um eine ganze Periode 
zu erzeugen.

Tipp: Bei Fragen den Quellcode und erwartete/gemessene Werte für ein 
komplettes Beispiel angeben. Dann kann man das im Simulator nachstellen 
und braucht nicht zu vermuten.

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