Guten Morgen,
brauche mal eure Hilfe bei einem kleinen Syntax-Fehler. Hier mal der
Code:
int main(void)
{
DDRA = 0x0F;
while(1)
{
PORTA = 3;
_delay_ms(500);
PORTA &= (0<<PA0);
_delay_ms(500);
}
}
LED an Port A.0 blinkt ordnungsgemäß wie erwartet nur die LED A.1 blinkt
gleichzeitig mit. Sie dürfte eigentlich mit der LED an A.0 an gehen und
dann nicht mehr ausgehen.
Verwende gerade das Studio 6.2 mit dem internen C-Compiler. Warum wird
überhaupt ein Schiebebefehl verwendet um Ports zu schalten? Bei BASCOM
ist es doch so einfach. Habe aber gerade eine zeitkritische Anwendung.
Danke HH
HH schrieb:> brauche mal eure Hilfe bei einem kleinen Syntax-Fehler
Da es kompiliert ist es offensichtlich kein Syntax-Fehler... Überleg
doch mal genau was (0 << PA0) für einen Wert hat.
Ja mit
PORTA &= ~(1<<PA0); funktioniert es und mit
PORTA = ~(1<<PA0); blinken die LEDs 0 und 2,3,4,5,6,7 abwechselnd. 3
bleibt ein!
Trinke erst mal einen Kräuter!
Danke
Hallo Curby,
dachte auch dass PORTA &= (0<<PA0); funktioniert und nur A.0
ausschaltet.
Aber eben nur der Befehl PORTA &= ~(1<<PA0); funktioniert. Dann mache
ich es eben so. ;-(
Habe einen Tiny461A dran.
HH schrieb:> Dann mache ich es eben so.
Ich hatte den Tipp mit dem Nachdenken über den < Operator gegeben. Du
solltest ihn befolgen, denn solche Bitoperationen werden dir laufend
begegnen.
Ein Tipp dazu: PA0 ist in einem Headerfile definiert als 0
Curby23523 N. schrieb:> Eigentlich sollte PORTA = 3;> _delay_ms(500);> PORTA &= (0<<PA0);> _delay_ms(500);>> funktionieren.
Aha.
Schon HH schrieb, dass es nicht funktioniert. Das gibt dir nicht zu
Denken ?
Curby23523 N. schrieb:> ICh weiß ja nicht welchen Controller du verwendest. Eigentlich sollte>
1
>PORTA=3;
2
>_delay_ms(500);
3
>PORTA&=(0<<PA0);
4
>_delay_ms(500);
5
>
>> funktionieren. Möglicherweise liegt so etwas vorkonfiguriertes wie JTAG> auf dem Pin?
Klar funktioniert das, deshalb Compiliert das auch ohne Fehler. Aber
auch für dich, überlege mal was
1
PORTA&=(0<<PA0)
Bewirken wird. Grade ein Anfänger wird das falsch interpretieren ;)
Irgendwie bewirkt der Befehl:
PORTA &= (0<<PA0);
dass der gesamte PORTA mit Null überschrieben wird und nicht nur PA.0!
Mache mal Pause ......
Danke für die Hinweise!
HH schrieb:> Irgendwie bewirkt der Befehl:> PORTA &= (0<<PA0);> dass der gesamte PORTA mit Null überschrieben wird und nicht nur PA.0!
schreibe dir es doch einfach auf:
PA0 ist Bit 0
also setzt du die 8 Portsbits auf 0000 0000
Es ist Bit 0 auf 0 gesetzt richtig aber auch Bit 1 bis 7
und nun undierst du alle Bits auf Port A mit 0
was soll da rauskommen ausser 8x NULL?
Maske 0000 0000
PortA 1010 xxxx
---------------
gibt 0000 0000
weswegen wird es wohl richtig mit
PORTA &= ~(1<<PA0)
Maske 0000 0001
negiert 1111 1110
PortA 1010 xxxx
---------------
gibt 1010 xxx0
gemacht?
alle bleiben wie sie sind ausser BIT 0 das wird auf 0 gesetzt gelöscht
HH schrieb:> LED an Port A.0 blinkt ordnungsgemäß wie erwartet nur die LED A.1 blinkt> gleichzeitig mit. Sie dürfte eigentlich mit der LED an A.0 an gehen und> dann nicht mehr ausgehen.MaWin schrieb:> Schon HH schrieb, dass es nicht funktioniert. Das gibt dir nicht zu> Denken ?
Ja, wieder zu schnell gelesen, er möchte, dass der PORT nicht angeht.
Dann bitte in C-Lektüre nachschauen, wie man Bits manipuliert.
HH schrieb:> Trinke erst mal einen Kräuter!
Entweder Programmieren oder Saufen. Beides gleichzeitig funktioniert
eher nicht, da wirst du nur das Saufziel erreichen...
Geringe Mengen Alkohol können allerdings wirklich auch die Kreativität
beim Programmieren erhöhen, so meine Beobachtung. Sie lösen etwas die
Verhaftung in eingefahrene Bahnen.
> Warum wird> überhaupt ein Schiebebefehl verwendet um Ports zu schalten? Bei BASCOM> ist es doch so einfach.
Zum Beispiel solche Veklemmungen... Nein, hier wird kein Schiebebefehl
verwendet. Geschoben wird hier nur zur Compile-Zeit, letztlich ergeben
die Ausdrücke zur Laufzeit eine konstante Zahl.
Du solltest dich mit dem grundsätzlichen Unterschied zwischen
Kompilezeit und Laufzeit auseinandersetzen. Wenn du den begriffen hast,
wird das klarer.
Oh c-hater. Auch schon getrunken?
Mir ist jetzt schon klar, wie es funktioniert. Werde aber wohl nicht
erfahren, warum Mann einen schlüssigen Befehl, um ein Bit zusetzen (also
mit Oder maskiert - mit oder ohne senkrechten Strich) nicht eine
ähnliche Syntax verwendet, um ein Bit zu löschen. In Bascom und in
Pascal für PICs geht es doch. Aber hier wird erst das Einer-Komplement
mit der Tilde gebildet.
Oder seht euch mal CodeVision an.
Aber die Variante von A (Gast) ganz oben gefällt mir ganz gut.
Danke und schönen Sonntag noch.
HH schrieb:> Mir ist jetzt schon klar, wie es funktioniert. Werde aber wohl nicht> erfahren, warum Mann einen schlüssigen Befehl, um ein Bit zusetzen (also> mit Oder maskiert - mit oder ohne senkrechten Strich) nicht eine> ähnliche Syntax verwendet, um ein Bit zu löschen. In Bascom und in> Pascal für PICs geht es doch. Aber hier wird erst das Einer-Komplement> mit der Tilde gebildet.> Oder seht euch mal CodeVision an.
Ich bin mir nicht sicher, ob du mit dieser Einstellung in der C und C++
Welt gut aufgehoben bist.
Denn da wird nicht alles mundgerecht vorgekaut, wie es deiner Meinung
nach sein sollte. Hier muss man die die Dinge selber machen.
HH schrieb:> Aber die Variante von A (Gast) ganz oben gefällt mir ganz gut.
Passt ins Bild.
Es ist fast wie immer. Einige sachliche Antworten und viele am Kern
vobei.
Anfängern oder besser hier > Umsteigern < wird unterstellt, dass sie es
besser lassen sollten.
Ja, Arduino F, vielleicht bist Du in diesem Forum falsch mit Deiner
Einstellung. Deine Beiträge an anderer Stelle "passen ins Bild"!
Also weiter so .....
HH schrieb:> Oh c-hater. Auch schon getrunken?>> Mir ist jetzt schon klar, wie es funktioniert.
Das glaube ich nicht.
> Werde aber wohl nicht erfahren, warum Mann einen schlüssigen Befehl, um> ein Bit zusetzen (also mit Oder maskiert - mit oder ohne senkrechten> Strich) nicht eine ähnliche Syntax verwendet, um ein Bit zu löschen.
Weil das nicht primär die "Befehle" sind, um ein Bit zu setzen oder zu
löschen. Sie werden nur unter anderem auch dafür verwendet.
Sven A. schrieb:> was spricht denn dagegen? das steht sogar im datenblatt der controller,> bei denen es möglich ist, das man so den pin toggled.
Dass du das "^" vergessen hast vor dem "=" ;)
M. K. schrieb:> Dass du das "^" vergessen hast vor dem "=" ;)
Nein, hat er nicht. Bei halbwegs aktuellen AVRs kann man ein Bit in
einem PORT-Register toggeln, indem man eine 1 in das entsprechende Bit
des dazugehörigen PIN-Registers schreibt.
Sven A. schrieb:> was spricht denn dagegen?
Mir würde nur einfallen, dass es bei Portierung auf einen älteren AVR zu
fiesen, schwer zu findenden Fehlern kommen könnte.
M. K. schrieb:> Dass du das "^" vergessen hast vor dem "=" ;)
Sorry, die Anweisung an PINx! ist schon ok, man findet diese Eigenschaft
zum Toggeln eines Bits bei "neueren" Amtel µC nur versteckt im
Datenblatt.
Arduino F. schrieb:> HH schrieb:>> Mir ist jetzt schon klar, wie es funktioniert. Werde aber wohl nicht>> erfahren, warum Mann einen schlüssigen Befehl, um ein Bit zusetzen (also>> mit Oder maskiert - mit oder ohne senkrechten Strich) nicht eine>> ähnliche Syntax verwendet, um ein Bit zu löschen. In Bascom und in>> Pascal für PICs geht es doch. Aber hier wird erst das Einer-Komplement>> mit der Tilde gebildet.>> Oder seht euch mal CodeVision an.>>> Ich bin mir nicht sicher, ob du mit dieser Einstellung in der C und C++> Welt gut aufgehoben bist.
Die eigentliche Frage ist doch (und die finde ich berechtigt):
Warum benötige ich zur Manipulation einzelner Bits einen Datentyp
uint8_t, der ja vorzeichenlose Ganzzahlen repräsentieren soll?
Was er möchte ist ein Datentyp, der einfach nur eine Ansammlung von Bits
darstellt, und der dann Operationen zum Setzen / Löschen einzelner Bits
anbietet.
Und da ist er doch in der C++-Welt sehr gut aufgehoben ;-) Damit könnte
man auch die Problematik des RMW lösen ...
Wilhelm M. schrieb:> Warum benötige ich zur Manipulation einzelner Bits einen Datentyp> uint8_t, der ja vorzeichenlose Ganzzahlen repräsentieren soll?> Was er möchte ist ein Datentyp, der einfach nur eine Ansammlung von Bits> darstellt, und der dann Operationen zum Setzen / Löschen einzelner Bits> anbietet.> Und da ist er doch in der C++-Welt sehr gut aufgehoben ;-) Damit könnte> man auch die Problematik des RMW lösen ...
Dir steht es natürlich frei eine Bitstruct darüber zu legen. Der
Compiler muss trotzdem einen Zugriff auf das Register machen, das bei
diesem Controller funktioniert. Das wird hier eben 8 Bit sein.
Wobei es bei manchen uC auch Bereiche gibt die Bit adressiert sind.
Hallo Wilhelm M. schrieb:> Warum benötige ich zur Manipulation einzelner Bits einen Datentyp> uint8_t, der ja vorzeichenlose Ganzzahlen repräsentieren soll?
Die Frage ist doch schnell beantwortet, da ein Port eines AVR µC 8 Bit
Breit ist.
Das "soll" ist doch eher ein "ist".
Und wenn in "C" programmiert wird, dann kann man sich seine eigenen
Zugriffe auf Pins basierend auf einem Port programmieren, so dass einem
die Syntax zusagt.
Hier geht es wirklich nur um das Aussehen, um mehr nicht.
Also warum der ganze Stress?
Anderer Frank schrieb:> Wilhelm M. schrieb:>> Warum benötige ich zur Manipulation einzelner Bits einen Datentyp>> uint8_t, der ja vorzeichenlose Ganzzahlen repräsentieren soll?>> Was er möchte ist ein Datentyp, der einfach nur eine Ansammlung von Bits>> darstellt, und der dann Operationen zum Setzen / Löschen einzelner Bits>> anbietet.>> Und da ist er doch in der C++-Welt sehr gut aufgehoben ;-) Damit könnte>> man auch die Problematik des RMW lösen ...>> Dir steht es natürlich frei eine Bitstruct darüber zu legen.
Ja, das mache ich auch schon sehr lange so ... und mittlerweile ist so
etwas in rudimentärer Form (eine Ansammlung von Bits) auch in der
libstdc++ enthalten ;-)
Karl M. schrieb:> Hallo Wilhelm M. schrieb:>> Warum benötige ich zur Manipulation einzelner Bits einen Datentyp>> uint8_t, der ja vorzeichenlose Ganzzahlen repräsentieren soll?>> Die Frage ist doch schnell beantwortet, da ein Port eines AVR µC 8 Bit> Breit ist.
8-Bit als ein Byte zusammengefasst: ja.
Aber diese 8-Bit immer als Ganzzahl interpretieren: klares nein.
> Hier geht es wirklich nur um das Aussehen, um mehr nicht.
Nein. Es geht darum, den Code ausdrücken zu lassen, was er bedeutet. Und
da ist es eben unsinnig, 8-Bits eines Ports zu einer Ganzzahl zusammen
zu fassen. Es sind einfach nur 8 (zusammenhanglose) Bits.
> Also warum der ganze Stress?
Welcher Stress?
Wilhelm M. schrieb:> Karl M. schrieb:>> Hallo Wilhelm M. schrieb:>>> Warum benötige ich zur Manipulation einzelner Bits einen Datentyp>>> uint8_t, der ja vorzeichenlose Ganzzahlen repräsentieren soll?>>>> Die Frage ist doch schnell beantwortet, da ein Port eines AVR µC 8 Bit>> Breit ist.>> 8-Bit als ein Byte zusammengefasst: ja.>> Aber diese 8-Bit immer als Ganzzahl interpretieren: klares nein.
Tut man ja auch weder bei dem &, noch bei dem <<. Man shiftet ja Bits
und nicht eine Ganzzahl. Man interpretiert sie in dem Fall lediglich als
einen zusammengehörigen Block aus 8 Bits, aber nicht als Ganzzahl.
Rolf M. schrieb:> Wilhelm M. schrieb:>> Karl M. schrieb:>>> Hallo Wilhelm M. schrieb:>>>> Warum benötige ich zur Manipulation einzelner Bits einen Datentyp>>>> uint8_t, der ja vorzeichenlose Ganzzahlen repräsentieren soll?>>>>>> Die Frage ist doch schnell beantwortet, da ein Port eines AVR µC 8 Bit>>> Breit ist.>>>> 8-Bit als ein Byte zusammengefasst: ja.>>>> Aber diese 8-Bit immer als Ganzzahl interpretieren: klares nein.>> Tut man ja auch weder bei dem &, noch bei dem <<. Man shiftet ja Bits> und nicht eine Ganzzahl. Man interpretiert sie in dem Fall lediglich als> einen zusammengehörigen Block aus 8 Bits, aber nicht als Ganzzahl.
Dann lies mal genauer:
http://en.cppreference.com/w/c/language/operator_arithmetic
Rolf M. schrieb:> M. K. schrieb:>> Dass du das "^" vergessen hast vor dem "=" ;)>> Nein, hat er nicht. Bei halbwegs aktuellen AVRs kann man ein Bit in> einem PORT-Register toggeln, indem man eine 1 in das entsprechende Bit> des dazugehörigen PIN-Registers schreibt.
Achja, stimmt ja. Da war ja noch was mit PINx...wo ist mein Kaffee?
Arduino F. schrieb:> Wilhelm M. schrieb:>> Ja, das mache ich auch schon sehr lange so ...> Zeigen!> (bitte)
Grundsätzlich: primitive Datentypen sind die kleinsten "Bausteine".
Allerdings, sind sie in vielen Einsatzbereichen sowohl im Wertebereich
wie auch in der Operationenmenge unpassend. Zudem tragen sie keinerlei
Semantik. Das ist der Tatsache geschuldet, das wir es mit einer
general-purpose Sprache zu tun haben (irgendetwas muss die Sprache ja
bereitstellen). Für seine eigene, projektspezifische Problemdomäne
sollte man sich eigene Datentypen maßgeschneidert erstellen.
Nun, es geht darum, einen Typ zu erstellen, der ein Byte, d.h. eine
geordnete Sammlung von 8-Bits darstellt. Da diese 8-Bits zunächst keine
Semantik haben, macht es keinen Sinn
i) implizite Typkonversionen von/zu arithmetischen DT zu erlauben
ii) arithmetische Rechenoperationen
zuzulassen. Als erlaubte Operationen kommt zunächst mal nur die
Kopierzuweisung und die Kopierkonstruktion in Betracht.
Also
1
autox=Byte{42};
2
autoy=x;
3
y=x;
soll möglich sein, aber
1
autoz1=2*x;
2
autoz2=x+y;
soll nicht möglich sein.
Die erste Möglichkeit, wäre ein Typ
1
structByte{
2
uint8_tvalue;
3
};
zu schreiben. Eine andere Möglichkeit ist:
1
enumclassbyte:uint8_t{};
Ich habe die zweite Variante genommen, denn es gab mal einen
gcc-Optimizer isra-Bug, der mit der ersten manchmal Schwierigkeiten
hatte. Die scoped-enum Variante benutzt auch libstdc++.
Jetzt kann man anfangen, seine gewünschten Operation hinzuzufügen, etwa:
und andere.
Wobei man die Operatoren dann besser als SFINAE-enabled templates
schreibt, falls man auch noch andere Bit-Typen hat, wie etwa Nibble,
o.ä.
*Achtung*: an dieser Stelle kommt regelmäßig der Einwand:
Was, sooo viel Aufwand. Das mache ich doch mit C und int einfacher.
Dazu ist natürlich zu bedenken:
a) den Aufwand macht man sich für seine N-Projekte genau einmal.
b) für den Klienten ist es eben nicht aufwändiger
c) ich gewinne Sicherheit im Sinne von "ease to use, hard to misuse"
d) der Code wird expressiver
Das war es in Kürze und nur ganz grob.
Sven A. schrieb:> was spricht denn dagegen? das steht sogar im datenblatt der controller,> bei denen es möglich ist, das man so den pin toggled.
Dagegen spricht, daß jeder erstmal grübelt, wenn er nicht das Datenblatt
im Kopf hat. Ich benutze es daher absichtlich nicht. In der Regel ist
der Einspareffekt unerheblich.
Peter D. schrieb:> Sven A. schrieb:>> was spricht denn dagegen? das steht sogar im datenblatt der controller,>> bei denen es möglich ist, das man so den pin toggled.>> Dagegen spricht, daß jeder erstmal grübelt, wenn er nicht das Datenblatt> im Kopf hat. Ich benutze es daher absichtlich nicht. In der Regel ist> der Einspareffekt unerheblich.
Schaltest Du dann bei einem unechtem RMW auch die Interrupts aus und
legst die anderen Kerne still?
Wilhelm M. schrieb:>> Tut man ja auch weder bei dem &, noch bei dem <<. Man shiftet ja Bits>> und nicht eine Ganzzahl. Man interpretiert sie in dem Fall lediglich als>> einen zusammengehörigen Block aus 8 Bits, aber nicht als Ganzzahl.>> Dann lies mal genauer:>> http://en.cppreference.com/w/c/language/operator_arithmetic
Und dann?