Forum: Mikrocontroller und Digitale Elektronik ATmega, C, GCC, Warteschleife, ICF1-Flag innerhalb 40ms gesetzt


von AC (Gast)


Lesenswert?

Hallo zusammen,

bin Anfänger also alles ganz langsam.

Ich programmiere eine Frequenzmessung in C (Atmel Studio 7, GCC).

Dazu muss ich das ICF1-Flag abfragen ob dieses innerhalb 40ms gesetzt 
wurde.
Ist dies nicht der Fall, Ausgabe "A"
Ist dies der Fall, ICR1-Wert in eine Variable und auf das nächste 
ICF1-Flag warten.

Leider habe ich keine Ahnung wie ich die "Warteschleife" umsetzen soll.
An sich müsste es Sinngemäß so funktionieren:

if (TIFR1 == 0x27 && Zeit<40ms)
{Anweisung}

Ich kann da auch keine for-Schleife nehmen die 1ms pro Durchlauf dauert, 
das verfälscht mein Ergebnis.
Und es darf keine ISR benutzt werden...soll eben alles in der 
Hautschleife passieren.

Danke für eure Hilfe
AC

von Verbieter (Gast)


Lesenswert?

AC schrieb:
> Und es darf keine ISR benutzt werden...soll eben alles in der
> Hautschleife passieren.

Wer verbietet das?

von AC (Gast)


Lesenswert?

Da das ganze Programm sehr Zeitkritisch wird soll dort keine ISR benutzt 
werden. Die Frequenzmessung soll in der Hauptschleife geschehen. Dieser 
jemand der das "verbietet" hat das ganze, wie oben beschrieben, in 
BASCOM programmiert und ich muss jetzt diesen Teil aber in C umsetzen.

von Verbieter (Gast)


Lesenswert?

AC schrieb:
> Da das ganze Programm sehr Zeitkritisch wird

Das kann nicht sein, wenn es erlaubt ist mehrere Millisekunden in der 
Hauptschleife auf ein Flag aktiv zu warten.

von AC (Gast)


Lesenswert?

tja, was soll ich sagen...ich habe die frequenzmessung schon mit der ISr 
Timer1 Capt gemacht und da zittert der Wert etwas (bei eingestellten 
55Hz zwischen 55,018Hz und 54,863Hz).
Und ich soll es jetzt wie oben geschrieben programmieren...also nochmal:

Leider habe ich keine Ahnung wie ich die "Warteschleife" umsetzen soll.
An sich müsste es Sinngemäß so funktionieren:

if (TIFR1 == 0x27 && Zeit<40ms)
{Anweisung}

Jemand eine Idee?

von Bernd (Gast)


Lesenswert?

AC schrieb:
> tja, was soll ich sagen...ich habe die frequenzmessung schon mit der ISr
> Timer1 Capt gemacht und da zittert der Wert etwas (bei eingestellten
> 55Hz zwischen 55,018Hz und 54,863Hz).
> Und ich soll es jetzt wie oben geschrieben programmieren...also nochmal:
>
> Leider habe ich keine Ahnung wie ich die "Warteschleife" umsetzen soll.
> An sich müsste es Sinngemäß so funktionieren:
>
> if (TIFR1 == 0x27 && Zeit<40ms)
> {Anweisung}
>
> Jemand eine Idee?

Suche dir eine andere Aufgabe.

von Verbieter (Gast)


Lesenswert?

AC schrieb:
> Und ich soll es jetzt wie oben geschrieben programmieren

Es ist völliger Unsinn das nicht mit einer ISR zu machen.
Dagegen spricht auch eine Zeitkritikalität des restlichen Programms 
nicht.
Wenn eine Interrupt-Unterbrechung von wenigen Mikrosekunden dein 
Programm stört, dann ist es falsch.

von Peter D. (peda)


Lesenswert?

AC schrieb:
> tja, was soll ich sagen...ich habe die frequenzmessung schon mit der ISr
> Timer1 Capt gemacht und da zittert der Wert etwas (bei eingestellten
> 55Hz zwischen 55,018Hz und 54,863Hz).

Dann rechne mal nach, wie hoch Dein Quantisierungsfehler überhaupt ist.
Der Witz am Cature ist nämlich, daß es von der Interruptlatenz 
unabhängig ist. Aber besser als ein Timertakt kann es nicht auflösen. 
Wenn das nicht reicht, mußt Du den Timertakt erhöhen oder über mehrere 
Perioden messen.

von AC (Gast)


Lesenswert?

