mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Problem mit dem überschreiben einer Variable


Autor: Oliver Kra (Firma: TGM) (oliver1990)
Datum:
Angehängte Dateien:

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

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

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

Autor: Volker Zabe (vza)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
suche mal nach "volatile"

Autor: Ga st (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> suche mal nach "volatile"
Wozu sollte er das tun?

Autor: Oliver Kra (Firma: TGM) (oliver1990)
Datum:

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

Autor: Oliver Kra (Firma: TGM) (oliver1990)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ga st schrieb:
>> suche mal nach "volatile"
> Wozu sollte er das tun?

Was soll das sein? Naja ich google mal.

Autor: Volker Zabe (vza)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hast Recht, ist nicht nötig. Ich habe mich vertan.

Autor: Oliver Kra (Firma: TGM) (oliver1990)
Datum:

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

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

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

Autor: Oliver Kra (Firma: TGM) (oliver1990)
Datum:

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

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

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

Autor: Oliver Kra (Firma: TGM) (oliver1990)
Datum:

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

Autor: Oliver Kra (Firma: TGM) (oliver1990)
Datum:

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

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Oder denk ich hier vollkommen falsch?
Nein. Soweit passt das zum Setzen eines Bits.

Nur das Rücksetzen muß über eine VerUNDung gehen...

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

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

Autor: Oliver Kra (Firma: TGM) (oliver1990)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Aja, ok, hab schon wieder mal nicht weitergelesen.
Danke, werd gleich mal probieren ob es jetzt funkt.

Autor: Oliver Kra (Firma: TGM) (oliver1990)
Datum:

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

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

Autor: Oliver Kra (Firma: TGM) (oliver1990)
Datum:

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

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

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

Autor: Oliver Kra (Firma: TGM) (oliver1990)
Datum:

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

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

Autor: Oliver Kra (Firma: TGM) (oliver1990)
Datum:

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

Autor: Juergen (Gast)
Datum:

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

Autor: Oliver Kra (Firma: TGM) (oliver1990)
Datum:

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

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

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.