Forum: Mikrocontroller und Digitale Elektronik Signal auswerten


von Heiko (Gast)


Lesenswert?

Hallo!

Bin gerade auf diese Seite gestoßen und hoffe ihr könnt mir helfen.

Ich habe ein Signal welches drei untersciedliche Impulse enthält. Der 
erste Impuls ist 10µs lang, der zweite 20µs und der dritte 50µs. Diese 
drei Impulse werden alle 100ms wiederholt.

Nun möchte ich dieses Signal mit einem Mikrocontroller auswerten. Dazu 
benutze ich den Atmega48 in der Programmierspreache C. Als Idee ist mir 
in den Kopf gekommen, einen Flankenzähler mit dem externen Interuppt zu 
machen. Bei einer steigenden Flanke wird dann eine Variable hochgezählt. 
Nur ist mir nicht ganz klar, wie ich die länge der Impulse bestimmen 
kann, damit ich auch weiß welches Signal gerade ausgewertet wird.

Für ein paar Tips wäre ich echt dankbar.

Grüße

Heiko

von johnny.m (Gast)


Lesenswert?

Imho klassischer Fall für Input Capture. Schau Dir mal die 
Funktionsweise der Input Capture Unit des Timers 1 an. Damit kannst Du 
sehr präzise Impulslängen messen.

von fieser Rahul (auch Oskar genannt) (Gast)


Lesenswert?

Benutz die ICP-Einheit!

von fieser Rahul (auch Oskar genannt) (Gast)


Lesenswert?

Diesmal war Johnny schneller ;-)

von johnny.m (Gast)


Lesenswert?

@Oskar-Rahul:
Ich hoffe, Du bist nicht so fies, dass Du mir den einen klitzekleinen 
Erfolg missgönnst... ;-)

von fieser Rahul (auch Oskar genannt) (Gast)


Lesenswert?

>Ich hoffe, Du bist nicht so fies, dass Du mir den einen klitzekleinen
>Erfolg missgönnst... ;-)

Ist ja auch unfair: Ich hatte eine "Sitzung"...

