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
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.
0000 0001 = 1 Warten 0000 0010 = 2 Warten 0000 0100 = 4 Warten usw. usw. So in diese Richtung vielleicht?
@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.
@Praktikant Nein, muss über Bitmanipulation gehen. Will nicht den kompletten Port beschreiben.
1 | PORTA = 1; |
2 | |
3 | for (i=0; i<8; i++) { |
4 | _delay_ms(100); |
5 | PORTA <<= 1; |
6 | }
|
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).
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
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
natürlich andersrum: 11111111 11111110 11111101 11111011 Der Beitrag von Johannes hört sich schonmal ganz gut an.
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...
Wenns noch andere saubere Möglichkeiten gibt bin ich natürlich auch dabei.
@ 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
@ Moe (Gast)
>damit tut sich garnichts bei mir.
Poste mal dein vollständiges Programm als Anhang.
MFG
Falk
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; }
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.
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
Danke Falk, das sieht mir sehr sauber aus und funktioniert. Jetzt muss ich das ganze nurnoch auf 4 LEDS begrenzen. Moe
@ Moe (Gast)
>Jetzt muss ich das ganze nurnoch auf 4 LEDS begrenzen.
Dies ist eine Öbong för den Schööööler. ;-)
MfG
Falk
@Falk Naja, als Hobby-Tüfftler weniger. Ka wie man das sinnvoll begrenzen kann :o
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?
Moe wrote: > @Falk > > Naja, als Hobby-Tüfftler weniger. Ka wie man das sinnvoll begrenzen kann > :o if (PORTB == 0x7F) <-- Was macht das wohl!?
Na man müsste eine "11110111" reinschreiben, oder? Damit er nach 4 aufhört und wieder von vorne beginnt.
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.
Öhm ja schon, war doch richtig meine Überlegung? Ich kann ja schlecht "11110111" schreiben?
@ 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
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.
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
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
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.
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
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)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.