Forum: Mikrocontroller und Digitale Elektronik atmega324p TIMER0 INT0 verständnis Problem


von Harry (Gast)


Lesenswert?

Hallo zusammen,

bin gerade dabei wie schon in diesem Artikel beschrieben,

Beitrag "Carrera Digital 132 Zeitmessung / Rundenzähler"

eine Erfassung für Carrera digital1xx Autos zu realisieren.
Die Autos senden über eine IR LED 4000000/1024*256*n an einen 
Phototransistor. Soweit alles klar ich bekomme ein schönes 
rechtecksignal mit schönen Flanken.

Mein bisheriger Ansatz mit INT0 und Timer0 liefert jedoch nicht das 
gewünschte resultat.
1
#define F_CPU 16000000L
2
3
volatile int countSensorA = 0;
4
volatile char Buffer[20];
5
volatile int last = 0;
6
volatile int count = 0;
7
8
9
SIGNAL (INT0_vect)
10
{
11
  // steigende flanke kommt
12
  countSensorA++;
13
  // Timer0 in betrieb setzen
14
  if(countSensorA == 1)
15
  {
16
    TIMSK0 |= (1<<TOIE0);    
17
  }
18
}
19
20
21
SIGNAL (TIMER0_OVF_vect)
22
{
23
  // Timer overflow
24
  cli();
25
26
  // Timer ausschalten
27
  TIMSK0 &= ~(1<<TOIE0);
28
  if(countSensorA > 5)
29
  {
30
    // pulse anzeigen
31
    itoa( countSensorA, ( char* ) Buffer, 10 );
32
    Oputs(( char* ) Buffer);
33
    Oputs(" Pulse gezählt\r\n");
34
35
  }      
36
  // zähler auf 0
37
  countSensorA = 0;
38
    
39
  // bischen warten bis Auto weg ist
40
  _delay_ms(500);
41
  count = 0;
42
  sei();
43
}
44
45
46
void initIo()
47
{
48
  EICRA |= (1<<ISC01) | (1<<ISC00);  // Steigende Flanke von INT0 als auslöser
49
  EIMSK |= (1<<INT0);          // interruptmaske
50
  EIFR |= (1<<INTF0);
51
52
  // Timer 0 mit Prescaler 1024
53
    TCCR0B |= (1<<CS02) | (1<<CS00);     
54
}

Ist meine Ansatz der falsche oder hab ich was übersehen?

Gruß Harry

von Düsendieb (Gast)


Lesenswert?

Hallo Harry,
dein Ansatz ist unglücklich. so viel Programm packt man nie in einen 
Timerinterrupt und ein delay schon gar gar gar nicht.

Lass mit dem Timerinterrupt eine Variable meinetwegen in 0,1sec takt 
hochzählen und im Eingangsinterupt wird die Variable abgefragt und 
wieder auf Null gesetzt.


Axel

von STK500-Besitzer (Gast)


Lesenswert?

Harry schrieb:
> Die Autos senden über eine IR LED 4000000/1024*256*n an einen
> Phototransistor.

Eier, Kartoffeln? Liter?
Besitzt der MEGA324P eine Input-Capture-Unit?
Dann solltest du diese benutzen.

Harry schrieb:
> SIGNAL (TIMER0_OVF_vect)
>
> {
>
>   // Timer overflow
>
>   cli();
>
>
>
>   // Timer ausschalten
>
>   TIMSK0 &= ~(1<<TOIE0);
>
>   if(countSensorA > 5)
>
>   {
>
>     // pulse anzeigen
>
>     itoa( countSensorA, ( char* ) Buffer, 10 );
>
>     Oputs(( char* ) Buffer);
>
>     Oputs(" Pulse gezählt\r\n");
>
>
>
>   }
>
>   // zähler auf 0
>
>   countSensorA = 0;
>
>
>
>   // bischen warten bis Auto weg ist
>
>   _delay_ms(500);
>
>   count = 0;
>
>   sei();
>
> }

"cli" und vor allem "sei" haben in einer ISR nichts zu suchen!

Deine Messmethode muss man nicht verstehen, oder?
Kannst du die mal in Worten beschreiben?
Vielleicht auch noch ein paar Angaben zum Takt?

von Tommy T. (tommy2000)


Lesenswert?

Während das Programm in der ISR ist läuft der Zähler schon für den 
nächsten Timer weiter, d.h. du darfst in der ISR nur so viel Code 
ausführen wie zeitlich zwischen zwei Timer-Interrupts passt.

