www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Interrupts zählen 8535


Autor: JFA (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ?

Autor: Freudi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: JFA (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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....

Autor: crazy horse (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Michael (Gast)
Datum:

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

Autor: JFA (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ?

Autor: crazy horse (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: JFA (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dann sperrst Du irgendwo die Interrupts, oder die Ausgaberoutine ist
voll schlecht.

Autor: crazy horse (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Rahul (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: crazy horse (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: JFA (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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 )

Autor: JFA (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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....

Autor: crazy horse (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: JFA (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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....

Autor: crazy horse (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: JFA (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
;)

Autor: crazy horse (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.