>Erfolg missgönnst... ;-)
Weisst du, was Voodoo ist? (Tut's schon weh? ;-)

von johnny.m (Gast)


Lesenswert?

@Voodoo-Oskar:
Aauuuuuu!!!!

von Heiko (Gast)


Lesenswert?

Danke für die schnellen Antworten.

Das mit dem Input Capture hört sich gut an, hab ich mir gerade mal im 
GCC-Tutorial hier auf der Seite angeschaut.

Dazu hab ich aber noch ne Frage zur genauen Funktionsweise. Da steht

> Nun kann je nach Konfiguration entweder ein Signalwechsel von 0 nach 1
> (steigende Flanke) oder von 1 nach 0 (fallende Flanke) erkannt werden und
> der zu diesem Zeitpunkt aktuelle Zählerstand in ein spezielles Register
> abgelegt werden.

Wann fängt denn der Timer an zu zählen? Sagen wir mal ich stell den 
Signalwechsel von 0 nach 1 ein. Die Flanke kommt und der Timer fängt an 
zu zählen. Geht der Pegel wieder auf O dann stoppt der Timer.

So, oder zählt er nach der Initialisierung los und stoppt wenn die 
Flanke kommt?

von johnny.m (Gast)


Lesenswert?

Der Timer läuft bei dem Verfahren kontinuierlich im Hintergrund. Die 
Input Capture Unit speichert lediglich bei Auftreten einer 
entsprechenden Flanke den aktuellen Zählerstand. Bei der nächsten Flanke 
bildest Du dann die Differenz der beiden erfassten Werte und zack 
haste Deine Signaldauer...

von fieser Rahul (auch Oskar genannt) (Gast)


Lesenswert?

>Wann fängt denn der Timer an zu zählen?
Den starten man irgendwann vorher.
ICP kopiert den aktuellen Wert des Timers ins ICP-Register. Von dort aus 
kann man ihn lesen; er wird beim nächsten Auftreten der Flanke wieder 
überschrieben.
Hat man eine steigende Flanke programmiert, schaltet man die 
Flankenrichtung in der ICP-ISR um, da man ja die Pulsdauer und nicht die 
Periodendauer messen will.
Wenn man dann die alte "Uhrzeit" von der neuen abzieht, erhält man die 
Impulslänge (da es sich um einen begrenzten Zahlenraum handelt, braucht 
man sich auch nicht um negative Zahlen kümmern: die gibt es nämlich 
nicht...).

Ablauf:
Timer starten
ICP-Flanke auf steigend programmieren.
Interrupt freigeben
warten, dass Flag gesetzt ist
flag löschen
Pulslänge auswerten...
weiter warten



Interrupt-Routine:
Ist steigende Flanke eingestellt?
ja: ICPR in "Startzeit" speichern
    Flanke auf "fallend" stellen
nein:
   ICPR in "Stopzeit" speichern
   Flanke auf "steigend" stellen
   "Pulslänge" = "Stopzeit" - "Startzeit"
   Flag setzen.

von Heiko (Gast)


Lesenswert?

Versteh ich nicht ganz.

Also der Timer wird initialisiert und fängt an zu zählen. Bei einem Wert 
von 50 kommt die erste Flanke. Die 50 wird gespeichert und in eine 
Variable geschrieben. Der erste Impuls sagen wir dauert 10 Zählwerte, 
dann sind wir bei 60. Die nächste Flanke kommt bei einem Zählwert von 
200 und die 200 wird wieder gespeichert. Aber wie komm ich da auf die 10 
für meine Impulslänge?



      --                 ----
     |  |               |    |
     |  |               |    |
-----    ---------------      ---------------
0   50  60             200

von johnny.m (Gast)


Lesenswert?

Ergänzung:
Tritt zwischen zwei Flanken ein Timer-Überlauf auf, muss der natürlich 
entsprechend berücksichtigt werden, sonst kommt Müll raus.

von Heiko (Gast)


Lesenswert?

Hab den Tread von Rahul jetzt erst gelesen und nun auch kapiert. Supi!

Vielen Dank euch beiden!

von johnny.m (Gast)


Lesenswert?

Da Du nach der ersten pos. Flanke die Flanke auf neg. umgestellt hast, 
wird nach der 50 zunächst mal die 60 gespeichert. Und 60-50 = 10... 
Klar? Danach wird wieder auf pos. Flanke umgestellt und die 200 kommt 
als nächster (Start-)Wert rein.

von fieser Rahul (auch Oskar genannt) (Gast)


Lesenswert?

>Tritt zwischen zwei Flanken ein Timer-Überlauf auf, muss der natürlich
>entsprechend berücksichtigt werden, sonst kommt Müll raus.
Nö, tut es nicht. (Zumindest nicht bei dieser Pulslänge...)

von johnny.m (Gast)


Lesenswert?

Stimmt natürlich. Bei den paar µs dürfte es keine Probleme geben.

von fieser Rahul (auch Oskar genannt) (Gast)


Lesenswert?

Binäre Berechnung:

Stopzeit = 0001
Startzeit = 1100
Somit ist Startzeit > Stopzeit
Stopzeit - Startzeit:
  0001
- 1100
------
 10101
Da hier nur mit 4 Bitz gerechnet wird, streicht man die erste Stelle 
(5.Bit/Übertrag) noch, und hat das richtige Ergebnis...
(Die führende 1 kann man auch als Vorzeichen ansehen...)

http://de.wikipedia.org/wiki/Dualsystem#Schriftliche_Subtraktion

von fieser Rahul (auch Oskar genannt) (Gast)


Lesenswert?

Probleme gibt es erst, wenn es zu einem weiteren Überlauf kommt...

von johnny.m (Gast)


Lesenswert?

@wie-auch-immer-Rahul:
> Probleme gibt es erst, wenn es zu einem weiteren Überlauf kommt...
...oder wenn der zweite Wert nach einem Überlauf größer oder gleich dem 
ersten (vor dem Überlauf) ist, also z.B. Startwert: 10000d, dann 
Überlauf, dann Stopwert: 12000d -> Differenz: 2000, müsste aber 
eigentlich ein bisschen mehr sein...

von fieser Rahul (auch Oskar genannt) (Gast)


Lesenswert?

>müsste aber eigentlich ein bisschen mehr sein

Dann hat der Programmentwickler Mist gebaut.

von Heiko (Gast)


Angehängte Dateien:

Lesenswert?

So,

hab den Code soweit fertig. Scheint aber noch nicht zu funktionieren. 
Hab bestimmt wieder die Hälfte vergessen;-)

Vielleicht könnt ihr ja mal drüber schauen, hänge ihn mal an.

