Hi! ich arbeite an meinem Maturaprojekt und bin jetzt vom ATMega8 auf den 128er umgestiegen. Programmiert wird er mit einem von uns entwickeltem ISP-Programmer. Jetzt habe ich seit letzter Woche folgendes Problem: Ich hab eine Variable, in diesem Fall enablex die durch die if-Anweisung im Timer-Interrupt den PB5 HI oder LOW setzt. Jedoch sobald ich diese Variable mehr als einmal ändern will, funktioniert dies nicht. Bei dem Beispiel also setzt er es zuerst auf HI aber nie mehr auf LOW. In der Simulation funktioniert jedoch alles einwandfrei. Anbei findet ihr das C-File, entschuldigt die vielen auskommentierten Zeilen, diese verwende ich momentan nach, will sie aber nicht löschen, da vl ja hier der Fehler liegt, was ich mir aber nicht vorstellen kann. Auch die Funktion zeilenscan sollte ja kein Problem darstellen, da sie ja nicht aufgerufen wird. Aja beim Dateinamen hab ich mich vertippt, also nicht wundern ;-) Im Voraus schon mal vielen Dank für eure Hilfe! Lg Oliver
> PORTC = PORTC | (0 << PC1); Was wird da wohl rauskommen? Dein Nachholbedarf liegt beim Thema Bitmanipulation in C. Als Tipp: Probiers mal so PORTC = PORTC & ~(1 << PC1); > In der Simulation funktioniert jedoch alles einwandfrei. Das würde mir aber zu Denken geben... :-o
> suche mal nach "volatile"
Wozu sollte er das tun?
Lothar Miller schrieb: >> PORTC = PORTC | (0 << PC1); > Was wird da wohl rauskommen? > Dein Nachholbedarf liegt beim Thema Bitmanipulation in C. > > Als Tipp: > Probiers mal so PORTC = PORTC & ~(1 << PC1); > >> In der Simulation funktioniert jedoch alles einwandfrei. > Das würde mir aber zu Denken geben... :-o Das kann gut sein, haben das leider nie so wirklich gelernt. Aber ein Oder scheint doch richtig, wenn ich nur den einen Pin ändern will?! Also mit dem & ~ funktioniert es leider auch nicht. Wie meinst du das mit der Simulation? Also, einen anderen 128er hab ich auch schon probiert, einen andern PC auch, weil evtl. ja das AVR-Studio was haben kann und einen anderen Programmer auch, jedoch leider einer der selben Bauweise. Aber letzte Woche hat alles komischer Weise noch funktioniert, in genau der selben Konfiguration. lg
Ga st schrieb: >> suche mal nach "volatile" > Wozu sollte er das tun? Was soll das sein? Naja ich google mal.
Also mit volatile funktioniert es leider auch nicht, nimmt trotzdem nur einmal einer Änderung der Variable vor. Sollte nicht eigentlich static reichen? Soll ich vl. alle Variablen anstatt mit static mit volatile deklarieren? lg
> Das kann gut sein, haben das leider nie so wirklich gelernt. Aber ein > Oder scheint doch richtig, wenn ich nur den einen Pin ändern will?! Angenommen, dein Port hat den Zustand 0b11111111. Nun veroderst du dazu 0b00000000. Danch hat dein Port immer noch 0b11111111. Also: Viel getan und nicht bewirkt. Wenn du aber zu 0b11111111 den Wert 0b00000000 verundest, hat dein Port anschliessend 0b00000000. > Das kann gut sein, haben das leider nie so wirklich gelernt. Dann tus jetzt. Der Ausdruck (1 << PC1) ist das selbe wie (1 << 1), es kommt also 0b00000010 heraus. Der Ausdruck (0 << PC1) ist das selbe wie (0 << 1), es kommt also 0b00000000 heraus. Und das Veroderst du zum PortC. BTW: Du hast den falschen Ansatz. Deine Interruptroutine ist viel zu umständlich und lang... :-o
Lothar Miller schrieb: >> Das kann gut sein, haben das leider nie so wirklich gelernt. Aber ein >> Oder scheint doch richtig, wenn ich nur den einen Pin ändern will?! > Angenommen, dein Port hat den Zustand 0b11111111. Nun veroderst du dazu > 0b00000000. Danch hat dein Port immer noch 0b11111111. Also: Viel getan > und nicht bewirkt. > > Wenn du aber zu 0b11111111 den Wert 0b00000000 verundest, hat dein Port > anschliessend 0b00000000. > >> Das kann gut sein, haben das leider nie so wirklich gelernt. > Dann tus jetzt. > Der Ausdruck (1 << PC1) ist das selbe wie (1 << 1), es kommt also > 0b00000010 heraus. > Der Ausdruck (0 << PC1) ist das selbe wie (0 << 1), es kommt also > 0b00000000 heraus. > Und das Veroderst du zum PortC. PortB, aber is ja eh gleich. Und dann wird auch nur der eine Pin geändert? Ich bild mir immer ein, dass dann der Rest auch verändert wird. Ich will jedoch ja nur das eine Bit ändern. > BTW: > Du hast den falschen Ansatz. Deine Interruptroutine ist viel zu > umständlich und lang... :-o Das ist, damit der Takt zuerst schneller und dann wieder langsamer wird. Was ist da so umständlich, bzw. was könnte ich noch optimieren? Aja vielen Dank einmal für eure schnellen Bemühungen. lg
Oliver Kra schrieb: > Und dann wird auch nur der eine Pin geändert? Siehe Bitmanipulation > Was ist da so umständlich, bzw. was könnte ich noch optimieren? Die Hauptarbeit bei einem uC-Programm wird in der Main-Schleife erledigt. Interruptroutinen sind kurz. Sie verwenden nur vorberechnete Werte oder stellen Rohwerte bereit.
Lothar Miller schrieb: >> Was ist da so umständlich, bzw. was könnte ich noch optimieren? > Die Hauptarbeit bei einem uC-Programm wird in der Main-Schleife > erledigt. > Interruptroutinen sind kurz. Sie verwenden nur vorberechnete Werte oder > stellen Rohwerte bereit. Also soll ich die ganzen if-Anweisungen in die while(1) hauen? Das mit dem Verändern der Variable DURCHLAUFE muss ich ja so lassen, sonst überprüft er mir das ja nicht immer, oder? und er wird dann nicht immer schneller und langsamer?
Lothar Miller schrieb: > Oliver Kra schrieb: >> Und dann wird auch nur der eine Pin geändert? > Siehe Bitmanipulation laut Bitmanipulation stimmt es doch wenn ich "PORTB = PORTB | (1 << PB5);" schreibe, denn genau dann wird nur PB5 verändert und gegebenenfalls auf 1 gesetzt und wenn anstatt des 1 eine 0 drinn steht, dann umgekehrt. Oder denk ich hier vollkommen falsch?
> Oder denk ich hier vollkommen falsch?
Nein. Soweit passt das zum Setzen eines Bits.
Nur das Rücksetzen muß über eine VerUNDung gehen...
Oliver Kra schrieb: > laut Bitmanipulation stimmt es doch wenn ich "PORTB = PORTB | (1 << > PB5);" schreibe, denn genau dann wird nur PB5 verändert und > gegebenenfalls auf 1 gesetzt und wenn anstatt des 1 eine 0 drinn steht, > dann umgekehrt. Nix umgekehrt mit PORTB = PORTB | ( 1 << PB5 ); wird das Bit PB5 auf 1 gesetzt. Punkt mit PORTB = PORTB & ~( 1 << PB5 ); wird das Bit PB5 auf 0 gesetzt. Punkt. Da gibts nichts 'umgekehrt'. Die Operation um ein Bit gezielt auf 1 zu bekommen ist eine andere als die, mit der ein Bit gezielt auf 0 gesetzt wird.
Aja, ok, hab schon wieder mal nicht weitergelesen. Danke, werd gleich mal probieren ob es jetzt funkt.
Juhu, vielen Dank, das war der Fehler. Da sieht man, dass mir leider vieles vom Grundwissen fehlt. Muss es mal genauer Durchtesten ob jetzt alles funktioniert. Aja, soll ich jetzt die if-Anweisungen in die main unter die while(1) hauen? lg
Oliver Kra schrieb: > Juhu, vielen Dank, das war der Fehler. Da sieht man, dass mir leider > vieles vom Grundwissen fehlt. Kann mir die Frage nicht verkneifen: Warum nimmst du dir dann sowas zum Maturaprojekt?
Karl heinz Buchegger schrieb: > Oliver Kra schrieb: >> Juhu, vielen Dank, das war der Fehler. Da sieht man, dass mir leider >> vieles vom Grundwissen fehlt. > > Kann mir die Frage nicht verkneifen: > Warum nimmst du dir dann sowas zum Maturaprojekt? Wir sind ja eh eine ganze Gruppe, jedoch muss einer den AVR-Programmieren und, traurig aber war, kann ich es am Besten. Da haben wir leider ein sehr Großes Defizit. Aja die if anweisungen muss ich doch im Timer lassen, ansonsten, ruft er mir sie nie regelmäßig auf. Kennt ihr vl eine Lösung die effektiver ist? lg
> Kennt ihr vl eine Lösung die effektiver ist?
Setz im Timer ein Flag, und werte das in der Hauptschleife aus.
Ich würde die Daten für die Rampe in einer Tabelle vorbereiten, und in
der ISR nur noch den Tabellenindex manipulieren.
Lothar Miller schrieb: >> Kennt ihr vl eine Lösung die effektiver ist? > Setz im Timer ein Flag, und werte das in der Hauptschleife aus. > > Ich würde die Daten für die Rampe in einer Tabelle vorbereiten, und in > der ISR nur noch den Tabellenindex manipulieren. ok, werd das mal am We probieren. Das mit der Tabelle verstehe ich gerade nicht so wirklich. Kannst mir das näher erläutern?
Lothar Miller schrieb: >> Kennt ihr vl eine Lösung die effektiver ist? > Setz im Timer ein Flag, und werte das in der Hauptschleife aus. Hab ich mir auch schon gedacht. Aber dann wird die Sache mit dem Zeilenscan so nicht mehr gehen. Aber egal wie man es dreht und wendet: Der ganze Ansatz ist verkorkst
Karl heinz Buchegger schrieb:
> Aber egal wie man es dreht und wendet: Der ganze Ansatz ist verkorkst
Wie meinst verkorkst? Ein Schaß, oder wie?
Ich hoffe gar so schlimm ist es nicht, oder?
Für jeden produktiven Vorschlag bin ich dankbar und werde ihn Versuchen
umzusetzen und zu probieren.
> Aja, soll ich jetzt die if-Anweisungen in die main unter die while(1)
hauen?
"Hauen" ist ganz schlecht, man sollte immer wissen, was man tut.
Für den Anfang ist deine Interrupt-Routine garnichtmal so schlecht,
immerhin hast du keine Schleifen oder Wartezeiten drin (hatten wir hier
auch schon).
Noch besser wäre es, vorberechnete Werte für den Timer (und evtl. die
Bits in PORTB und PORTC) zu speichern, die dann der Interrupt nur noch
in die entsprechenden Register schreibt. Das muss natürlich mit dem
Interrupt synchronisiert werden, dazu setzt der Interrupt ein Flag, wenn
er fertig ist (hier z.B. eine Variable int flag auf 1). In der
while-Schleife wartest du, bis das Flag gesetzt ist, setzt es zurück und
dann berechnest die Werte für den nächsten Interrupt. Wenn jetzt noch
das Timing stimmt, d.h. der Interrupt dem Hauptprogramm genügend
Rechenzeit übriglässt, dann funktioniert das wunderbar.
Alle Variablen, die von Interrupt und Hauptprogramm benutzt werden,
müssen volatile deklariert werden!
Juergen schrieb: > evtl. die > Bits in PORTB und PORTC aber sobald ich die Bits in die jeweiligen PORTS schreibe übernimmt er diese ja auch. Das wäre ja dann zu früh, oder? Wenn ich im TimerInterrupt mittels Flag auf die while-schleife verweise ist doch der zeilenscan schon vorbei, und die if-Anweisungen werden ja dafür benötig. Oder sucht sich der flag immer den Teil raus, wo er hinsoll und überspringt dabei alles andere? Was würdet ihr davon halten, wenn ich für das ganzen einfach eine neue Funktion schreibe und diese im Timer aufrufe? lg
Oliver Kra schrieb: > Was würdet ihr davon halten, wenn ich für das ganzen einfach eine neue > Funktion schreibe und diese im Timer aufrufe? Gar nichts. Wenn du ein Loch gräbst, geht das auch nicht schneller wenn du einen Sichtschutz rundum stellst. Bei 'kurze ISR' geht es nicht um die Anzahl der Codezeilen sondern um die Ausführungszeit. Und die hängt wiederrum von dem auszuführenden Code ab.
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.