mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Frage zu Bitmanipulation


Autor: Moe (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: A. M. (bacarni) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielleich meinst du das : nach deiner Zeile ein

PORTB &= 1;

Autor: Praktikant (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
0000 0001 = 1
Warten
0000 0010 = 2
Warten
0000 0100 = 4
Warten

usw. usw.

So in diese Richtung vielleicht?

Autor: Moe (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Moe (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Praktikant

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

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

PORTA = 1;

for (i=0; i<8; i++) {
  _delay_ms(100);
  PORTA <<= 1;
}

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: hans (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Moe (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Moe (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
natürlich andersrum:

11111111
11111110
11111101
11111011

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

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Moe (Gast)
Datum:

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

Autor: Moe (Gast)
Datum:

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

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Moe (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
mhhhhh


  PORTB = ~(~PORTB<<1);


damit tut sich garnichts bei mir.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Moe (Gast)

>damit tut sich garnichts bei mir.

Poste mal dein vollständiges Programm als Anhang.

MFG
Falk

Autor: Tobi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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;
}

Autor: Tobi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PORTVar natürlich, nicht PortVar

Autor: Tim T. (tim_taylor)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
void main(void)
{
DDRB = 0xFF;
PORTB = ~1;
}

ISR (TIMERX..)
{
  if (PORTB == 0x7F)
  PORTB = ~1;
  else
    PORTB=~(~PORTB <<1);
}

Das mit Portvar ist Unsinn.

MFG
Falk

Autor: Moe (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke Falk, das sieht mir sehr sauber aus und funktioniert.

Jetzt muss ich das ganze nurnoch auf 4 LEDS begrenzen.

Moe

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Moe (Gast)

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

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

MfG
Falk

Autor: Peter (Gast)
Datum:

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

Autor: Moe (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Falk

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Tim T. (tim_taylor)
Datum:

Bewertung
0 lesenswert
nicht 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!?

Autor: Moe (Gast)
Datum:

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Moe (Gast)
Datum:

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

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Tim T. (tim_taylor)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Moe (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Tim T. (tim_taylor)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Moe (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wäre eine gute Idee ja :-)

Autor: Spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.