Bevor ich die Aufgabe bekommen habe, habe ich es, wie folgt umgesetzt 
wobei der Wert z.B bei eingestellter frequenz vonn 55Hz zwischen 
55,018Hz und 54,863Hz zittert:
1
Timer Initialisierung:
2
TCCR1A = 0x00;        //Timer1 Normal Mode
3
  TCCR1B = 0x45;        //Input Capture Edge (Positive Flanke); Kein Vorteiler
4
  TIMSK1 |= (1<<ICIE1);    //Input Capture Interrupt aktiviert  
5
  //TIMSK1 |= (1<<TOIE1);    //Timer Overflow Interrupt aktiviert
6
7
ISR:
8
ISR(TIMER1_CAPT_vect)          //Interrupt Service Routine Timer1 - Capture
9
{
10
  if (messflag ==1)
11
    return;
12
  
13
  if (flanke_nr == 0)
14
  {
15
    start_wert = ICR1;
16
    flanke_nr = 1;  
17
  }
18
  
19
  else if (flanke_nr == 1)
20
  {
21
    end_wert = ICR1;
22
    flanke_nr = 0;
23
    messflag = 1;  
24
  }
25
}
26
27
Schleife:
28
      float frequenz = 0.0;          //Ergebnis Frequenzmessung
29
      char buffer[20];            //Buffer für die Page 2 Ausgabe
30
      
31
      if (messflag == 1)            //Messung durchgeführt und bereit zur Ausgabe
32
      {          
33
                  
34
      //*****************Berechnung Frequenz************************
35
      if (end_wert <= start_wert)
36
      {
37
      frequenz = ( 65536 + end_wert ) - start_wert;
38
      frequenz = 20000000 / frequenz;
39
      frequenz = frequenz / 1024;
40
      }
41
      else
42
      {
43
      frequenz = end_wert - start_wert;
44
      frequenz = 20000000 / frequenz;
45
      frequenz = frequenz / 1024;  
46
      }
47
      //_delay_ms(500);
48
      //**********Ausgabe Frequenz***************
49
      if (frequenz < 45 || frequenz > 65)
50
      {
51
        char_x=2;//0-128
52
        char_y=7; //0-8
53
        display_write("Out of Range");
54
      }
55
      
56
      else
57
      {
58
      display_clear();
59
      char_x=2;//0-128
60
      char_y=7; //0-8
61
      sprintf (buffer, "Frequenz: %4.3f Hz",frequenz);      //Ausgabe Frequenz
62
      display_write_str(buffer);  
63
      }
64
      
65
      messflag =0;                        //Messung ausgegeben          
66
      }

Controller ist ein Atmega1284P mit 20Mhz Takt. Die Frequenz wird von 
einem FreqGen (Velleman) der per USB angeschlossen wird eingespeist.
Ist der Code so in Ordnung oder könnte das Zittern der Werte irgendwo im 
Code verursacht werden?

von AC (Gast)


Lesenswert?

Sehe gerade bei TCCR1B = 0x45; habe ich noch den alten Kommentar 
gelassen. Vorteiler ist 1024.

von c-hater (Gast)


Lesenswert?

Peter D. schrieb:

> Dann rechne mal nach, wie hoch Dein Quantisierungsfehler überhaupt ist.

Das sollte er tatsächlich dringend mal tun, völlig klar.

> Der Witz am Cature ist nämlich, daß es von der Interruptlatenz
> unabhängig ist.

Nein, leider natürlich nicht wirklich. Klar, das Capture selber passiert 
unabhängig von allen Aktivitäten der MCU. Aber: Der Code muss auf ein 
ICP-Ereignis reagieren, bevor das nächste eintritt, sonst ist der 
Capturewert schlicht verloren und es wird Müll bei der Messung 
herauskommen, weil erst der nächste (oder übernachste...u.s.w.) 
Capturewert zur Messung verwendet wird.

Das gilt übrigens völlig unabhängig davon, ob der Code zur Messung in 
einer ISR agiert oder in main(), da sowohl die Antwortzeit in main() als 
auch in einer ISR unmittelbar von den Sperrzeiten aller anderen 
Interrupts im System abhängt.

Deswegen ist es natürlich sehr vermessen, zu sagen, das Capture wäre von 
der Interruptlatenz unabhängig...

von Wolfgang (Gast)


Lesenswert?

AC schrieb:
> Die Frequenz wird von einem FreqGen (Velleman) der per USB
> angeschlossen wird eingespeist.

Und wieviel Jitter hat der?

von Rolf M. (rmagnus)


Lesenswert?

AC schrieb:
> Bevor ich die Aufgabe bekommen habe, habe ich es, wie folgt umgesetzt
> wobei der Wert z.B bei eingestellter frequenz vonn 55Hz zwischen
> 55,018Hz und 54,863Hz zittert:

>       frequenz = frequenz / 1024;