Ach ja, nicht über die Auswertung wundern, die war jetzt nur zum testen.

Danke

von johnny.m (Gast)


Lesenswert?

> if (TCCR1B & (1<<UDRE0))
Was hat UDRE0 denn mit dem TCCR1B zu tun? Du musst schon das ICES1-Bit 
abfragen. Ich will jetzt auch nicht nachsehen, ob das UDRE0 zufällig an 
der selben Stelle steht wie das ICES1...

> Startwert = ICR1L;
> Startwert += (ICR1H<<8);
Für sowas sind in der Lib 16-Bit-Register definiert. Also besser
1
Startwert = ICR1;
Dann brauchste Dir keine Gedanken über die (wichtige) Reihenfolge beim 
Auslesen zu machen (die bei Dir aber stimmt...).

von fieser Rahul (auch Oskar genannt) (Gast)


Lesenswert?

>TCCR1B & (1<<UDRE0))

Interessanter Aspekt, den Timer direkt mit dem USART zu verbinden...

>  Stopwert = ICR1L;
>  Stopwert += (ICR1H<<8);

Geht einfacher:   Stopwert = ICR1;

von Michael Wilhelm (Gast)


Lesenswert?

Versuch doch mal folgendes:

ICP des Timers wie vorher beschrieben initialisieren auf steigende 
Flanke

wenn der Interrupt kommt Timerwert löschen und auf fallende Flanke 
setzen

wenn der nächste Int ausgelöst wird hast du ziemlich genau die 
Impulslänge in Ticks

keine Start und Stopprechnungen nötig

ob der Timer überläuft oder nicht ist egal, da nur der Wert während des 
High-Pegels gemessen wird

MW

von johnny.m (Gast)


Lesenswert?

Oh oh, ich spüre schon wieder diese Schmerzen...

BTW: Möglicherweise gibts Probleme, weil die Variable "Pulsdauer", auf 
die in der ISR und im Programm zugegriffen wird, nicht "volatile" ist. 
Besser
1
volatile unsigned int Pulsdauer;

von fieser Rahul (auch Oskar genannt) (Gast)


Lesenswert?

>ob der Timer überläuft oder nicht ist egal, da nur der Wert während des
>High-Pegels gemessen wird

Angenommen der Controller hat eine Taktfrequenz von 1MHz und der Impuls 
ist etwa 14.0000µs lang. Man will die exakte Imulslänge wissen (so wie 
Johnny oben). Ist da der Überlauf wirklich irrelevant?
Eher nicht.

>wenn der Interrupt kommt Timerwert löschen und auf fallende Flanke
>setzen

Das mag bei dieser Anwendung vielleicht gehen, benutz den gleichen Timer 
dann aber noch zur Erzeugung einer PWM. Da hast du schöne EMV-Probleme, 
wenn du eine induktive Last betreibst...

von johnny.m (Gast)


Lesenswert?

@Michael:
> ...ziemlich genau die Impulslänge in Ticks
Aber eben nur "ziemlich" genau, nämlich abzüglich der Zeit zwischen 
Auftreten des Interrupts (setzen des Flag) und Beendigung des 
Löschvorgangs im Timer-Register (und das sind allein zwei Zugriffe). Da 
gehen einige "Ticks" flöten, was grad bei Zeiten im µs-Bereich durchaus 
erheblich sein kann!

von Michael Wilhelm (Gast)


Lesenswert?

@ Rahul,

die Zeiten stehen fest, 10, 20 und 50 µs, ok?

@ Jonny, die Zeiten sind aber konstant und können zu der Berechnung 
addiert werden.

MW

von johnny.m (Gast)


Lesenswert?

@Michael:
> die Zeiten sind aber konstant und können zu der Berechnung addiert werden.

Jau, wenn man als fortgeschrittener (und Assembler-erfahrener) 
Programmierer sich die Mühe macht, rauszuklamüsern, was der Compiler 
beim Einsprung in die ISR alles macht oder wenn man direkt in Assembler 
programmiert. Außerdem enthält Dein obiges Posting diese Information 
nicht und dient deshalb höchstens zur Verwirrung eines Anfängers. Also 
entweder die ganze Wahrheit oder gar nichts... Und Heiko programmiert 
weder in Assembler noch scheint er ein erfahrener Programmierer zu sein.

von fieser Rahul (auch Oskar genannt) (Gast)


Lesenswert?

>aber konstant und können zu der Berechnung
>addiert werden.

