Forum: Mikrocontroller und Digitale Elektronik Interrupts zählen 8535


von JFA (Gast)


Lesenswert?

Moin Moin,

ich benutze den ATMega8535 und möchte an INT0,INT1 und INT2
"Änderungen"  zB steigende Flanke eines Rechtecksignals zählen und
das mit möglichst hoher Frequenz.Funktioniert an jeweils einem
Interrupt auch ganz wunderbar...
Wenn ich nun das selbe Rechtecksignal an alle 3 Interrupts lege, dann
funktioniert das ganze nurnoch sehr merkwürdig...
Bei einer Frequenz von zB 10kHz "verzählt" sich der MC schon sehr
früh um "6" Flanken von Interrupt zu Interrupt...
Das merkwürdige ist, dass sich das nichtmehr Ändert, sprich auch noch
Millionen von Zählungen is die Differenz zwischen den Interrupts
immernoch "6" Flanken die abhandengekommen sind.

Das scheint ja nun ein Problem zu sein welches nicht darauf schließen
lässt,dass die Frquenz des Rechtecksignals zu hoch ist, sondern eher
ein Problem des MC...

Meine Frage nun hat jemand eine Idee worans liegt bzw hat jemand
schonmal ein ähnliches Problem gehabt ?

von Freudi (Gast)


Lesenswert?

Mit welcher Frequenz arbeitet die CPU ? Wie sind Deine Int-Routinen
gestaltet ? Gibst Du bei Eintritt per sei Int's frei ?
Wenn alle 3 gleichzeitig auftreten gehts nach Priorität also die int0
Routine wird zuerstausgeführt dann int1 usw.

Freudi

von JFA (Gast)


Lesenswert?

CPU Freq 8 Mhz

SIGNAL (SIG_INTERRUPT0)
    {
    counter1++;// zähler erhöhen
    }

jop sind alle freigeben...

Das es nach Priorität geht is ja auch ok, aber der AVR müsste es doch
bis zu einer bestimmten Freq hinbekommen die anderen Interrupts nicht
teilweise unter den Tisch fallen zu lassen....

von crazy horse (Gast)


Lesenswert?

kommt natürlich auch sehr darauf an:
-wieviel der Compiler rettet.
-wie gross ist die Variable
-liegt die im Registerberech oder RAM

da hilft dir nur ein Blick ins list- oder asm-File, um das beurteilen
zu können.

von Michael (Gast)


Lesenswert?

Programmiere die Sache doch einfach in Assembler. Dann solltest Du keine
Probleme mit der Zählfrequenz haben.

von JFA (Gast)


Lesenswert?

also ich hab jetz heraus gefunden, dass das mit meiner "ausgabe"
konfliktiert bzw. mit dem was das programm noch so macht....
1. gibt es den wert auf anfragen über die uart schnittstelle weiter
(das beinhaltet zB auch eine konvertierung des wertes "ltoa")
2. prüft es auf einen bestimmten überlaufwert

wenn ich das programm darauf zusammenkürze, dass es mir nur die werte
per tastendruck ausgibt funktioniert es bis 1khz...
also mute ich dem guten wohl etwas zuviel zu...

vielen dank für eure hilfe

von Michael (Gast)


Lesenswert?

>> also mute ich dem guten wohl etwas zuviel zu...

Das machst Du eigentlich nicht :-)
Selbst bei 3 x 10kHz hat jede Zählroutine 33µs Zeit, um den Zähler zu
erhöhen; bei 8MHz sind das rund 260 Takte - und das reicht allemal, es
sei denn, Du verbietest irgendwo die Interrupts ?

von crazy horse (Gast)


Lesenswert?

mal so grob worst case gerechnet, angenommen eine unsigned long-Variable
im RAM.
-ISR-Aufruf
-Rettung von 4 Registern + SREG
-Variable aus RAM laden
-incrementieren
-Variable speichern
-Register + SREG wiederherstellen
-reti

Das macht ca. 50 Takte, für 3 gleichartige Interrupts also 150 Takte.
Bei 8MHz Taktfrequenz also knappe 20µs. Das ganze sollte also bis 50kHz
funktionieren können.

von JFA (Gast)


Lesenswert?

nee das mache ich eigentlich nicht...
ich hab ihn jetzt einfach mal die variablen vergleichen lassen und ihn
dann eine ausgabe machen lassen, sonst nichts, sprich

if( counter1 && counter2 && counter3 == 500000) puts("\n BINGO ")

das funktioniert bis 30kHz !

aber sobald ich zwischen durch mal einen wert "abfrage" bringt das
alles durcheinander und die counter haben nichtmehr die selben
werte...
bei "dauerausgabe" der werte macht er selbst bei 100hz schon
fehler...

von Michael (Gast)


