Ports binär weiterschalten

OP #4665991
Lesenswert?

Ich möchte gerne folgendes Bit-Muster mit einer Tasteneingabe hochzählen 
und mit einer anderen taste runterzählen:

0000 0000
0001 0000
0010 0000
0011 0000

und das gleiche mit:

0000 0000
0000 0100
0000 1000
0000 1100

Wenn das letzte Bitmuster erreicht ist und man schaltet weiter soll 
wieder von vorne begonnen werden.
Wie stell ich das am einfachsten an?

Es sollen ja immer nur 2 Bits fortlaufend geändert werden.

Soll ich hier binär oder doch lieber Hex zählen? -> Wäre jetzt 
Profimäßig geklärt...
#4666007
Lesenswert?

Dem Prozessor ist es völlig wurscht. Binär oder Hexadezimal sind nur 
verschiedene Darstellungsarten. Die Daten und die Rechenoperationen, die 
im Programm ausgeführt werden, sind exakt die selben.
Daher nimm das, was besser lesbar ist. Da du uns die Sprache 
verheimlichst, kann man da wenig Tipps geben.

Lokus P. schrieb:
> Wie siehts jetzt mit dem Rest aus?

Welchem Rest?
#4666110
Lesenswert?

Rolf M. schrieb:
> Wie in einem Thread nebenan letztens ausführlich diskutiert, ist beides
> nicht zulässig, da das Verhalten in C undefiniert ist. Es muss heißen:

Unabhängig davon, daß ich hier auch (p+1) bevorzugen würde (weil 
"schöner"), sehe ich an (++p) aber weder ein undefiniertes Verhalten, 
noch warum es unzulässig sein soll!?
Auch (p++) ist zulässig und definiert, führt hier bei "p = (p++)" aber 
nicht zur Veränderung der Variablen p.
Gast #4666218
Lesenswert?

..eher armselig ist die Fragestellung!

Die stellt kein Fünfjähriger mehr.

Nimm mal ein Blatt Papier und nen Bleistift.

Auf Tastendruck erhöht sich eine Variable jeweils von Null um den Wert 
16.
Also 0,16,32,48. Bei 48 soll es umgekehrt laufen.

Wer das Problem löst, bekommt einen Nobelpreis. Haha
#4666246
Lesenswert?

Lokus P. schrieb:
> Was soll Ausgabe1 darstellen?
> ...
> oder wie?
1
void right()
2
 {
3
   int p;  // tmp, Zähler selbst ist Teil von OUT_PORT
4

5
   p = (OUT_PORT>>4) & 3;  // 3 ist max 2Bit, 4 ist Ausgabeposition
6
   P = (p+1) % 4;          // 0..3
7

8
   OUT_PORT =   OUT_PORT & ~(3<<4)    // Bit 4..5 "frei machen"
9
              | (P<<4);               // Zähler wieder einfügen
10
   ...
11
 }

Die magischen Zahlen kann man besser als SHIFT und MASK einmal 
festlegen, via #define oder static const (oder constexpr, wenn man 
dessen Sprache spricht)

Der Zähler könnte natürlich auch außerhalb des OUT_PORT leben, als 
globale Variable

@Db:
Einfach nur 16 draufaddieren funktioniert natürlich nur, wenn man kein 
Problem mit den Überlauf des Zählers auf das 3.Bit hat.

Besser geht das mit C++ (mit avr-gcc5.3),da bin ich gerade am Erkunden 
von C++11/14. Mit etwas variadic template kann man die Bits, die man 
hoch/runter zählen will in jeder beliebigen Reihenfolge auf jedem 
vorhandenen PORT verteilen.
#4666262
Lesenswert?

Thomas E. schrieb:
> Rolf M. schrieb:
>> Wie in einem Thread nebenan letztens ausführlich diskutiert, ist beides
>> nicht zulässig, da das Verhalten in C undefiniert ist. Es muss heißen:
>
> Unabhängig davon, daß ich hier auch (p+1) bevorzugen würde (weil
> "schöner"), sehe ich an (++p) aber weder ein undefiniertes Verhalten,
> noch warum es unzulässig sein soll!?

Nicht das (++p) alleine, sondern in Kombination mit der Zuweisung.

> Auch (p++) ist zulässig und definiert, führt hier bei "p = (p++)" aber
> nicht zur Veränderung der Variablen p.

Es fürt zu undefiniertem Verhalten laut ISO C, da die Variable p zweimal 
beschrieben wird, ohne dass ein Sequenzpunkt dazwischen liegt.
Aber wie gesagt, das wurde letztens schon ausführlichst diskutiert.
Gast #4666266
Lesenswert?

Lokus P. schrieb:

> eher armselig.