Finde das mal raus, ohne den Assemblercode durchzukämmen!

Warum soll der Controller nicht ein wenig rechnen?
Wie oben schon erwähnt: Kommt es zu einem Überlauf, wird dieser auf 
jeden Fall (unbewusst) mit reingerechnet. Alles andere ist doch 
"Gebastel".
Der 8051 hat(te) eine schöne Timer-Funktion: Den Gate-Mode. Da wurde der 
Timer noch inkrmentiert, wenn ein Pin auf einem bestimmten Pegel lag - 
wunderbar um Pulslängen zu messen.

Da die Pulslänge ja feststehen, kann man also wunderbar "meine" Methode 
anwenden.
Wenn es um Pulslängen geht, die grösser als ein kompletter Timerumfang 
sind, muß man dessen Messbereich durch ein oder mehr Bytes erweitern.
So kann man auch aus einem 8Bit-Timer einem 32Bit-Timer machen...

>...oder wenn der zweite Wert nach einem Überlauf größer oder gleich dem
>ersten (vor dem Überlauf) ist, also z.B. Startwert: 10000d, dann
>Überlauf, dann Stopwert: 12000d -> Differenz: 2000, müsste aber
>eigentlich ein bisschen mehr sein...

>die Zeiten stehen fest, 10, 20 und 50 µs, ok?

Sagt das Johnny, nicht mir!

von Heiko (Gast)


Angehängte Dateien:

Lesenswert?

Danke, hab ich nun geändert.

Nur irgendwie scheint das Programm gar nicht erst in die Interrupt 
Routine zu springen. Lass mir dort zum Test eine Variable hochzählen und 
schaue mir diese dann später im Watch_Fenster an.(Debugger JTAGICE mkII)

Doch nichts tut sich. Hab das Programm noch mal angehängt.

von johnny.m (Gast)


Lesenswert?

@Rahul:
> Sagt das Johnny, nicht mir!
Hab's gelesen und entschuldige mich in aller Form dafür, dass ich ein 
Beispiel eingebracht habe für einen Fall, bei dem es Probleme geben 
könnte, auch wenn dieser Fall im konkreten Anwendungsfall nie 
auftritt... :-)

von Heiko (Gast)


Angehängte Dateien:

Lesenswert?

Hallo nochmal,

hab nun das ganze Wochenende damit zugebracht, den Fehler zu suchen. 
Leider ohne Erfolg. Wo kann der Fehler liegen? Hab ich irgenetwas falsch 
initialisiert, da der Input Capture Interrupt ja anscheinend gar nicht 
erst ausgeführt wird wenn ich eine Signal an PB0 anlege?

Ein Tip wäre super!

von Michael Wilhelm (Gast)


Lesenswert?

Kann es sein, dasss deine Signalquelle einen Open Collector-Ausgang ist? 
Dann musst du noch den Pull Up Widerstand an dem Portpin aktivieren.

MW

von Heiko (Gast)


Lesenswert?

> Kann es sein, dasss deine Signalquelle einen Open Collector-Ausgang ist?

Ist es nicht.

Hab den Pullup am Portpin trotzden mal aktiviert. Klappt aber auch 
nicht.

von johnny.m (Gast)


Lesenswert?

Woher weißt Du denn jetzt, dass die ISR nicht ausgeführt wird? Ich sehe 
in Deinem Code nirgends eine Ausgabe. Außerdem solltest Du wirklich 
Variablen, auf die in ISR und Programm zugegriffen wird, volatile 
deklarieren. Ich hab das oben nicht aus Spaß gesagt...

von Heiko (Gast)


Lesenswert?

> Woher weißt Du denn jetzt, dass die ISR nicht ausgeführt wird? Ich sehe
> in Deinem Code nirgends eine Ausgabe.

Doch doch, in der ISR wird die Variable C hochgezählt. Und die ist auch 
nach mehrmaligem anlegen einer Flanke immer 0. Egal ob volatile oder 
nicht.

von johnny.m (Gast)


Lesenswert?

Meine Frage bezog sich darauf, woher Du weißt, dass die Variable sich 
nicht ändert (dass sie da ist und inkrementiert wird, hab ich gesehen; 
so blind bin ich auch nicht...). Sie wird nirgends weiter bearbeitet 
oder ausgegeben!

von Heiko (Gast)


Lesenswert?

Siehe oben:

> Lass mir dort zum Test eine Variable hochzählen und schaue mir diese dann
> später im Watch_Fenster an.(Debugger JTAGICE mkII)

von johnny.m (Gast)


Lesenswert?

Aha, das hatte ich jetzt beim "Wieder-Einlesen" übersehen. Hatte extra 
drübergeschaut, ob irgendwo das Wörtchen JTAG auftaucht...

von Heiko (Gast)


Lesenswert?

Ich glaub ich hab den Fehler. Ich hab den Timer zwar 
initialisiert(Taktfrequenz, Interrupts), doch vergessen einem Mode 
einzustellen.

Welcher Mode für den Timer eignet sich am besten bei einem Input 
Capture? CTC?

von johnny.m (Gast)


Lesenswert?

Nein, Du brauchst keinen Waveform-Generation-Mode für das was Du 
vorhast. Der Timer muss nur laufen, und das sollte er nach Deiner 
Initialisierung tun. Die Waveform-Generation-Modes brauchste nur dann, 
wenn Du ein Signal erzeugen willst.

von johnny.m (Gast)


Lesenswert?

> ...Du brauchst keinen Waveform-Generation-Mode...
OK, um keine Verwirrung zu stiften: Du kannst den 
Waveform-Generation-Mode "0" (Normal Operation) einstellen. Der ist aber 
defaultmäßig aktiv und ist für meine Begriffe eigentlich kein 
Waveform-Generation-Mode...

von johnny.m (Gast)


Lesenswert?

Normalerweise müsste die Capture Unit mit jeder Timer-Betriebsart bis 
auf Waveform-Generation-Modes 8, 10, 12 und 14 (also die, bei denen ICR1 
eine andere Funktion hat) funktionieren. Um sicherzustellen, dass da nix 
passiert, könntest Du mal in Deinem Code die "|=" bei den Zugriffen auf 
TCCR1A und B durch "=" ersetzen. Die Bits haben zwar alle lt. Datenblatt 
den Reset-Wert 0, aber man weiß ja nie. Und andere Bits in den Registern 
brauchste eh nicht.

von Heiko (Gast)


Lesenswert?

Aber wo kann dann der Fehler liegen? An meinem Signal?

Der Controller wird mit 4,5 Volt betrieben. Das Signal ist mitlerweile 
schon nur noch eine Flanke(4,2V) von einem Labornetzteil.

von Heiko (Gast)


Lesenswert?

> Um sicherzustellen, dass da nix passiert, könntest Du mal in Deinem Code die > 
"|=" bei den Zugriffen auf TCCR1A und B durch "=" ersetzen.

Hat sich nichts geändert.

Ach ja, Bits im Register TCCR1A hab ich in meinem Code gar nicht 
gesetzt. Da müsste doch dann defaultmäßig die "normal port operation" 
eingestellt sein. Muss ich da irgenwas anderes einstellen?

von johnny.m (Gast)


Lesenswert?

Bei "Flanken" von Labornetzteilen wäre ich sehr vorsichtig. Hast Du es 
mal mit einem anderen Controller probiert? Dass Du das Signal auch 
tatsächlich an PORTB.0 angeschlossen hast, setze ich mal voraus (Obwohl: 
man weiß ja nie...). Ich steh momentan auch ziemlich auf dem Schlauch 
und weiß keine anderen Lösungsvorschläge mehr. Aber hinterher isses 
wahrscheinlich wieder irgendwas triviales, und man hat nur den Wald vor 
lauter Bäumen nicht gesehen. Ich schau jedenfalls, wenn ich zwischen der 
Arbeit mal Zeit habe auf jeden Fall noch mal drüber...

von johnny.m (Gast)


Lesenswert?

Schreib einfach ne Null ins TCCR1A

von Heiko (Gast)


Lesenswert?

Werd ich gleich mal mit nem Signal vom anderen Controller versuchen. Wie 
du schon sagst, wird wohl irgendein dummer Fehler sein, den man einfach 
übersehen hat.

Erst einmal vielen Dank für deine Mühe! Und wäre total super, wenn du 
noch mal drüberschauen könntest, falls du Zeit hast.

Danke und Gruß

Heiko

von Michael Wilhelm (Gast)


Lesenswert?

Schau dir mal die Interrupt-Tabelle an, der 48 und der 88 haben die 
gleichen Einsprungadressen (so wie ich es überschlagen habe), nur der 
168 hat eine andere Tabelle. Evtl. liegt da der Fehler.

