Forum: Mikrocontroller und Digitale Elektronik Eine "1" um x Schritte verschieben


von M.B. (Gast)


Lesenswert?

Ich möchte gerne 8 Signale auswerten und Abweichungen über 8 LED's an 
PORT B ausgeben.
Um mir mit meinem AVR ATmega die Arbeit leicht zu machen, möchte ich 
durch eine Schleife und Bitschieben die Ausgabe "vorkonfigurieren". Der 
Ansatz ist unten aufgelistet. Kann ich das so machen, sind meine 
Gedanken richtig?
1
Ausgabe =0;
2
for(i=1;i<=8;i++)
3
{
4
  if istwert[i] >= sollwert 
5
    Ausgabe |= (1<<i);
6
}
7
PortB= Ausgabe;

Wenn meine Abweichungen jetzt bei Wert 1, 3 und 6 sind sollen 
entsprechend die LED's 1,3 und 6 leuchten. Mein Ausgabe- 
Zwischenspeicher ist 0 und es soll die "1" um i Stellen in den Zwischen 
speicher geschoben werden:
- eine "1" um eine Stelle nach links (Ausgabe = 0b 0000 0001) mit (1<<1)
- eine "1" um drei Stellen nach links (Ausgabe = 0b 0000 0101) mit 
(1<<3)
- eine "1" um sechs Stellen nach links (Ausgabe = 0b 0010 0101) mit 
(1<<6)

Danach möchte ich den Zwischenspeicher an die LED's ausgeben mit PortB = 
0b 0010 0101

Ist das so korrekt?

von Johannes M. (johnny-m)


Lesenswert?

M.B. wrote:
> - eine "1" um eine Stelle nach links (Ausgabe = 0b 0000 0001) mit (1<<1)
Nö, das was da binär steht ist (1 << 0), also eine 1, die um null 
Stellen nach links geschoben ist!

> - eine "1" um drei Stellen nach links (Ausgabe = 0b 0000 0101) mit
> (1<<3)
(1 << 3) wäre 0b00001000...

von M.B. (Gast)


Lesenswert?

Ah ja richtig. Die "Grundstellung" ist ja 0b 0000 0001 und dann die 
Stellen der Verschiebung.
Danke für den Tipp, hatte ich nicht bedacht. Guter hinweis.

Aber hierzu:
>> - eine "1" um drei Stellen nach links (Ausgabe = 0b 0000 0101) mit
>> (1<<3)
>(1 << 3) wäre 0b00001000...

wie du im Code siehst ist das ganze ja verodert mit "|=" da soll der 
Wert von vorher ja beibehalten werden und die um drei Stellen 
verschobene "1" dazugerechnet werden.

von Karl H. (kbuchegg)


Lesenswert?

M.B. wrote:

> Ist das so korrekt?

Im Prinzip passt das schon so. (Nach der Korrektur, dass i bei 0 anfängt 
und nicht bei 1)

Das einzige, was du bedenken solltest: Die Operation 1 << i ist für 
einen AVR ziemlich aufwändig, weil sie nicht in einem Schritt gemacht 
werden kann, sondern der Compiler muss das seinerseits als Schleife 
implementieren, bei der die 1 jeweils i mal um 1 geschoben wird. (Ausser 
natürlich: der Optimizer des Compilers ist seeeeehr gut. Da würde ich 
aber nicht drauf wetten). Da dein i aber schön aufsteigend durchlaufen 
wird, kannst du das auch selber etwas besser formulieren
1
  Ausgabe =0;
2
  Mask = 1;
3
4
  for( i = 1; i <= 8; i++ )
5
  {
6
    if( istwert[i] >= sollwert )
7
      Ausgabe |= Mask;
8
    Mask = Mask << 1;
9
  }
10
11
  PortB = Ausgabe;

PS: Bist du sicher, dass dein Array istwert wirklich von der Länge 9 
ist? Ansonsten greifst du auf das Array 'out of Bounds' zu. Ein Array

int istwert[8];

besitzt 8 Elemente. Diese haben die Indizes: 0, 1, 2, 3, 4, 5, 6, 7
(und keinen Index 8!). Zähl nach, es sind genau 8 Elemente.

Die übliche for-Schleife, um so ein Array abzuabeiten lautet daher

    for( i = 0; i < 8; i++ )

sie beginnt bei 0, und in der Vergleichsbedingung (welche immer auf 
"kleiner" lautet), steht die Arraygröße und nicht der höchste Index.

Ich würde daher wetten, dass dein Code eigentlich so aussehen sollte
1
  Ausgabe =0;
2
  Mask = 1;
3
4
  for( i = 0; i < 8; i++ )
5
  {
6
    if( istwert[i] >= sollwert )
7
      Ausgabe |= Mask;
8
    Mask = Mask << 1;
9
  }
10
11
  PortB = Ausgabe;

von M.B. (Gast)


Lesenswert?

Hallo Karl heinz, Danke für die Info.
Ich bin immer froh für Tipps zur Codeoptimierung.

