Forum: Mikrocontroller und Digitale Elektronik Timer Capture - zwei Signale "parallel"


von Maciek (Gast)


Lesenswert?

Hallo,

hab folgendes Problem: möchte mit meinem 90S4433 bei zwei Signalen 
jeweils die Abstände zwischen zwei steigenden Flanken "parallel" 
erfassen. So parallel ,dass man sie mehr oder weniger gleichzeitig auf 
einem LCD Display anzeigen kann.
Jetzt hab ich nur einen Pin für Timer Capture :-( Signal 1 läuft an dem 
Port und es klappt bestens.
Ein schnelles Umschalten zwischen den Signalen per Multiplexer klappt 
nicht (weiss nicht warum).Jetzt dachte ich mir für das zweite Signal: 
lass den Timer0 laufen , löse einen externen Interrupt bei steigender 
Flanke von Signal2 aus, sichere den Zählerstand und fertig. Klappt aber 
auch nicht :-(
Hat jemand eine Idee wie man die zwei Signale doch messen kann ?

Danke,

Maciek

von crazy horse (Gast)


Lesenswert?

das klappt schon mit dem externen Int. Auch kannst du dafür Timer1 
nehmen, wenn du ihn durchlaufen lässt.
Der externe Int liest den Zählerstand des Timer1 und schreibt den in 
eine Variable, beim nächsten wird wieder der Zählerstand gelesen und die 
Differenz der beiden Werte ist die Zeit zwischen den Ereignissen. 
Genauso verfährst du beim ICP-Int, nur dass nicht der Zählerstand, 
sondern das ICP-Register gelesen wird. Differenz bilden, fertig. Solange 
der Timer max. 1mal überläuft, brauchst du dich auch darum nicht 
kümmern, das Ergebnis stimmt. Für längere Zeiten kannst du auch die 
Timer1-OV mitzählen und so aus der 16bit-Zahl eine 24bit-Zahl machen 
(oder auch noch mehr bei Bedarf).
Die Zeit, die von EX0 bis zum tatsächlichen Lesen der Zählerstandes 
vergeht (Anspringen der ISR, Sichern von Registern/PSW, Lesen des 
Zählers) verursacht keinen Fehler, da jedesmal diesselbe Verzögerung 
entsteht. Kritisch kann es dann werden, wenn während des EX0-Ereignisses 
ein anderer Int läuft, dann wird eine längere Zeit gemessen.

von Werner Hoch (Gast)


Lesenswert?

Hallo Maciek,

Welche Zeit vergeht zwischen den Signalflanken,

Ist die Zeit kleiner als 20 Takte kannst du das IMHO vergessen.

ansonsten:
ICP = Signal1 XOR Siganl2
Digitalpin = Signal1

Jetzt kannst du am Digitalpin die Flankenrichtung bestimmen und am ICP 
erhälst du einen Impuls.

In der ISR des ICP wertest du einmal die Steigende und einmal die 
fallende Flanke aus und bildest die Differenz.

@horse
Der ISR-Aufruf dauert nicht immer gleich lang, durch die 
unterschiedliche Ausführungszeit der verschiedenen Befehle entsteht ein 
fehler von +-3 Takten.

mfg
werner

von crazy horse (Gast)


Lesenswert?

vom Aufruf bis zum Lesen dauert es immer gleich lang, ein Fehler kann 
entstehen, bis der Aufruf erfolgt, insofern hast du recht, +-3 Takte 
stimmt aber nicht, sondern 1-3 Takte.
Aber wollen wir mal keine Erbsen zählen.

von Werner Hoch (Gast)


Lesenswert?

@horse

Ich denke die +- 3Takte sind für eine Zeitmessung richtig.

Die AVR-Befehle dauern zwischen 1 und 4 Takten.

folgende Fälle sind möglich:

   INT0              INT1               Fehler
1. Flanke +1Takte, 2. Flanke +1Takte    Durchschnitt
2. Flanke +4Takte, 2. Flanke +1Takte    -3 Takte
3. Flanke +1Takte, 2. Flanke +4Takte    +3 Takte
4. Flanke +4Takte, 2. Flanke +4Takte    Durchschnitt

Bei der Verwendung von ICP für die eine und einem normalen Interrupt für 
die andere Flanke geb ich dir recht: 0-3 Takte
Fehler zwischen verschiedenen Messungen.

Ist natürlich Erbsenzählerei, aber wenn wir schon dabei sind:
Muß man eigentlich nicht sogar noch einen oder gar zwei Takte dazuzählen 
weil das Ereignis ja sowohl am Anfang des uC-Taktes als auch am Ende des 
uC-Taktes auftreten kann?

uC_clk: 000000000000111111111111111100000000000001111111111
Ereignisübernahme: ^^^^                        ^^^^
event1: 000000000011111111111111111111111111111111111111111
event2: 000000000000001111111111111111111111111111111111111

event2 wird erst einen Takt später übernommen, obwohl Die Differenz 
zwischen event1 und event2 nahezu null werden kann.

PS: Dieser Fehler tritt auch bei der ICP Methode auf.

mfg
werner

von Maciek (Gast)


Lesenswert?

Hallo,

  danke für die Antworten ,werde ich gleich ausprobieren. Wenn noch 
jemand Lust hat :
Wieso klappt das hier nicht? Es soll bei jedem Interrupt der Zählerstand 
gesichert werden.
Die Interrupts kommen abwechselnd von zwei verschiedenen Signalen 
(maximal 160Hz).Zwischen den Signalen wird mit einem MUX
gewechselt. Kommt ein Interrupt, so werden die Interrupts erstmal global 
abgeschaltet ,eine Berechnung
durchgeführt ,der MUX auf das andere Signal geschaltet und die 
Interrupts global wieder angeschaltet.
So immer hin und her.Der Mux arbeitet richtig.
In der Praxis klappt es nicht. Es werden abenteuerliche Werte angezeigt 
,die ich mir überhaupt nicht erklären kann.
So ändert die Variable für Signal2 ihre Werte obwohl Signal2 keinen 
Interrupt ausgelöst hat. Bin ratlos ,probiere
jetzt mal Eure Tipps.

Grüsse,

Maciek


SIGNAL(SIG_INPUT_CAPTURE1)
{
  TIMER_L = TCNT1L;                                           // Unteren 
Bits des Zählers retten
  TIMER_H = TCNT1H;                                           // Oberen 
Bits des Zählers retten
  TCNT1H=0; TCNT1L=0;                                         // Zähler 
auf Null setzen
  interrupt=1;
  overflow=0;                                                 // Kein 
overflow
}
.
.
.
while(1)
{
  if(interrupt)
    {
      asm volatile("cli");                                    // 
Interrupt global aus

      if(bit_is_set(PORTB,2))                                 // MUX 
Pin1
  {
    RPM = (unsigned int)(60*(31250/(float)((TIMER_H*256)+TIMER_L)));
    outp (0x03,PORTB);                                  // MUX auf Pin0 
schalten
    delay50us();
  }
      else                                                    // MUX 
Pin0
  {
    KMH = (unsigned int)(62500/(float)((TIMER_H*256)+TIMER_L));
    outp (0x07,PORTB);                                  // MUX auf Pin0 
schalten
    delay50us();
  }
      interrupt = 0;
      asm volatile("sei");                                     // 
Interrupt global an

    }
.
.
.

von Maciek (Gast)


Lesenswert?

Hallo nochmal,

habs jetzt mit dem externen interrupt (INT1) versucht.
Geht nicht :-( Hab probeweise an ICP gemessen und dann an INT1
(mit nur einem Signal) Die Interruptroutinen machen in beiden Fällen das 
gleiche. Die Messung an ICP klappt an INT1 bekomme ich abwechseln ca 
25500 und 9200.
Wenn das an INT1 klappen würde gäbe es doch keinen Unterschied zu pin 
ICP. Ist INT1 vielleicht langsamer ?
Tips?
Ich probier jetzt noch den zweiten Tip mit dem XOR. Den Digitalpin 
brauche ich am festzustellen welches Signal grade anklopft , oder ? Nur 
, wie kann ich mir das merken ,wenn gleichzeitig ein Interrupt kommt und 
kurz danach der Impuls wieder weg ist?

Grüsse,

Maciek

von Werner Hoch (Gast)


Lesenswert?

Hallo Maciek,

[2 Signale mit 160 Hz]
mir scheint wir haben uns mißverstanden:

Du willst 2 Frequenzen von 2 verschiedenen Signalen messen?

Ich habe verstanden, du willst die Differenz zwischen 2 Signalflanken 
messen.
Also Flanke Signal1 bis Flanke Signal2.


Du solltest dir Gedanken über deinen Programmablauf machen. Ich zeichne 
das mal auf:

Signal1: _______----------------__________________-----------
Signal2: ____________-----------------_________________-------

Beschr:_________1_2__3_____A______________________4_5__6_____

Der Multiplexer steht auf Signal1.
1.
- Durch die Steigende Flanke wird TCNT1 in die ICR1 Register kopiert.
- In deiner ISR kopierst du TCNT1 in die TIMER-Variable, löschst TCNT1, 
interrupt wird gesetzt.

Welcher Wert steht eigentlich in TIMER? TIMER enthält die Zeit die seit 
dem letzten
Löschen vergangen ist (steigende Flanke von Signal2 bis steigende Flanke 
Signal1).

2.
Wir haben die ISR verlassen und sind jetzt im Hauptprogramm.
- Du deaktivierst alle Interrupts.
- Du berechnest RPM
(bist du sicher das TIMER den Wert enthält den du haben wolltest? s.o.)
- Du schaltest den Mux auf Signal2 um.
- Du aktivierst alle Interrupts

Was würdest du sagen, wieviel Zeit ist seit dem Zeitpunkt 2 vergangen?
Du hast immerhin eine höchst komplizierte Berechnung mit float 
durchgeführt.
Sind wir auf der Zeitachse noch for (3) oder schon etwa bei (A)?

Angenommen wir sind bereits bei (A)? Und du hast die Interrupts 
reaktiviert.
Das Interrupt Flag ist ist zum Zeitpunkt (3) gesetzt worden und die ISR 
Routine
wird zum Zeitpunkt (A) ausgeführt.
Damit enthält TIMER den wert, der zwischen (1) und (A) vergangen ist.

Den Rest kannst du ja selber durchspielen.


uint16_t timer

SIGNAL(SIG_INPUT_CAPTURE1)
{
 if (interrupt)
  return;
 if (ERSTEFLANKE)
  timer= ICR1;         /* Wert speichern */
  ERSTEFLANKE=0;
 else {
  timer= ICR1-timer    /* Zeitdifferenz ermitteln */
  interrupt=1
  ERSTEFLANKE=1;
 }
};



while(1)
{
  if(interrupt)
  {
  INTERRUPT ABSCHALTEN;
  if (MUX_AUF_SIGNAL1){
     RPM = (uint32_t) 60*31250/timer;
     MUX_AUF_SIGNAL2;
  }
  else {
     KMH = (uint32_t) 62500/timer;
     AUF_MUX1_UMSCHALTEN;
  }
  ICP_INTERRUPT LÖSCHEN;

  interrupt = 0;
  asm volatile("sei"); // Interrupt global an
  }
}

von Maciek (Gast)


Lesenswert?

Hallo Werner,

vielen Dank ,dass du dir die Mühe gemacht hast :-) Jetzt sehe ich auch 
,dass mein Programm nicht laufen konnte. Kommt davon wenn man sich freut 
,dass es mit einem Signal funktioniert und nicht merkt ,dass es 
eigentlich Zufall war ;-)
Ich hatte den Timer und den Interrupt gar nicht verstanden...
Werde morgen mal meine Signalquelle bemühen (ist ein Auto) und schauen 
wie es klappt.
Es sollen zwei Frequenzen gemessen werden. Wenn eine Flanke mal verloren 
geht oder die Messung nicht 100% genau ist,ist auch nicht schlimm.

Danke und Grüsse,

Maciek (dersichjetzthoffentlichmehrgedankenmacht)

von Werner Hoch (Gast)


Lesenswert?

Na ja, jeder steht mal auf dem Schlauch.

wie kannst du dir sonst erklären, daß ich die Zeit zwischen den 
steigenden Flanken der beiden Signale messen wollte obwohl du im 
Ursprungsposting deine Anforderungen eigentlich klar angegeben hattest?

mfg
werner
life is stupid

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.