Soll man daraus die nicht ganz unwichtige Erkenntnis ziehen, dass der 
Timer womöglich mit einem Prescaler von 1024 läuft? Das hieße, er läuft 
mit einer Frequenz von ca. 19,5 kHz und kann damit die Periodendauer in 
Schritten von ca. 51 µs ermitteln. Deine 55 Hz haben eine Periodendauer 
von ca. 18 ms, was etwa 355 mal so viel ist. Das heißt, wenn deine 
Messung nur um einen Timer-Tick schwankt, reicht das schon aus, um 
deinen angezeigten Wert um etwa 0,15 Hz schwanken zu lassen, was 
ziemlich genau deiner Beobachtung entspricht. Mit anderen Worten: Die 
Auflösung deiner Messung ist einfach nicht höher.

von S. Landolt (Gast)


Lesenswert?

Der Vorteiler ist mit 1024 zu groß, folglich der Zählwert zu klein: er 
wird derzeit 355 oder 356, und daraus werden nach obiger Rechnung eben 
55.0176 bzw. 54.8631.

von Rolf M. (rmagnus)


Lesenswert?

Mal ganz davon abgesehen kümmert sich der Code nicht um atomare Zugriffe 
oder darum, was passiert, wenn während der Ausgabe ein Interrupt 
auftritt. Da kommt dann in manchen Fällen vermutlich auch mal 
zwischendrin irgendein Unsinn raus.

von Dieter F. (Gast)


Lesenswert?

AC schrieb:
> Schleife:

Du nutzt nicht zufällig die Arduino-Umgebung? Da werden Timer durchaus 
auch mit anderen Aufgaben betraut - ohne das Du es siehst.

Falls nicht - was macht Dein Programm denn sonst noch so?

von Rolf M. (rmagnus)


Lesenswert?

S. Landolt schrieb:
> er wird derzeit 355 oder 356, und daraus werden nach obiger Rechnung eben
> 55.0176 bzw. 54.8631.

Wie einfach man es doch schreiben kann. ;-)
Meins wirkt dagegen so kompliziert...

von S. Landolt (Gast)


Lesenswert?

Ein Vorteiler von 8 wäre optimal, wenn nur diese 55 Hz gemessen werden 
sollen.

von AC (Gast)


Lesenswert?

Danke für die Erklärung das es schon mal mit der Auflösung zu tun haben 
kann.

Wenn ich jetzt den Vorteiler auf 1 setze und die Zeile
1
frequenz = frequenz / 1024;
 in der Berechnung rausnehme, dann werden bei 50Hz, 2932,121 Hz 
angezeigt. Die erste Stelle vor dem Komma und die Nachkomma stellen 
zittern etwas.

Hab ich einen Fehler in der Berechnung?
Dann würde ich Timer1 ohne Vorteiler laufen lassen.

Auf dieser "seite" (Display) wird nur die Frequenz ausgegeben und auf 
einer anderen "seite" 2 ADC Werte. Die Display Seiten schalte ich mit 
einem Taster um.

von AC (Gast)


Lesenswert?

Die Frequenzrange ist von 45Hz bis 65Hz. davor und danach wird Out of 
Range ausgegeben.

von S. Landolt (Gast)


Lesenswert?

Der Timer1 hat 16 bit: 2^16=65536; mit Vorteiler=1 und 50 Hz ergibt sich 
bei 20 MHz aber ein Zählwert von 400000.

von Peter D. (peda)


Lesenswert?

c-hater schrieb:
> Der Code muss auf ein
> ICP-Ereignis reagieren, bevor das nächste eintritt

Das habe ich bei 55Hz einfach mal als gegeben vorausgesetzt.

von AC (Gast)


Lesenswert?

d.h bei 400000 Zählschritten macht er über 6 Overflows und ich addiere 
nur 1?

Wenn ich den Vorteiler auf 8 setze dann dauert ein zählschritt 400ns, 
also bei 20ms (50Hz) sind es 50000. Schlimmstenfalls bei 45Hz 55555,56 
zähltakte...wäre dann ein overflow?

von Rolf M. (rmagnus)


Lesenswert?

Solange du sicher weniger als die 65536 brauchst, die der Zähler an 
Schritten hat, passt alles.

von AC (Gast)


Lesenswert?

Yeah...danke euch!

Habe jetzt den Vorteiler auf gesetzt und bei 45Hz werden 44,996Hz und 
bei 65Hz werden 64,994Hz angezeigt. Und wenn überhaupt dann zuckt nur 
die letzte Nachkommastelle. das ist dann ne Abweichung von nichtmal 
0,01% das muss reichen...anstatt das bereits programmierte zu optimieren 
habe ich mich verrückt machen lassen.

Danke nochmal

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.