Mein Array ist wirklich von der Länge 9, wobei ich die 0 leer lasse. 
(Platz habe ich genug)
Weil ich es einfach nicht so umständlich finde.Ich habe 1 bis 8 Signale 
durchlaufe die Schleife 1- 8 mal und die LED's 1 bis 8 leuchten. Für 
mich wäre es dann irritierend wenn ich dann in den Speicherzellen 0-7 
die Werte speicher. War jetzt der Wert 4 für die vierte oder fünfte LED 
oder Signal. Oder war es doch das dritte?
So kann ich mir einfach merken in Zelle 4 steht das Signla des 4. 
Signals und ist für LED 4. Zelle 0 kann ich zur Not mit anderen Sachen 
benutzen falls erforderlich, für Summen oder zur Korntrolle oder für 
Zwischenwerte.

Mein Code dafür würde dann so aussehen:
1
 Ausgabe =0;
2
  Mask = 1;
3
4
  for( i = 0; i < 8; i++ )
5
  {
6
    if( istwert[i+1] >= sollwert )
7
      Ausgabe |= Mask;
8
    Mask = Mask << 1;
9
  }
10
11
  PortB = Ausgabe;

Nochmal vielen Dank für die Hinweise!

von Johannes M. (johnny-m)


Lesenswert?

@M.B.:
Du solltest Dir dringend die in der Technik übliche Zählweise 
angewöhnen, sonst kommst Du irgendwann wirklich durcheinander! Bei 
solchen Zusammenhängen, bei denen es um Bits in Variablen oder Registern 
geht, fängt die Zählung grundsätzlich bei 0 an, nicht bei 1. Auch Deine 
LEDs solltest Du von 0 bis 7 durchnummerieren, schließlich heißen die 
Portpins auch PORTx0...7 und nicht anders. Wenn Du das nicht 
verinnerlichst, wirst Du irgendwann massive Probleme bekommen. Das mit 
dem 1<<1 oben wäre Dir nämlich auch nicht passiert, wenn Du daran 
gedacht hättest...

von M.B. (Gast)


Lesenswert?

Hallo Johannes,

ich werde darüber nachndenken. Hört sich schlüssig an. Besser frühzeitig 
umdenken als zu spät - aber für mich ist es halt noch eher umständlich.

Aber ich werde mich bemühen - versprochen!

von Johannes M. (johnny-m)


Lesenswert?

M.B. wrote:
> ich werde darüber nachndenken. Hört sich schlüssig an. Besser frühzeitig
> umdenken als zu spät
Genau das ist der Punkt. Nicht erst was falsches angewöhnen.

> - aber für mich ist es halt noch eher umständlich.
Nun, das sind viele Dinge auf den ersten Blick. Nur werden sie noch 
komplizierter, wenn man versucht, mit irgendwelchen Verrenkungen drumrum 
zu kommen...

von Stephan H. (stephan-)


Lesenswert?

spätetens wenn man wegen einem Bit ein zusätzliches Byte anfassen muß.

von Karl H. (kbuchegg)


Lesenswert?

Auch ist es deinem Compiler ziemlich egal, wo du für dich den ersten 
Index in ein Array siehst. Spätestens bei Strings kocht der sowieso sein 
eigenes Süppchen und lässt das char Array in dem ein String gespeichert 
ist beim Index 0 anfangen.

  char Test = "Hello world";

das 'H' ist nun mal an Position Test[0].

Auch vereinfachen sich viele Index-Berechnungsvorgänge, wenn man den 
ersten Index als 0 annimmt. Das ganze ist also nicht nur akademisch 
sondern hat durchaus einen ernsten Hintergrund.

Bsp: Du brauchst eine Umsetztabelle, die Zahlenwerte von 80 bis 83 
(jeweils inklusive) in neue Zahlen umsetzt.

    80   ->   256
    81   ->   123
    82   ->   205
    83   ->    78

Wie ist der übliche Ansatz:

   char Table[] = { 256, 123, 205, 78 };

   int NewValue = Table[ OldValue - 80 ];

Wenn OldValue den Wert 80 hat, dann ergibt OldValue - 80 die 0. Also den 
Index des ersten Eintrags.

Wenn du dein System konsistent durchziehen willst, dann müsstest du 
schreiben

   char Table[] = { 0, 256, 123, 205, 78 };

   int NewValue = Table[ OldValue - 80 + 1 ];

und das gibt es oft: Wenn Indizes berechnet werden müssen, sind die 
Formeln einfacher, wenn der erste Index die 0 hat.

von Johannes M. (johnny-m)


Lesenswert?

Karl heinz Buchegger wrote:
>    char Table[] = { 256, 123, 205, 78 };
Hmm, mit char wird das aber nix...

(Wenn Du es korrigiert hast, kannste dieses dann gegenstandslose Posting 
löschen...)

von Karl H. (kbuchegg)


Lesenswert?

Johannes M. wrote:
> Karl heinz Buchegger wrote:
>>    char Table[] = { 256, 123, 205, 78 };
> Hmm, mit char wird das aber nix...

LOL.
Danke für die Korrektur.

> (Wenn Du es korrigiert hast, kannste dieses dann gegenstandslose
> Posting löschen...)

Kanns im Original nicht mehr korrigieren. Daher bleibt auch dein absolut 
korrekter Fehleraufschrei da :-)

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.