von Harry (Gast)


Lesenswert?

Die IR LED der Autos senden permanent mit 4MHz/(256*CARNUMBER)

IR LED Auto_1 sendet 15625 Hz
.
.
.
IR LED Auto_6 sendet 2604 Hz
IR LED Auto_7 sendet 2232 Hz

Mein Ansatz war Auto fährt über den Sensor INT0 wird ausgelöst, TIMER0 
startet, INT0 zählt bis TIMER0 Overflow erreicht und das soll dann das 
Messergebnis sein.

Gibt es AVR's mit 4 ICP Modulen?

Überarbeite gerade die ISR

Gruß Harry

von MWS (Gast)


Lesenswert?

Harry schrieb:
> TIMER0 startet,

Der startet aber nicht dadurch, dass man den Overflowinterrupt erlaubt, 
sondern der läuft dauernd bei Deinem Code.

Was passiert eigentlich, wenn mehrere Fahrzeuge gleichzeitig den Sensor 
durchfahren ?

> Gibt es AVR's mit 4 ICP Modulen?

XMega.

Aus dem momentanen Code zu urteilen wird das aber noch ein weiter Weg, 
zudem die XMega's um Einiges komplexer sind.

von Karl H. (kbuchegg)


Lesenswert?

Was willst du eigentlich messen?

Dein Programm, bzw. die Programmidee ist ziemlich wirr. Für mich ist da 
nicht wirklich erkennbar, was eigentlich gemessen werden soll.


ICP ist gut, aber ob du die Rundenzeit eines Autos auf +- 1 
Zehntausendstel Sekunden genau feststellst oder +- deren 2, spielt dann 
nicht wirklich die grosse Rolle. Das kriegt man in dem Fall sicherlich 
auch ohne ICP hin. Dafür allerdings auf 5 Kanälen, solange nur sicher 
gestellt ist, dass die Durchfahrten der Autos auseinandergehalten werden 
können.