Armselig ist deine Frage. Jeder mit Minimal-Eigenintelligenz würde sich 
schämen, sie überhaupt gestellt zu haben...

Denn sie beweist:
1) Du hast keine Ahnung von binärer Logik.
2) Du hast keine Ahnung von der Programmiersprache, die du verwendest.

Damit: Du tust etwas, wozu dir sämtliche essentiellen Grundlagen fehlen.

Mehr noch: Dir ist nicht einmal klar, dass diese Grundlagen essentiell 
sind und dass sie dir fehlen.

Klar: dann muss natürlich jeder Hinweis auf diesen Problemkreis aus 
deiner Sicht einer Beleidigung gleichkommen. Ist aber keine...

Es ist einfach so: ein wirklich Doofer kann einfach nicht erkennen, dass 
er doof ist...
OP #4666296
Lesenswert?

Carl D. schrieb:
> Lokus P. schrieb:
>> Was soll Ausgabe1 darstellen?
>> ...
>> oder wie?
> void right()
>  {
>    int p;  // tmp, Zähler selbst ist Teil von OUT_PORT
>
>    p = (OUT_PORT>>4) & 3;  // 3 ist max 2Bit, 4 ist Ausgabeposition
>    P = (p+1) % 4;          // 0..3
>
>    OUT_PORT =   OUT_PORT & ~(3<<4)    // Bit 4..5 "frei machen"
>               | (P<<4);               // Zähler wieder einfügen
>    ...
>  }
>
> Die magischen Zahlen kann man besser als SHIFT und MASK einmal
> festlegen, via #define oder static const (oder constexpr, wenn man
> dessen Sprache spricht)
>
> Der Zähler könnte natürlich auch außerhalb des OUT_PORT leben, als
> globale Variable
>
> @Db:
> Einfach nur 16 draufaddieren funktioniert natürlich nur, wenn man kein
> Problem mit den Überlauf des Zählers auf das 3.Bit hat.
>
> Besser geht das mit C++ (mit avr-gcc5.3),da bin ich gerade am Erkunden
> von C++11/14. Mit etwas variadic template kann man die Bits, die man
> hoch/runter zählen will in jeder beliebigen Reihenfolge auf jedem
> vorhandenen PORT verteilen.

Das funktioniert doweit, danke.
Aber warum bekomme ich diesen Warnhinweis:

../main.c:104: warning: suggest parentheses around arithmetic in operand 
of |

bei der Zeile: OUT_PORT = OUT_PORT & ~(3<<4) | (p<<4);
Gast #4666311
Lesenswert?

c-hater schrieb:
> Es ist einfach so: ein wirklich Doofer kann einfach nicht erkennen, dass
> er doof ist...

...und ein kaltschnäuziger, arroganter Mensch kann einfach nicht 
erkennen, daß er NICHT der Nabel der Welt ist.

Auch wenn ich dir hier in der Sache völlig recht gebe, aber deine 
Ausdrucksweise macht deiner Mutter klar, daß sie mit deiner Erziehung 
auf ganzer Linie völlig versagt hat.
Gast #4666317
Lesenswert?

> Aber warum bekomme ich diesen Warnhinweis:
>
> ../main.c:104: warning: suggest parentheses around arithmetic in operand
> of |
>
> bei der Zeile: OUT_PORT = OUT_PORT & ~(3<<4) | (p<<4);

Weil es sehr schlechter Stil ist, bei Binäroperatoren Klammern 
wegzulassen. Deren Präzedenz ist teilweise unintuitiv und führt ohne 
Klammern schnell zu Fehlern.

Ich würde übrigens in zwei getrennten globalen Variablen zählen, und aus 
den aktuellen Zählerständen dann die Ausgabe auf den Port 
zusammensetzen.
#4666330
Lesenswert?

holger schrieb:
>>Aber warum bekomme ich diesen Warnhinweis:
>> ../main.c:104: warning: suggest parentheses around arithmetic in operand
>> of |
>>
>> bei der Zeile: OUT_PORT = OUT_PORT & ~(3<<4) | (p<<4);
> Weil da Klammern fehlen.

Ja, aber nicht wie's der Compiler vorschlägt, denn erst muß man die Bits 
maskieren (&) und dann den neuen Wert einfügen (|).

@Lokus:
Schreib es so:
1
OUT_PORT = ( OUT_PORT & ~(3<<4) ) | (p<<4);
dann versteht es der GCC (und vielleicht auch sonst noch wer)
#4666335
Lesenswert?

Rolf M. schrieb:
> Es fürt zu undefiniertem Verhalten laut ISO C, da die Variable p zweimal
> beschrieben wird, ohne dass ein Sequenzpunkt dazwischen liegt.
> Aber wie gesagt, das wurde letztens schon ausführlichst diskutiert.

