Forum: Mikrocontroller und Digitale Elektronik Frage zu Bitmanipulation


von Moe (Gast)


Lesenswert?

Hi,

ich will ein Lauflicht realisieren:


PORTB = PORTB << 1

Das schiebt ja praktisch bei jedem Aufruf ne 1 durch den kompletten 
Port. Problem dabei, die LEDs bleiben ja an. Wie löst man das am besten?

thx, Moe

von A. M. (bacarni) Benutzerseite


Lesenswert?

Das kannst du lösen, indem du eine Led an schaltest, wartest z.B. durch 
einen Timer oder die delay-Funktion, und dann die Voherige ausschaltest 
und die Nächste an. Und dann immer so weiter.

von Gast (Gast)


Lesenswert?

Vielleich meinst du das : nach deiner Zeile ein

PORTB &= 1;

von Praktikant (Gast)


Lesenswert?

0000 0001 = 1
Warten
0000 0010 = 2
Warten
0000 0100 = 4
Warten

usw. usw.

So in diese Richtung vielleicht?

von Moe (Gast)


Lesenswert?

@Gast:

Das kann nicht funktionieren.

@Arnulf:

Ja ne is klar...is ja die Frage wie ich die Bits manipulieren muss damit 
eben  immer nur eine LED an ist.

von Moe (Gast)


Lesenswert?

@Praktikant

Nein, muss über Bitmanipulation gehen. Will nicht den kompletten Port 
beschreiben.

von Falk B. (falk)


Lesenswert?

1
PORTA = 1;
2
3
for (i=0; i<8; i++) {
4
  _delay_ms(100);
5
  PORTA <<= 1;
6
}

von Johannes M. (johnny-m)


Lesenswert?

Moe wrote:
> PORTB = PORTB << 1
>
> Das schiebt ja praktisch bei jedem Aufruf ne 1 durch den kompletten
> Port.
Nö. Es schiebt den Inhalt von PORTB um eine Stelle nach links. Wenn in 
PORTB vorher keine 1 stand, dann wird auch keine 1 geschoben.

Wenn Du willst, dass immer nur eine LED leuchtet, musst Du hinten 
jeweils wieder ne 1 anhängen (also das Bit Nr. 0 auf 1 setzen).

Bsp.:
Anfang: PORTB: 11111110
-> PORTB <<= 1;
-->     PORTB: 11111100
-> PORTB |= 1; (letztes Bit 1 setzen)
-->     PORTB: 11111101
usw...
Da musste jetzt noch Code machen, den Dein Compiler versteht

EDIT:
Wenn die LEDs Low-Side angeschlossen sind, dann sieht das natürlich 
anders aus. Ich bin jetzt von High-Side angeschlossenen LEDs ausgegangen 
(Portpin 0 -> LED leuchtet).

von hans (Gast)


Lesenswert?

Abhilfe schaft ein Portsave.

Problem ist Read-Modify-Write.
Daher Char ändern und schreiben

unsigned char pas=1;

while(1){
  pas<<= 1;
  if (pas==0)pas=1;
  PORTA =pas;
  _delay_ms(100);
  PORTA =pas;
}

das geht bestimmt!!!
gruß hans

von Moe (Gast)


Lesenswert?

Also nochmal:


Ich hab schon nen Timer der X mal in der Sekunde nen Interrupt auslöst.

So und mit meinem Code geht eine LED nach der anderen an bis alle an 
sind und dann werden sie praktisch wieder eingeschaltet. Es sollte aber 
immer nur eine LED an sein.

Startwert ist PORTB = 0xFF // Alle LEDS aus

11111111
01111111
10111111
11011111
.
.
.
so sollte es aussehen, ohne einen hexwert auf den kompletten port zu 
schreiben. Geht das?

Moe

von Moe (Gast)


Lesenswert?

natürlich andersrum:

11111111
11111110
11111101
11111011

Der Beitrag  von Johannes hört sich schonmal ganz gut an.

von Johannes M. (johnny-m)


Lesenswert?

Moe wrote:
> natürlich andersrum:
>
> 11111111
> 11111110
> 11111101
> 11111011
>
> Der Beitrag  von Johannes hört sich schonmal ganz gut an.
Die eleganteste Methode wäre, jeweils das höchstwertige Bit zu sichern 
und beim nächsten Schieben wieder hinten dranzuhängen. In Assembler 
geht das übrigens ganz einfach. In C ist es komplizierter...

von Moe (Gast)


Lesenswert?

Wäre evtl. was ja. Man kann doch ASM auch in C integrieren? :-)

von Moe (Gast)


Lesenswert?

Wenns noch andere saubere Möglichkeiten gibt bin ich natürlich auch 
dabei.

von Falk B. (falk)


Lesenswert?

@ Johannes M. (johnny-m)

>> 11111111
>> 11111110
>> 11111101
>> 11111011
>
> Der Beitrag  von Johannes hört sich schonmal ganz gut an.
>Die eleganteste Methode wäre, jeweils das höchstwertige Bit zu sichern
>und beim nächsten Schieben wieder hinten dranzuhängen. In Assembler