Lesenswert?

Dann sperrst Du irgendwo die Interrupts, oder die Ausgaberoutine ist
voll schlecht.

von crazy horse (Gast)


Lesenswert?

naja, vielleicht stellst du mal dein gesamtes Programm ein, ehe das hier
zu weiterem Rätselraten führt.
z.B. gibts da eine kleine Tücke: dein Hauptprogramm liest gerade den
Zählerstand ein, mittendrin kommt der Interrupt und verändert dir den
Zählerstand, anschliessend liest du weiter ein. Dein Wert ist falsch.
Beispiel: Zählerstand 0x00ff, du liest das low_byte, interrupt kommt,
erhöht den Zählerstand auf 0x0100, du liest das high_byte. Und jetzt
rechnest du mit 0x01ff - den Wert hat es aber nie gegeben.

von Rahul (Gast)


Lesenswert?

Wenn du an alle drei Eingänge exakt das gleiche Signal legst, kommen
sich die ISR ins Gehäge, weil alle gleichzeitig auf das Ereignis
reagieren wollen.
ISR sehr klein wählen (nur ein Flag setzen) und dann im Hauptprogramm
das flag auswerten.

von crazy horse (Gast)


Lesenswert?

stimmt nicht, kommen sich nicht ins Gehege. In so einem Fall greift die
Priorität. Int0 wird ausgeführt, Int1 und 2 gespeichert. Nach reti vom
Int0 wird Int1 ausgeführt, anschliessend Int2.

von JFA (Gast)


Angehängte Dateien:

Lesenswert?

das mit der schlechten ausgabe hat mich auf eine idee gebracht...
ich habe die ausgabe über den uart_receive_interrupt laufen lassen, ich
habe gedacht, dass die ausgabe + die umrechnung inder der routine gut
aufgehoben währen, aber das war wohl grosser mist.damit habe ich dann
wohl doch die interrupts gesperrt,denn diese routine musste ja erstmal
abgearbeitet werden...

nun habe ich meine ausgabe ins hauptprogramm verlagert ( siehe anhang )

von JFA (Gast)


Lesenswert?

c1 = counter1;
c2 = counter2;
c3 = counter3;
ltoa(c1,buffer,10);
ltoa(c2,buffer1,10);
ltoa(c3,buffer2,10);

hab jetzt noch meine zähl variable quasi "schnell" umgespeichert und
dann konvertiert.
juhuuu jetz funktioniert es mit 20 khz ohne probleme
danke crazy horse für den super tipp....

von crazy horse (Gast)


Lesenswert?

das ist zwar besser, aber immer noch nicht exakt. Während des
Umkopierens musst du die Interrupts sperren.
#asm ("cli")
zwischenspeichern
#asm ("sei")
Ausgabe

von JFA (Gast)


Lesenswert?

könnte es mir dann nicht passieren, dass ich genau dann die interrupts
sperre, wenn zB der INT0 gerade gezählt hat und die anderen beiden
genau dann quasi "ausgesperrt" werden..dadurch verliere ich die
anderen beiden doch dann....

von crazy horse (Gast)


Lesenswert?

nö, du verlierst gar nichts. Die Interruptanforderungen werden ja
gespeichert, nur die Ausführung der zugehörigen ISR vorläufig
verhindert. Im Prinzip ist es unabdingbar, es so zu machen, wie ich dir
gesagt habe. Fehler, die auftreten können, werden auch irgendwann
auftreten. Da gibts Programme, die laufen monatelang störungsfrei, dann
passiert es eben doch. Normalerweise wird das dann auf die Hardware/ext.
Störungen geschoben, ist aber ein klarer Softwaredesignfehler.

von JFA (Gast)


Lesenswert?

ich habs jetzt auch so gemacht wie du es vorgeschlagen hast, nun
funktioniert es sogar bis 30 khz.
meine frage von eben kam deshalb auf:
wenn ich alle 3 interruptzähler zurücksetze, bekomme ich manchmal einen
verschub von einem zähler( zB "int0 = 10" "int1 = 11" "int2 =
11").das passiert halt nicht immer, aber ab und zu, ich dachte halt
das es eventuell daran liegt, tut es wie ich jetzt festgestellt habe
aber nicht.
werd nochmal weiter suchen, ich find schon noch heraus woran das liegt
;)

von crazy horse (Gast)


Lesenswert?

na, dass nähert sich ja langsam der oben überschlagenen 50kHz :-).
Der Versatz von max 1 ist jederzeit möglich, da du ja auch nicht
wirklich gleichzeitig die Zähler auf Null setzen kannst. Müsste man
dann wieder nach der selben Methode machen

cli
counter1=counter2=counter3=0
sei

Ausserdem müssten noch evtl. anhängige Int-flags gelöscht werden.

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.