MW

von Michael Wilhelm (Gast)


Lesenswert?

Nachtrag:


auch 48 und 88 haben andere Tabellen. Nur in dem Bereich, in dem du 
arbeitest sind sie gleich.

MW

von Max (Gast)


Lesenswert?

Hi Michael,

blöde Frage, aber wo finde ich diese Tabellen?

von fieser Rahul (auch Oskar genannt) (Gast)


Lesenswert?

>aber wo finde ich diese Tabellen?

Ohne den Beitrag genau gelesen zu haben:
Im Datenblatt!

von fieser Rahul (auch Oskar genannt) (Gast)


Lesenswert?

>Schau dir mal die Interrupt-Tabelle an, der 48 und der 88 haben die
>gleichen Einsprungadressen (so wie ich es überschlagen habe), nur der
>168 hat eine andere Tabelle. Evtl. liegt da der Fehler.

Interrupt-Tabellen? Und C?
Sollten nicht weiter interessieren, wenn man im makefile den richtigen 
Controller angegeben hat.
Um die kümmert sich in der Compiler.


von Heiko (Gast)


Lesenswert?

Hatte ich schon überprüft. Im Build-Fenster steht: "Device: Atmega88"

von johnny.m (Gast)


Lesenswert?

Hab das Programm mal bei mir durch den Simulator gejagt und da 
funktioniert es tadellos. Der Interrupt wird schön sauber ausgeführt, 
auch in der Langversion der ISR klappts.

von Michael Wilhelm (Gast)


Lesenswert?

>>Hatte ich schon überprüft. Im Build-Fenster steht: "Device: Atmega88"

Ich denk du arbeitest mit dem 48?

MW

von johnny.m (Gast)


Lesenswert?

Das mit Mega48 / 88 war mir auch grad aufgefallen. Sollte aber in dem 
Fall keine Schwierigkeiten machen. Solange da kein Mega168 steht, 
unterscheiden die sich afaik nicht.

von Michael Wilhelm (Gast)


Lesenswert?

Vielleicht versucht der Compiler den Stack da anzulegen, wo der 48 gar 
kein Ram hat (256 zu 512 Byte).

MW

von johnny.m (Gast)


Lesenswert?

@Michael:
Das ist natürlich nicht von der Hand zu weisen. ATMega48: 512 Bytes RAM, 
ATMega88: 1KByte RAM.

@Heiko:
Also, einmal für ATMega48 kompilieren bitte...

von Heiko (Gast)


Lesenswert?

> Hab das Programm mal bei mir durch den Simulator gejagt und da
> funktioniert es tadellos. Der Interrupt wird schön sauber ausgeführt,
> auch in der Langversion der ISR klappts.

Daher könnte man annehmen, der Pin PB0 ist kaputt. Versucht ne LED über 
den Pin zu schalten. Geht nicht. Tonne auf, Controller rein. Neuen aufs 
Board und siehe da, es funktioniert.

Was ein dummer ärgerlicher Fehler. Nur da erst mal drauf zu kommen, da 
alle anderen Pins einwandfrei funktionierten.

Na ja, allen vielen Dank die sich mit dem Problem auseinandergesetzt 
haben! Versuche nächste mal solche Fehler(was mir bestimmt nicht noch 
mal passiert) direkt auszuschließen.

Gruß und besten Dank!

von Michael Wilhelm (Gast)


Lesenswert?

@ Jonny,
hast natürlich recht. Hab auf die schnelle die EEPROM Daten gelesen.

MW

von johnny.m (Gast)


Lesenswert?

@Michael:
Die genauen Zahlen sind ja eh egal. Der Unterschied (den ich beim ersten 
Datenblattcheck übersehen hatte) macht die Musik...

Gruß

joHnny

von Heiko (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich bin es nochmal. Soweit funktioniert das ganze.

Ich lese nun zwei Impulse von einer Signalquelle ein. Die Signalquelle 
erzeugt ein Rechtecksignal mit einer Periodendauer von 30µs. Also ein 
Highpegel hat eine Länge von 15µs. Das Capture Interrupt habe ich so 
programmiert, wie oben schon Besprochen. Das ganze läuft nun 
folgendermaßen ab:

- Positive Flanke kommt
- Interrupt_Routine wird ausgeführt
- Wenn auf positive Flanke eingestellt, Startwert = ICR1 und auf 
negative
  Flanke gestellt
- Zusätzlich wird in der Routine noch die Variable c hochgezählt
- Routine wird beendet.

- Negative Flanke kommt
- Interrupt_Routine wird ausgeführt
- Wenn auf negative Flanke eingestellt, Stopwert = ICR1 und auf positive
  Flanke gestellt und Impulslänge durch Stopwert - Startwert berechnet
- Zusätzlich wird in der Routine noch die Variable c hochgezählt
- Routine wird beendet.


Das ganze ist zum Test erst einmal auf 4 Durchläufe begrenzt. Daher 
müssten genau 2 Impulse gemessen und den zugehörigen Variablen 
zugeordnet werden. Die Zuordnung geschieht durch den Wert der Variable 
c.

Was mich ein wenig wundert ist, das ich für gleiche Impulslängen 
unterschiedliche Werte herausbekomme. Und nicht nur leicht 
unterschiedliche, die Werte der Variablen unterscheiden um ca. 1000.

Hab den aktuellen Code nochmal angehangen.

Gruß  Heiko

von fieser Rahul (auch Oskar genannt) (Gast)


Lesenswert?

>Die Signalquelle erzeugt ein Rechtecksignal mit einer Periodendauer von >30µs.

Mit welcher Frequenz arbeitet dein Controller?
Kannst du u.U. auch nur einen einzelnen "Ping"* senden?
Ich vermute, dass deine ISR einfach zu lang ist, und du deswegen die 
fallende Flanke eines der darauffolgenden Impulse misst.


*"Jagd auf Roter Oktober"...

von johnny.m (Gast)


Lesenswert?

Deine Funktion ICP_Auswertung ist nicht sonderlich geschickt angelegt. 
Da sie ständig wieder ausgeführt wird, kann da alles Mögliche schief 
gehen. Das Beste wäre, die Funktion nur dann einmal auszuführen, wenn 
sich tatsächlich was geändert hat (z.B. indem Du ein Software-Flag in 
der ISR setzt und nur dann, wenn dieses gesetzt ist, die Funktion 
aufrufst). Zugriffe auf 16-Bit-Variablen, die in ISRs verändert werden 
können, sind generell kritisch. Man sollte in solchen Fällen besser vor 
dem Zugriff im Hauptprogramm die Interrupt-Bearbeitung deaktivieren (mit 
cli()) und erst nach Beendigung des Vorganges mit sei() wieder 
freigeben.

von johnny.m (Gast)


Lesenswert?

BTW: Mit was für ner Taktfrequenz läuft Dein µC eigentlich? Kann zwar 
sein, dass das oben schon mal erwähnt wurde, ich finde es jetzt aber 
nicht...

von Heiko (Gast)


Lesenswert?

Der Controller läuft mit 14,74500 MHz. Nen einzelnen Ping kann ich nicht 
senden.

von johnny.m (Gast)


Lesenswert?

Also, 15µs / 67ns = 224, d.h. zwischen zwei Flanken sollten 224 Zyklen 
passen. Das sollte eigentlich für das bisschen Programm in der ISR und 
die Auswertung dicke reichen. Daran dürfte es also nicht liegen...

von Heiko (Gast)


Lesenswert?

Hab es jetzt gerade hinbekommen, nur einen einzelnen Rechteckimpuls von 
10µs Länge zu erzeugen.

Trotzdem wird die ISR 4mal aufgerufen. Das dürfte doch eigentlich auch 
schon nicht sein.

von Michael Wilhelm (Gast)


Lesenswert?

Ich hab noch mal ins Datenblatt geschaut. Hier der Auszug:

Measurement of an external signal’s duty cycle requires that the trigger 
edge is changed
after each capture. Changing the edge sensing must be done as early as 
possible after
the ICR1 Register has been read. After a change of the edge, the Input 
Capture Flag
(ICF1) must be cleared by software (writing a logical one to the I/O bit 
location). For
measuring frequency only, the clearing of the ICF1 Flag is not required 
(if an interrupt
handler is used).

Also, wenn du per Hand die Flanke wechselst das entsprechende Bit (ICF1) 
löschen. Das sollte helfen.

MW

von johnny.m (Gast)


Lesenswert?

Aah ja, da hatte ich auch nicht mehr dran gedacht! Die Input Capture 
Unit detektiert ein Umschalten der Flankendetektierung selber als Flanke 
und setzt das Flag sofort wieder...

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.