Kaum. Einfach auf positive Logik umrechnen, schieben und gut.

PORTA = ~(~PORTA<<1);

MfG
Falk

von Moe (Gast)


Lesenswert?

mhhhhh


  PORTB = ~(~PORTB<<1);


damit tut sich garnichts bei mir.

von Falk B. (falk)


Lesenswert?

@  Moe (Gast)

>damit tut sich garnichts bei mir.

Poste mal dein vollständiges Programm als Anhang.

MFG
Falk

von Tobi (Gast)


Lesenswert?

volatile unsigned char PORTVar = 0x01; //Dient zur Sicherung des Ports

void main(void)
{
.. //Timer Inits, Interrupt inits usw...
PORTB = 0xFF; //Erstmal Pull ups ein.
DDRB = 0xFF;  //Port als Ausgang schalten!!! (Damit werden PortPins zu 
high)
}

ISR (TIMERX..)
{
  if (PORTVar == 0x00) PORTVar=0x01; //Kann man so machen, da ja genug
                                     //Timer-Zeit vorhanden
  PORTB=~PortVar;
  PORTVar<<=1;
}

von Tobi (Gast)


Lesenswert?

PORTVar natürlich, nicht PortVar

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Du hast mehrere Möglichkeiten:

1.:
PORTA=0xFE;
 while(1){
  if (PORTA==0x7F) PORTA=0xFE;
  else{
   PORTA<<=1;
   PORTA++;
  };
 };

2.:
 unsigned char dummy;
 dummy=0x01;
 PORTA=0xFE;
 while(1){
  if (dummy==0x80) dummy=0x01;
  else dummy<<=1;
  PORTA=~dummy;
 };

3.:
 PORTA=0xFE;
 while(1){
  if (PORTA==0x7F) PORTA=0xFE;
  else PORTA=~(~PORTA<<1);
 };

Natürlich nicht in ne while(1) sondern in deine ISR. Und eben PORTB, 
nicht A.

von Falk B. (falk)


Lesenswert?

1
void main(void)
2
{
3
DDRB = 0xFF;
4
PORTB = ~1;
5
}
6
7
ISR (TIMERX..)
8
{
9
  if (PORTB == 0x7F)
10
  PORTB = ~1;
11
  else
12
    PORTB=~(~PORTB <<1);
13
}

Das mit Portvar ist Unsinn.

MFG
Falk

von Moe (Gast)


Lesenswert?

Danke Falk, das sieht mir sehr sauber aus und funktioniert.

Jetzt muss ich das ganze nurnoch auf 4 LEDS begrenzen.

Moe

von Falk B. (falk)


Lesenswert?

@ Moe (Gast)

>Jetzt muss ich das ganze nurnoch auf 4 LEDS begrenzen.

Dies ist eine Öbong för den Schööööler. ;-)

MfG
Falk

von Peter (Gast)


Lesenswert?

Mann, dass muss ja eine echt komplizierte Sache sein, so ein 
LED-Lauflicht!

von Moe (Gast)


Lesenswert?

@Falk

Naja, als Hobby-Tüfftler weniger. Ka wie man das sinnvoll begrenzen kann 
:o

von Karl H. (kbuchegg)


Lesenswert?

Moe wrote:
> @Falk
>
> Naja, als Hobby-Tüfftler weniger. Ka wie man das sinnvoll begrenzen kann
> :o


Als erstes musst du dir mal überlegen, welche 4 LED es denn sein sollen.
Wenn du das weist, dann weist du auch mit welchem Initialiwert
dein Port geladen werden muss, damit genau diese erste LED
brennt.
Wenn du dann 4 mal geschoben hast, welche LED brennt dann?
Wie sieht daher dann das entsprechende Byte aus?

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Moe wrote:
> @Falk
>
> Naja, als Hobby-Tüfftler weniger. Ka wie man das sinnvoll begrenzen kann
> :o

if (PORTB == 0x7F) <-- Was macht das wohl!?

von Moe (Gast)


Lesenswert?

Na man müsste eine "11110111" reinschreiben, oder? Damit er nach 4 
aufhört und wieder von vorne beginnt.

von Karl H. (kbuchegg)


Lesenswert?

Weist du: Das schöne an unserem Hobby ist, dass man einfach
mal auch ein bischen experimentieren kann. Natürlich überlegt.
Es ist sinnlos einfach irgendwelchen Quatsch hinzuschreiben
und zu hoffen das das schon funktionieren wird.
Aber wenn man einen Plan hat und sich bei dem was man tut
auch noch ein bischen was überlegt, dann kann man einfach
drauflos experimentieren ohne Gefahr zu laufen irgendwas
kaputt zu machen.
Das geile an der Sache ist, dass man sofort Rückmeldung
hat. Macht der µC das so, wie ich mir das gedacht habe, oder
habe ich falsch gedacht.

von Moe (Gast)


Lesenswert?

Öhm ja schon, war doch richtig meine Überlegung? Ich kann ja schlecht 
"11110111" schreiben?

von Falk B. (falk)


Lesenswert?

@ Moe (Gast)

>Öhm ja schon, war doch richtig meine Überlegung? Ich kann ja schlecht
>"11110111" schreiben?

Aber 0b11110111, dass versteht der AVR-GCC Compiler.

MfG
Falk

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Dann rechne es halt um.

Tip zum Umrechnen:
Bei BIN -> HEX ist es recht übersichtlich, du teilst das Byte in 2 
Nibble auf -> 1111 und 0111.
Der linke Teil ist die höherwertige Stelle in HEX 1111 = F, die 
niederwertige 0111 = Eigenleistung.

EDIT: Alternativ zur Eigenleistung einfach unten schauen.

von Karl H. (kbuchegg)


Lesenswert?

Moe wrote:
> Öhm ja schon, war doch richtig meine Überlegung? Ich kann ja schlecht
> "11110111" schreiben?

1. Man kann mit dem avr-gcc

   PORTB = 0b11110111;

   ist zulässig. Dieser Compiler ist erweitert um Zahlen mit
   dem Präfix 0b als Binärzahlen zu lesen

2. Die Umrechnung nach Hex sollte ja wohl kein Problem sein.
   Geht mittels Tabelle (die man bald auswendig kann)

   0000    0      0101   5      1010  A       1111  F
   0001    1      0110   6      1011  B
   0010    2      0111   7      1100  C
   0011    3      1000   8      1101  D
   0100    4      1001   9      1110  E


   Deine 8 Bit Zahl 11110111  in 2 4-Bit Einheiten (sog. Nibbles)
   zerlegen und für jeden Nibble den Wert aus der Tabelle holen:

   11110111 ->   1111  0111

                   |    |
                   |    |
                   v    v

                   F    7

   also entspricht 11110111 der Hex-Zahl 0xF7

von Moe (Gast)


Lesenswert?

Danke, Danke, Danke für die Erklärungen. Wenn man sich damit nur paar 
Tage im Monat beschäftigt bleibt halt nicht immer so viel hängen. Aber 
das hilft mir aufjeden Fall weiter.

Echt gut erklärt, und kapiert -> funktioniert

Schönen Tag noch,

Moe

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Schön soweit, kannst dir ja mal selber überlegen was du ändern müsstest 
wenn du die jetzt unbenutzten 4 Bit für was anderes benutzen willst.

@Karl Heinz: Lust dein Posting als Artikel zur Umrechnung abzulegen? 
Sowas hab ich bislang nicht gefunden.

von Moe (Gast)


Lesenswert?

Wäre eine gute Idee ja :-)

von Spess53 (Gast)


Lesenswert?

Hi

Man muss sich eigentlich nur merken, daß die Bits in einem Nibble die 
Wertigkeiten 8-4-2-1 (also 2er-Potenzen) besitzen. Z.B. 1010 ist dann 
1*8+0*4+1*2+0*1=10D. Wenn man dann noch weiss, das 10D=A ist, kann man 
sich den Rest an den Fingern abzählen.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

Ich hab da auch ein paar Merkhilfen.
Wie Spess schon sagte: dezimal 10 entspricht A. In der
binären Schreibweise ist das 1010 (also 2 mal die 10 hintereinander).
Die Hex-Buchstaben zähl ich normalerweise an den Fingern ab (bis
auf F).
Alle ungeraden Zahlen haben eine 1 an der letzten Stelle.
Und die Binärzahlen für 8, 4, 2, 1 und 0 sind auch leicht
zu merken. Da kommt immer nur eine einzelne 1 vor
Mal sehen was haben wir bisher

   0   0000            9
   1   0001            A  1010
   2   0010            B     Fingern abzählen
   3      1            C     Fingern
   4   0100            D     Fingern
   5      1            E     Fingern
   6      0            F  1111
   7      1
   8   1000

Da sind dann noch 3 und 7. Da sie um 1 kleiner sind als
die unmittelbar danach folgende 2-er Potenz 4 bzw. 8
merkt man sich die auch leicht: Lauter 1-er bis unmittelbar
vor die Stelle an der die nächste 2-er Potenz den einzigen
1-er haben wird.

   3    0011     (weil: 4 0100)
   7    0111     (weil: 8 1000)

damit bleiben aber nur noch 5, 6 und 9.
5 und 9, als Zahl unmittelbar nach einer 2-er Potenz sind
ähnlich aufgebaut.

die 2-er Potenz war 4  0100, 5 ist daher: 0101 (von mir aus
deswegen weil es die nächste ungrade Zahl ist und ungerade
Zahlen haben immer eine 1 ganz rechts

die 2-er Potenz war 8  1000, 9 ist daher: 1001

Bleibt nur noch die 6. Und die muss man sich merken 0110
(von mir aus: die beiden 1-er sind im Zentrum und das Zentrum
des Menschseins ist nun mal Sex)

von Falk B. (falk)


Lesenswert?

Die einfachste "Merkhilfe" ist, die Zahlen 0..15 in Dezimal, hex und 
binär im Kopf zu haben. Dann sieht man das sofort. So muss man auch 
Fremdsprachen etc. lernen.

MfG
Falk

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.