von MWS (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Für mich ist da
> nicht wirklich erkennbar, was eigentlich gemessen werden soll.

Also der prinzipielle Wille ist aus dem Code schon erkennbar :D

von Harry (Gast)


Lesenswert?

MWS schrieb:
> Was passiert eigentlich, wenn mehrere Fahrzeuge gleichzeitig den Sensor
> durchfahren ?

Die Autos überfahren den Sensor. D.h. pro Spur nur 1 Auto am Sensor. 
Aber 4 Spuren.

Das ganze ist keine neue Erfindung von mir ich möchte es nur 
nachstellen.

Die Harware steht schon. Es wurde damals auch nicht mit ICP gemacht, 
sondern mit mega88 über PD2(INT0), PD3(INT1), PD7(AINT1) und PD4(T0).

Leider hat der Herr (www.slotbaer.de) keine Zeit mehr.

@Karl Heinz Buchegger
> Was willst du eigentlich messen.
Eine Anzahl von Pulsen(15,5 kHz - 2,2kHz) in einer bestimmten 
Zeit(5-10ms)

Gruß Harry

von Karl H. (kbuchegg)


Lesenswert?

Harry schrieb:

> @Karl Heinz Buchegger
>> Was willst du eigentlich messen.
> Eine Anzahl von Pulsen(15,5 kHz - 2,2kHz) in einer bestimmten
> Zeit(5-10ms)

Ah!
Du willst erst mal nur feststellen, welches Auto da über den Sensor 
gerauscht ist?

OK.
MWS hats ja schon gesagt.
Ein Timer wird nicht dadurch gestartet oder gestoppt, in dem du seinen 
Overflow Interrupt freigibst.

Bei dir läuft der Timer ständig, d.h. es ist bei dir mehr oder weniger 
zufällig, wieviele Pulse in der Zeit vom ersten Puls bis zum Overflow 
eintreffen.

Wenn der erste Puls kommt, musst du den Timer definiert bei 0 wegzählen 
lassen! Erst dann hast du deine definierte Zeit bis zum Overflow.

Oder du lässt deinen Timer überhaupt einfach durchlaufen und vergleichst 
die Zählerstände bei 2 aufeinanderfolgenden Interrupts.

Da du ja die Frequenzen kennst, musst du nicht aufs Hz genau messen. Ein 
kleiner Fehler spielt zur Fahrzeugerkennung keine große Rolle.

von STK500-Besitzer (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Oder du lässt deinen Timer überhaupt einfach durchlaufen und vergleichst
> die Zählerstände bei 2 aufeinanderfolgenden Interrupts.
manuelle ICP.. ;)

Karl Heinz Buchegger schrieb:
> Da du ja die Frequenzen kennst, musst du nicht aufs Hz genau messen. Ein
> kleiner Fehler spielt zur Fahrzeugerkennung keine große Rolle.

Es interessier ja auch nur die Periodendauer...

Wie schnell mag so ein Auto über den Fotosensor fahren?
2-3 Perioden?

Harry schrieb:
> Eine Anzahl von Pulsen(15,5 kHz - 2,2kHz) in einer bestimmten
> Zeit(5-10ms)

Auch eine Möglichkeit, aber auch das macht der Code oben sicher nicht.

von STK500-Besitzer (Gast)


Lesenswert?

Harry schrieb:
> Eine Anzahl von Pulsen(15,5 kHz - 2,2kHz) in einer bestimmten
> Zeit(5-10ms)

5ms sollten auf jeden Fall reichen. Das auto 7 hat mit seiner Frequenz 
eine Periodendauer von 0,5ms. Das wären für schon 10 Perioden.
Bei Auto 1 ist die Periodendauer nur noch 64µs lang - das wären dann 
entsprechend mehr Perioden/Impuls pro 5ms.

von Harry (Gast)


Lesenswert?

Ok besten Dank für eure Hilfe. Bau mal den Code entsprechend um und 
Poste in dann nochmal

Gruß Harry

von MWS (Gast)


Lesenswert?

Harry schrieb:
> Aber 4 Spuren.

Basierend auf Deinem momentanen Konzept (Messung über Torzeit) 
bräuchtest Du 4 unabhängige voneinander zu startende Timer, in HW hast 
Du die nicht, könnte man in SW bauen.

Oder in der ext. Int den Zähler sampeln und nach soundsoviel Differenz 
eine Messung als beendet betrachten, hat aber auch Nachteile.

Oder Periodenzeitmessung, wobei im worst-case bei 4 konkurrierenden 
Signalen, also 4 Autos gleichzeitig, eine ausreichend genaue Messung der 
Periodendauer stattfinden muss.

Zeit also sich über's später verwendbare Konzept Gedanken zu machen und 
dann den Code daraufhin ausgerichtet zu beginnen.

Harry schrieb:
> PD2(INT0), PD3(INT1), PD7(AINT1) und PD4(T0).

Unwahrscheinlich. Sinnvoll war Int1 & 2, als auch 2 der PCInts, für den 
M324 dann Int0-2 & ein PCInt, oder PCINT0-3.

von Harry (Gast)


Lesenswert?

MWS schrieb:
> Oder Periodenzeitmessung, wobei im worst-case bei 4 konkurrierenden
>
> Signalen, also 4 Autos gleichzeitig, eine ausreichend genaue Messung der
>
> Periodendauer stattfinden muss.

Das arbeite ich gerade aus. Dauert aber länger muss mir das erst mit DB 
erabeiten ;-)

Später werd ich das über die PCINT lösen.

mfg
Harry

von Karl H. (kbuchegg)


Lesenswert?

Harry schrieb:
> MWS schrieb:
>> Oder Periodenzeitmessung, wobei im worst-case bei 4 konkurrierenden
>>
>> Signalen, also 4 Autos gleichzeitig, eine ausreichend genaue Messung der
>>
>> Periodendauer stattfinden muss.
>
> Das arbeite ich gerade aus. Dauert aber länger muss mir das erst mit DB
> erabeiten ;-)

Aus dem Bauch heraus würde ich mal folgende Fragen angehen:

Bei den gegebenen Auto-Frequenzen und den möglichen Vorteilern, wie weit 
kann ein Zähler in der Zeit zwischen 2 Pulsen zählen. Und zwar bei allen 
auftretenden Frequenzen.

Ziel ist es, den Vorteiler zu finden, so dass der Timer in der Zeit 
zwischen 2 Pulsen nicht "überläuft" UND die festgestellten 
Timer-differenz-werten sich bei den jeweiligen Autofrequenzen stark 
genug unterscheiden, so dass sie eindeutig und sicher 
auseinandergehalten werden können.