Sorry, habe diese Diskussion offenbar wohl nicht verfolgt, und weiß auch 
nicht, wo/wie ich danach suchen soll.

Ist es nicht so, daß bei einer Zuweisung zuerst der Ausdruck rechts vom 
"=" ausgewertet wird, und dann der Wert des Ausdrucks der Variablen 
zugewiesen wird? Da sehe ich jedenfalls keinen Raum für Undefiniertes!
OP #4666341
Lesenswert?

Das ganze sieht jetzt so aus:
1
void right()
2
{
3
  int r;
4

5
  r = (OUT_PORT>>4) & 3;
6
  r = (r+1) % 4;
7
  OUT_PORT = (OUT_PORT & ~(3<<4)) | (r<<4);
8
  reset();
9
}
10

11
void left()
12
{
13
  int l;
14

15
  l = (OUT_PORT>>4) & 3;
16
  l = (l-1) % 4;
17
  OUT_PORT = (OUT_PORT & ~(3<<4)) | (l<<4);
18
  reset();
19
}
20

21
void up()
22
{
23
  int u;
24

25
  u = (OUT_PORT>>2) & 3;
26
  u = (u+1) % 4;
27
  OUT_PORT = (OUT_PORT & ~(3<<2)) | (u<<2);
28
  reset();
29
}
30

31
void down()
32
{
33
  int d;
34

35
  d = (OUT_PORT>>2) & 3;
36
  d = (d-1) % 4;
37
  OUT_PORT = (OUT_PORT & ~(3<<2)) | (d<<2);
38
  reset();
39
}

Da ist jedoch noch ein Fehler drinn. Wenn ich die Funktion down() 
aufrufe, werden irgendwann Bit 4 und 5 auch gesetzt.
#4666364
Lesenswert?

Thomas E. schrieb:
> Rolf M. schrieb:
>> Es fürt zu undefiniertem Verhalten laut ISO C, da die Variable p zweimal
>> beschrieben wird, ohne dass ein Sequenzpunkt dazwischen liegt.
>> Aber wie gesagt, das wurde letztens schon ausführlichst diskutiert.
>
> Sorry, habe diese Diskussion offenbar wohl nicht verfolgt, und weiß auch
> nicht, wo/wie ich danach suchen soll.

Ich meinte diese hier:
Beitrag "fragezeichen operator may be undefined"

Am Ende von Beitrag "Re: fragezeichen operator may be undefined" hab ich 
auch nochmal explizit hingeschrieben, was dazu in der 
ISO-C-Spezifikation steht. Die dort angegebenen Beispiele verdeutlichen, 
dass es genau um solche Fälle geht.
In der Diskussion haben das einige auch nicht eingesehen, weil sie sich 
nicht vorstellen können, warum da was schiefgehen sollte. Das ändert 
aber nichts daran. Solche undefinierten Konstrukte hinzuschreiben, ist 
wie mit abgefahrenen Reifen rumfahren und zu ignorieren, dass das 
gefährlicher und außerdem verboten ist, weil ja noch nie was passiert 
ist.

> Ist es nicht so, daß bei einer Zuweisung zuerst der Ausdruck rechts vom
> "=" ausgewertet wird, und dann der Wert des Ausdrucks der Variablen
> zugewiesen wird?

Das schon, aber nicht definiert ist, wann die Nebeneffekte (also das 
Schreiben in die Variable) abgeschlossen ist.
#4666366
Lesenswert?

Das mit dem Modulo muß man natürlich für Zähler bis 2hochN -1 nicht 
machen.
1
...
2
  u = (u+1) & ((1<<2)-1);
3
...
4
  d = (d-1) & ((1<<2)-1);
5
...
Damit zählt man Modulo 4 hoch/runter.

Ich habe mit Absicht stehen gelassen, wie es zur magischen Zahl 3 kommt.
In konkreten Programm sollt man da #define's benutzen (oder bessere 
Nachfolger).
Denn eventuell will man mal 3Bit Zähler, die auf 0..2 und 5..7 am Port 
erscheinen sollen, umstellen. Was bedeutet dann nochmal 2, 3 und 4?
Gast #4666408
Lesenswert?

Lokus P. schrieb:
> Die könnte man zwar ignorieren, aber wie macht man es richtig?

Man könnte es richtig machen und sie nicht ignorieren. Denkst du, die 
Warnung ist ein Scherz? Sieh mal in einem c-Buch nach oder bemühe eine 
Suchmaschine. Du bist sicherlich nicht der erste, der diese Warnung 
bekommt, also findest du die Auflösung sicher bei einer Suchmaschine...

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren