Forum: Mikrocontroller und Digitale Elektronik Ports binär weiterschalten


von Lokus P. (derschatten)


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...

von user (Gast)


Lesenswert?

Lokus P. schrieb:
> Soll ich hier binär oder doch lieber Hex zählen?
Und was macht das an Unterschied?

von Frickelfritze (Gast)


Lesenswert?

Lokus P. schrieb:
> Soll ich hier binär oder doch lieber Hex zählen?

Ich stehe vor einem ähnlichen Problem. Ich hoffe ihr
könnt mir weiterhelfen. Soll ich jetzt Butter oder
Margarine aufs Brot tun?

von Lokus P. (derschatten)


Lesenswert?

Also ob mir das hier jetzt weiterhelfen würde.

von Schlaumeier (Gast)


Lesenswert?

Frickelfritze schrieb:
> Soll ich jetzt Butter oder
> Margarine aufs Brot tun?

Das ist falsch. Es muss "Butter oder Butter" heißen.

Die Zahlendarstellung im Programm spielt keine Rolle, wenn die Variable 
selbst binär ist. (Also int, uint8_t, ...)

von Lokus P. (derschatten)


Lesenswert?

Ok, hätten wir mal die erste Frage geklärt. Wie siehts jetzt mit dem 
Rest aus?

von Rolf M. (rmagnus)


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?

von Thomas E. (picalic)


Lesenswert?

Lokus P. schrieb:
> Ok, hätten wir mal die erste Frage geklärt. Wie siehts jetzt mit dem
> Rest aus?

Mit einer AND-Verknüpfung (C-Operator: &) kannst Du beliebige Bits auf 0 
zwingen, also z.B. ergibt

  1011 0101
& 0011 1100
  ---------
  0011 0100

von W.A. (Gast)


Lesenswert?

Lokus P. schrieb:
> Wie stell ich das am einfachsten an?

zB. etwa so:
1
int p=0;
2
while(1)
3
  {
4
  Ausgabe1(p<<4);
5
  Ausgabe2(p<<2);
6
  p = (p++) & 0x03;
7
  }

von Lokus P. (derschatten)


Lesenswert?

Wie man bits setzt weiß ich auch wie man zählt, aber wie genau definiere 
ich das nur ein bestimmter Bitbereich hochgezählt werden soll.
1
void right()
2
{
3
  unsigned char i;
4
5
  OUT_PORT &= i;                        // Alle PIN = LOW
6
  i++;
7
}

von Simpel (Gast)


Lesenswert?

"wie genau definiere
ich das nur ein bestimmter Bitbereich hochgezählt werden soll?"

Z.B. indem du als Zähleinheit 16 oder 4 addierst anstatt 1...

von Thomas E. (picalic)


Lesenswert?

W.A. schrieb:
> p = (p++) & 0x03;

wohl eher p = (++p) & 0x03;

von Rolf M. (rmagnus)


Lesenswert?

Thomas E. schrieb:
> W.A. schrieb:
>> p = (p++) & 0x03;
>
> wohl eher p = (++p) & 0x03;

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:
1
p = (p+1) & 0x03;
Alternativ:
1
p++;
2
p &= 0x03;

von Thomas E. (picalic)


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.

von Lokus P. (derschatten)


Lesenswert?

Was soll Ausgabe1 darstellen?
1
void right()
2
{
3
  int p=0;
4
5
  OUT_PORT &=(p<<4);                      // Alle PIN = LOW
6
  p = (p+1) & 0x03;
7
  reset();
8
}
oder wie?

von Schlumpf (Gast)


Lesenswert?

Wieso nicht einfach im ersten Fall 16 als Inkrement/Dekrement nehmen und 
im zweiten Fall 4

von Db (Gast)


Lesenswert?

lustig wie das hier völlig entgleist????

von Lokus P. (derschatten)


Lesenswert?

eher armselig.

von Db (Gast)


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

von Carl D. (jcw2)


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.

von Rolf M. (rmagnus)


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.

von c-hater (Gast)


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...

von Lokus P. (derschatten)


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);

von holger (Gast)


Lesenswert?

>Aber warum bekomme ich diesen Warnhinweis:

Weil da Klammern fehlen.

von Jack (Gast)


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.

von Juergen (Gast)


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.

von Carl D. (jcw2)


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)

von Thomas E. (picalic)


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!

von Lokus P. (derschatten)


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.

von Peter II (Gast)


Lesenswert?

Lokus P. schrieb:
> d = (d-1) % 4;

wenn d=0 ist, dann wird d negativ. Dann kommt Unsinn bei, nächsten 
schritt Unsinn raus.

von Rolf M. (rmagnus)


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.

von Carl D. (jcw2)


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?

von Lokus P. (derschatten)


Lesenswert?

noch eine Frage dazu. ich rufe aus der Function noch eine Function auf: 
reset()

Das erzeugt mir eine Warnung: ../main.c:75: warning: implicit 
declaration of function 'reset'

Die könnte man zwar ignorieren, aber wie macht man es richtig? Drauf 
verzichten?

von Jack (Gast)


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...

von Thomas E. (picalic)


Lesenswert?

Rolf M. schrieb:
> Ich meinte diese hier: ...

Danke! Habe inzwischen auch noch selbst ein bisschen gegoogled. Dachte, 
eine Zuweisung wäre praktisch auch schon ein Sequenzpunkt, ist es aber 
dann wohl doch nicht. Man lernt halt nie aus... :)

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
Noch kein Account? Hier anmelden.