Ich denke weiters, dass du mit dem 8-Bit Timer nicht weit kommen wirst. 
Ein Zählumfang von 0 bis 255 ist nun mal nicht besonders gross, wenn man 
~15khz von ~2khz nur anhand der Periodendauer auseinanderhalten soll UND 
in die Zählerstände nach Möglichkeit die Overflows nicht eingerechnet 
werden sollen (vereinfacht das Handling insgesamt).

von Harry (Gast)


Lesenswert?

@Karl Heinz Buchegger
  danke für den Hinweis hab mal etwas gerechnet:

FCPU=16Mhz, prescaler=0, 16MHz/256 = 62,5kHz 1/62,5kHz = 16us

[CAR1] kürzeste Periode 1/15,62kHz = 64us /16us = 4
[CAR7] längste  Periode 1/2,232kHz = 448us/16us = 28
[CAR6]                               384us/16us = 24


Sollte ich alles richtig verstanden haben würde das so funktionieren 
oder?

mfg
Harry

von Karl H. (kbuchegg)


Lesenswert?

Harry schrieb:
> @Karl Heinz Buchegger
>   danke für den Hinweis hab mal etwas gerechnet:
>
> FCPU=16Mhz, prescaler=0, 16MHz/256

welches ist der nächst kleinere Prescaler? Hast du zb 64 zur Verfügung?

> [CAR1] kürzeste Periode 1/15,62kHz = 64us /16us = 4
> [CAR7] längste  Periode 1/2,232kHz = 448us/16us = 28
> [CAR6]                               384us/16us = 24

> Sollte ich alles richtig verstanden haben würde das so funktionieren
> oder?

Könnte hinkommen. Da dein Timer durchläuft, sollte man auch noch einen 
Zählfehler von +-1 mit einkalkulieren. du hast dann anstellt von 28 und 
24, die Werte 27 und 25. Sollte noch unterscheidbar sein, aber dann darf 
nicht mehr viel passieren.
Wenn du zb einen Prescaler von 64 hast, dann hast du 4-fache Werte.

  112   zu  96

da jetzt noch einen Zählfehler von +-1 eingerechnet, sind wir bei 111 zu 
97 und da gibt es dann schon einen viel schöneren Grenzwert in der 
Mitte, zu dem die erwarteten Ergebnisse einen ordentlichen Abstand 
haben.


112 ist immer noch nicht Ende der Fahnenstange. Bei einem Vorteiler von 
32 wäre der Wert 224. Hast du 32 zur Verfügung?

von Harry (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> welches ist der nächst kleinere Prescaler? Hast du zb 64 zur Verfügung?

Ich verwende doch schon den kleinsten prescaler = 0

Du meinst ich soll den 16bit Timer nehmen und mich da mit den prescaler 
an meinen Bereich nähern?

Ich hab 0, 8, 64, 256, 1024 als Prescaler.

von spess53 (Gast)


Lesenswert?

Hi

>Ich hab 0, 8, 64, 256, 1024 als Prescaler.

Beim Timer2 hättest du auch 32.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

Harry schrieb:
> Karl Heinz Buchegger schrieb:
>> welches ist der nächst kleinere Prescaler? Hast du zb 64 zur Verfügung?
>
> Ich verwende doch schon den kleinsten prescaler = 0

1. Bei einem Prescaler von 0 steht der Timer.

Trotzdem.
Mein Fehler.

von Harald M. (_harry_)


Lesenswert?

>1. Bei einem Prescaler von 0 steht der Timer.
Ja klar mein Fehler div/0 und so ;-)

Hab alles mal etwas umgeschrieben aber jetzt kommt nur noch unsinn:
1
//#define F_CPU  16000000
2
#define LOOP  1
3
4
#include <stdio.h>
5
#include <stdlib.h>
6
#include <avr/io.h>
7
#include <avr/interrupt.h>
8
#include "usart/usart.h"
9
10
volatile unsigned long int startTime = 0;
11
volatile unsigned long int stopTime = 0;
12
volatile unsigned long int count = 0;
13
unsigned long int newWert = 0;
14
15
void display();
16
void initIo();
17
18
SIGNAL (INT0_vect)
19
{
20
  startTime = stopTime;
21
  stopTime = TCNT0;
22
  count++;
23
}
24
25
//SIGNAL (TIMER0_OVF_vect)
26
//{
27
//  timerOVF++;
28
//}
29
30
int main()
31
{
32
  unsigned long int lastWert = 0;
33
  
34
  initIo();
35
  sei();
36
37
  while(LOOP)
38
  {    
39
    if(count == 2)
40
      cli();
41
42
    lastWert = newWert;
43
44
    if(stopTime < startTime)
45
      newWert = 256 + stopTime - startTime;
46
    else
47
      newWert = stopTime - startTime;
48
    
49
    stopTime = 0;
50
    startTime = 0;
51
52
    if(lastWert != newWert)
53
      display();
54
    
55
    sei();
56
  }
57
  return 0;
58
}
59
60
void display()
61
{
62
  char Buffer[20];
63
  itoa( newWert, ( char* ) Buffer, 10 );
64
  Oputs(( char* ) Buffer);
65
  Oputs(" \r\n");
66
}
67
68
void initIo()
69
{  
70
  InitUart();
71
  Oputs("UART Init 9600 Baud\r\n");
72
  EICRA |= (1<<ISC01) | (1<<ISC00);  // Steigende Flanke von INT0 als auslöser
73
  EIMSK |= (1<<INT0);          // Interruptmaske
74
  EIFR |= (1<<INTF0);
75
    TCCR0B |= (1<<CS00);           // Timer 0 mit Prescaler 0 (16000000/0)/256 Hz = 62,5kHz = 1/62,5kHz s = 16us2604
76
//  TIMSK0 |= (1<<TOIE0);        // Timer0 Interrupt einschalten
77
}

Kann mir wer sagen ob ich da was grundlegendes falsch mach?

MfG
Harry

von Volkmar D. (volkmar)


Lesenswert?

Zumindest 2 Dinge fallen mir auf:
- nach dem "if(count == 2)" fehlen die Klammern für einen Block
- count wird nicht zurückgesetzt.

Und ein paar Kleinigkeiten:
- stopTime und startTime braucht nicht auf 0 gesetzt werden, da die 
beiden Variablen eh bei jedem Interrupt gesetzt werden.
- Im Interrupt würde ich die Start und Stop-Zeiten nur dann setzen, wenn 
es auch nötig ist.
- Nicht auf Gleichheit (count == 2) prüfen, besser auf größer gleich 
prüfen, vermeidet bei Problemfälle

Damit ergeben sich folgende Änderungen:
1
SIGNAL (INT0_vect)
2
{
3
  if(count<2) {
4
    startTime = stopTime;
5
    stopTime = TCNT0;
6
    count++;
7
  }
8
}
...
1
    if(count >= 2)
2
    {
3
      cli();
4
5
      lastWert = newWert;
6
7
      if(stopTime < startTime)
8
        newWert = 256 + stopTime - startTime;
9
      else
10
        newWert = stopTime - startTime;
11
    
12
      count = 0;
13
14
      if(lastWert != newWert)
15
        display();
16
    
17
      sei();
18
    }

von Harald M. (_harry_)


Lesenswert?

Morgen,

Volkmar Dierkes schrieb:
> Zumindest 2 Dinge fallen mir auf:
>
> - nach dem "if(count == 2)" fehlen die Klammern für einen Block
>
> - count wird nicht zurückgesetzt.

Danke für deine hilfe habe ich selbst schon bemerkt und den rest hab ich 
angepasst. Leider ohne sichtlichem Erfolg:

DEBUG AUSGABE:
96 result, 2 count, 0 startTime, 96 stopTime
250 result, 2 count, 96 startTime, 90 stopTime

Das ist die Ausgabe der 15,6kHz Quelle! (result sollte eigentlich 4 
sein. 4*16 = 64us)

Jetzt stellt sich mir die frage, ob der uC überhaupt mitkommt. In dem 
Projekt vom slotbaeren wurden nämlich 20MHz Takt benutzt.

Macht es sinn den 16bit timer zu nehmen um mehr "Timer counts" zu 
bekommen?
Ich glaub nicht darann, dass das nur mit ICP zu lösen ist!

mfg
Harry

von Karl H. (kbuchegg)


Lesenswert?

> volatile unsigned long int startTime = 0;

runter mit den Datentypen.
uint8_t reicht völlig. Du hast es nur mit 8 Bit Zahlen zu tun!


Und wenn du das hast, braucht es auch die Unterscheidung hier nicht
1
      if(stopTime < startTime)
2
        newWert = 256 + stopTime - startTime;
3
      else
4
        newWert = stopTime - startTime;

ein simples
1
     newWert = stopTime - statTime;
reicht völlig aus.

von Karl H. (kbuchegg)


Lesenswert?

> Das ist die Ausgabe der 15,6kHz Quelle! (result sollte eigentlich 4
> sein. 4*16 = 64us)


Jetzt muss ich mir doch deine Berechnungen dazu mal genauer ansehen. 
Rein gefühlsmässig kann das nicht stimmen.

....

Ich weiss schon, wo der Fehler ist.

Du hast hier gerechnet:

> FCPU=16Mhz, prescaler=0, 16MHz/256 = 62,5kHz 1/62,5kHz = 16us
>
> [CAR1] kürzeste Periode 1/15,62kHz = 64us /16us = 4

Dein Timer produziert OVERFLOWS mit einer Frequenz von 62.5kHz! Die 
Division durch 256 (die ich ursprünglich für einen Vorteiler gehalten 
hatte) ist der Zählumfang des Timers.
D.h. von einem Overflow zum nächsten vergehen 16us.

d.h. (in der weiteren Rechnung): der Timer zählt nicht bis 4, sondern 
bei dieser Eingangsfrequenz produziert der Timer 4 Overflows!


Ist mir doch gleich so spanisch vorgekommen, dass ein Zähler bei einem 
Vorteiler von 1 und lächerlichen EIngangsfrequenzen grade mal bis 4 
zählen soll. Ich hätt doch auf mein Gefühl vertrauen sollen.

Also: entweder das Zählsystem auf die Zählung von Overflows umstellen 
oder dem Timer einen Vorteiler verpassen (idealerweise 256, wenn du hast 
- dann ändert sich an den Zahlen nichts).

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz Buchegger schrieb:

> Also: entweder das Zählsystem auf die Zählung von Overflows umstellen
> oder dem Timer einen Vorteiler verpassen (idealerweise 256, wenn du
> hast).


Hab grad hochgescrollt. Du sagtest, es gäbe unter anderem 256 und 64.
64 wäre besser. Die Zahlen werden schöner.

von Karl H. (kbuchegg)


Lesenswert?

Du hast es irgendwie mit den unsigned long. Das ist scheinbar dein 
Lieblingstyp :-)

> volatile unsigned long int count = 0;

volatile uint8_t count = 0;

Bei dieser Variablen  ist es ganz besonders wichtig, dass du sie atomar 
lesen und schreiben kannst! einen unsigned long kannst du nicht atomar 
schreiben/lesen. einen uint8_t schon.


Generell: Du willst immer den kleinsten Datentyp benutzen, mit dem sich 
alles ausgeht. Wenn irgendwie möglich einen uint8_t. Das ist sozusagen 
des AVR Leib und Liebingsdatentyp. Damit kann er wunderbar umgehen. 
Alles andere ist für ihn mächtig Aufwand. Und: man kann sich damit auch 
mächtig Probleme einhandeln, die nicht so offensichtlich sind wie 
Overflows in Berechnungen.


(*) atomar: in einem Rutsch. Die Operation ist unteilbar, nicht 
unterbrechbar.

von Karl H. (kbuchegg)


Lesenswert?

> Jetzt stellt sich mir die frage, ob der uC überhaupt mitkommt.

Logisch nachdenken und mal überschlagsmässig abschätzen:
Der µC läuft mit 16Mhz. Deine Eingangsfrequenz ist ca. 16kHz. Das ist 
ein Faktor von ungefähr 1000.

Ein Faktor von 1000 kann man veranschaulichen:

Du zählst vor dich hin: 1, 2, 3, 4, 5 ....
wobei du ca. jede Sekunde immer um 1 weiterzählt.

Und alle Viertelstunde rufe ich: Halt, wie weit bist du gekommen.

Du hast also den 'Stress' mit jeder Sekunde und ich hab genügend Zeit, 
dass ich mir in der Zwischenzeit die Quantentheorie reinziehe. Deinen 
Zählerstand zwischendurch wieder mal abfragen und mal kurz umrechnen 
mach ich mit Links nebenher. Sozusagen in der Werbepause :-)

von Harald M. (_harry_)


Lesenswert?

@Karl Heinz Buchegger
Besten dank für die Erklärungen die haben mir jetzt echt weitergeholfen!

Hier das Resultat der geistigen Arbeit.
1
...
2
volatile uint8_t startTime = 0;
3
volatile uint8_t stopTime = 0;
4
volatile uint8_t sensor0 = 0;
5
...
6
SIGNAL (INT0_vect)
7
{
8
  sensor0++;
9
  if(sensor0<2)
10
  {
11
    startTime = stopTime;
12
    stopTime = TCNT0;
13
  }
14
}
15
16
int main()
17
{
18
  uint8_t result = 0;
19
  uint8_t lastResult = 0;
20
21
  TCCR0B |= (1<<CS01) | (1<<CS00);    // Timer0 mit Prescaler 64 (16000000/64) -> 4us/step
22
23
  init();
24
  sei();
25
26
  while(1)
27
  {    
28
    if(sensor0 >= 2)
29
    {
30
      sensor0 = 0;
31
32
      lastResult = result;
33
      result = stopTime - startTime;
34
      
35
      // prüfen ob letzter Messwert und neuer Messwert inerhalb der Toleranz sind
36
      if( ( (lastResult - result) < TOLERANZ) && ((lastResult - result) > - TOLERANZ) )
37
      {
38
        if(lastResult != result) 
39
          display(carId(result), 0);
40
      }
41
    }
42
  }
43
  return 0;
44
}
45
...

Funktioniert hoffentlich auch noch mit 4 Sensoren.

Allen beteiligten ein herzliches Dankeschön!!

MfG
Harry

von Volkmar D. (volkmar)


Lesenswert?

Hallo,

ich sehe noch Folgendes. In der ISR solltest Du den Befehl "sensor0++;" 
noch in das if mit reinziehen. Sonst könnte es bei extremer Auslastung 
des Prozessors passieren das die Variable sensor0 überläuft und wieder 
bei 0 beginnt.
1
  if(sensor0<2)
2
  {
3
    sensor0++;
4
    startTime = stopTime;
5
    stopTime = TCNT0;
6
  }

Desweiteren sollte das Zurücksetzen der Variablen "sensor0 = 0;" erst 
nach der Übernahme der Werte startTime und stopTime erfolgen:
1
    if(sensor0 >= 2)
2
    {
3
      lastResult = result;
4
      result = stopTime - startTime;
5
6
      sensor0 = 0;
Sonst kann es passieren, daß die ISR schon wieder zuschlägt und die 
Werte verändert bevor sie ausgelesen wurden.

von Karl H. (kbuchegg)


Lesenswert?

Und noch ein 2.tes Problem

Du musst unter allen Umständen verhindern, dass dir hier in dieser 
Sequenz
1
    if(sensor0 >= 2)
2
    {
3
      sensor0 = 0;
4
5
      lastResult = result;
6
      result = stopTime - startTime;

Der Interrupt zuschlägt und dir 'unter dem Hintern' die Werte verändert. 
Das darf auf keinen Fall passieren. Auch dann nicht, wenn gerade die 
Berechnung von
   stopTime - startTime
im Gange ist. Es muss sichergestellt sein, dass beide Werte aus 
derselben Messung stammen.

Dazu gibt es 3 Möglichkeiten
* entweder du kapselst das alles in eine cli/sei INterruptsperre
* oder du nutzt dein Wissen aus, dass dir die ISR die Werte nicht
  verändern wird, solange sensor0 größer/gleich 2 ist.
  Hier wäre es daher wichtig, dass das 0-Setzen von sensor0 als letztes
  erfolgt, nachdem sicher gestellt ist, dass du die stopTime bzw
  startTime nicht mehr brauchst.
* oder du verlagerst die Differenzberechnung überhaupt in die ISR.
  Das bischen Zeitreserve hast du dort allemal.

Das alles wird sich zum jetzigen Zeitpunkt noch nicht bemerkbar machen. 
Aber wenn dein Programm dann mal ein anderes Timingverhalten hat und die 
Zeiten enger werden, dann kann das zu einem Problem werden.


Edit: Hat sich mit Volkmars Analyse überschnitten.

von Harald M. (_harry_)


Lesenswert?

Volkmar Dierkes schrieb:
> ich sehe noch Folgendes. In der ISR solltest Du den Befehl "sensor0++;"
> noch in das if mit reinziehen. Sonst könnte es bei extremer Auslastung
> des Prozessors passieren das die Variable sensor0 überläuft und wieder
> bei 0 beginnt.
>
>   if(sensor0<2)
>   {
>     sensor0++;
>     startTime = stopTime;
>     stopTime = TCNT0;
>   }

ok neues Rätsel wenn ich das so mache klapt das micht mehr.
Aber warum?

--> OK Kein Rätsel es hat vorher nur andere Messwerte geliefert!!

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.