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 ?
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
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....
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.
Programmiere die Sache doch einfach in Assembler. Dann solltest Du keine Probleme mit der Zählfrequenz haben.
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
>> 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 ?
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.
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...
Dann sperrst Du irgendwo die Interrupts, oder die Ausgaberoutine ist voll schlecht.
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.
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.
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.
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 )
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....
das ist zwar besser, aber immer noch nicht exakt. Während des Umkopierens musst du die Interrupts sperren. #asm ("cli") zwischenspeichern #asm ("sei") Ausgabe
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....
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.
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 ;)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.