Hallo miteinander, ich hab mich im Forum angemeldet um den Rat der community zu suchen. mir stellt sich ein Problem für das ich schon die Suchfunktion genutzt habe. Allerdings glaube ich, dass mein Problem von dermaßen grundlegender Natur ist, dass ich es nicht hinbekomme eine Lösung zu finden. :D Folgende Situation: Ich möchte mit einem Atmega 328P ein Lauflicht an 8 LED's an Port D realisieren. Das ganze fängt bei LED 1 an PIND0 an und endet an PIND7 mit LED 8, wobei immer nur eine LED leuchten soll. Am Ende angekommen sollen die LEDs wieder absteigend leuchten, usw. usw. Hier mein Code: [c] #ifndef F_CPU #define F_CPU 16000000UL #endif #include <avr/io.h> #include <util/delay.h> #include <math.h> int main(void) { DDRD = 0xFF; int tmpLED = 0; int led = 0; int portCount = 0; while (1) { if(led>0 && led<7 && led>tmpLED){ portCount=(int) pow(2,led); PORTD =portCount; tmpLED = led; led++; _delay_ms(2000); } if(led>0&&led<7 && led<tmpLED){ portCount=(int) pow(2,led); PORTD = portCount; tmpLED = led; led--; _delay_ms(2000); } if(led==0){ portCount= (int)pow(2,led); PORTD = portCount; tmpLED=led; led++; _delay_ms(2000); } if(led==7){ portCount=(int) pow(2,led); PORTD = portCount; tmpLED=led; led--; _delay_ms(2000); } } } [c] Jetzt mal unabhängig davon, dass das auch eleganter geht und ich Bitmasken benutzen könnte, liegt mein Verständnisproblem in den Zeilen, in denen ich portCount = (int) pow(2, led) berechne und dies dann an den Port übergebe. (int) steht hier noch zusätzlich. Auch ohne diesen Typecast läuft das Programm falsch. Eigentlich müssten doch die Werte, die ich auf diese Weise an Port D übergebe 1, 2, 4, 8, 16, 32, 64, 128, 64, 32, etc. sein (so jedenfalls wenn ich den Code einfach nur in einer IDE für C Programme ausgeben lasse). Was mein Lauflicht allerdings daraus zu machen scheint ist folgendes (ich gebe hier jetzt die Dezimalzahl an, die sich aus der Binärdarstellung der LEDs ablesen lässt): 1, 2, 3, 7, 15, 31, 63, 128, 63, 31, etc. Warum läuft das nun falsch? Ich dachte immer, dass wenn ich eine integer Zahl an einen Port übergebe, dass dann das Register mit den entsprechenden Bits gefüllt wird. Wenn ich direkt 128 an PORTD übergebe leuchtet nur die letzte LED, wenn ich 4 übergebe, dann nur die 3te usw. Könnt ihr mir vielleicht helfen und sagen, warum die pow() funktion die Werte falsch berechnet? oder liegt das Problem vielleicht sogar ganz woanders?
pow() gibt einen Double (Gleitkommazahl) zurück, keinen Integer. Deshalb musst du ihn noch auf int casten.
Sebastian R. schrieb: > Deshalb > musst du ihn noch auf int casten. Tut er/sie/es. Zudem ist der Cast als impliziter Cast gleichwertig zum expliziten. (mal abgesehen von dem dokumentierenden Faktor.)
Hallo und danke für die Antwort, das hab ich auch vermutet, aber das typecasten scheint keine Veränderung zu bringen. Aus irgendeinem Grund z.b. wird (int) pow(2, 2) als 3 ausgegeben, nicht als 4.
Andre M. schrieb: > Aus irgendeinem Grund z.b. wird (int) pow(2, 2) als 3 > ausgegeben, nicht als 4. wegen float 3,9999 wie wäre es mit runden +0,5 vor int?
Ich tippe mal auf ein Rundungsproblem. Wenn du das tatsächlich über die Potenzfunktion machen willst, dann probiere mal: portCount=(int) (pow(2,led)+0.1); Ich würde Shiftoperationen verwenden und kein 'int' sondern 'uint8_t', Alternativ zu Shift: Multiplikation oder Division mit 2.
HildeK schrieb: > Ich tippe mal auf ein Rundungsproblem. :-) HildeK schrieb: > Ich würde Shiftoperationen verwenden und kein 'int' sondern 'uint8_t', > Alternativ zu Shift: Multiplikation oder Division mit 2. +1
Hi, statt pow könntest du auch einfach portcount = 2^led verwenden und das dann ausgeben oder mit dem BV Makro arbeiten. Auch das umschalten hoch/runterzählen kannst du vereinfachen, z.b. in dem du tmpled einfach nur auf 0 oder 1 setzt und damit die Laufrichtung vorgibst. Gruss tobi
Ihr habt alle recht, ich hatte echt ein Brett vorm Kopf o.O was mein Problem mit obigem Code löst ist, dass ich portCount als round(portCount) runden muss, dann wird zur nächst höheren Integer Zahl aufgerundet. Seltsam finde ich das ganze dennoch, in Codeblocks generiert mir (int) portCount den aufgerundeten Wert, entsprechend habe ich einen Rundungsfehler als Ursache verworfen. AtmelStudio scheint das aber vollkommen egal zu sein, dass ich eigentlich bei 3.999999 liege. Vielen lieben Dank jedenfalls! Jetzt wo mir das einleuchtet will ich das mal lieber mit Shift Operationen erledigen :) VG
Andre M. schrieb: > auch eleganter geht Code is evil. In den vier Zweigen deines Programms passiert mehr oder weniger das gleiche, und dieses gleiche sollte nur einmal beschtrieben werden. Völlig unabhängig davon dass (int) pow(2,led) besser als (1<<led) ausgedrückt wird ... LG, Sebastian
Hi nochmal, eine einfache Multiplikation / Division mit 2 funktioniert nicht ganz, da 2*0 = 0 und 2*1 = 2, portd.1 wird damit nicht angesprochen. Daher 2^led Gruss tobi
Wie kommt man auf die Idee, eine eigentlich simple Bit-Operation (shift) per float-Operation umzusetzen. Das ist wie ein Schuss von hinten durch die Brust ins Auge.
Ich fasse zusammen:
1 | #ifndef F_CPU
|
2 | #define F_CPU 16000000UL
|
3 | #endif
|
4 | |
5 | #include <avr/io.h> |
6 | #include <util/delay.h> |
7 | #include <math.h> |
8 | |
9 | int main(void) { |
10 | |
11 | DDRD = 0xFF; |
12 | int led = 0; |
13 | int dir; |
14 | |
15 | while (1) { |
16 | PORTD = (1 << led); |
17 | _delay_ms(2000); |
18 | |
19 | if (led == 0) dir = 1; |
20 | else if (led == 7) dir = -1; |
21 | led += dir; |
22 | }
|
23 | }
|
Will man verschiedene Muster darstellen, eignet sich auch gut ein Array. Das läßt sich dann besonders leicht ändern und man muß keine Formel dafür entwickeln. Hier mal ein Beispiel: Beitrag "Re: AVR Sleep Mode / Knight Rider" Das Array steht in pattern.c.
hacker-tobi schrieb: > eine einfache Multiplikation / Division mit 2 funktioniert nicht ganz, > da 2*0 = 0 und 2*1 = 2, portd.1 wird damit nicht angesprochen. Daher > 2^led Ja, die Division und Multiplikation ist ein wenig umständlicher. Man muss für die erste LED halt die 1 setzten und dann kann man mit einer Multiplikation mit 2 die weiteren ansprechen. Das zu erkennen hatte ich dem TO eigentlich zugetraut.
hacker-tobi schrieb: > 2^led Es geht um Sourcecode in C. Was hat die bitweise exklusive Oder-Operation mit dem Thema zu tun? LG, Sebastian
my2ct schrieb: > Wie kommt man auf die Idee, eine eigentlich simple Bit-Operation (shift) > per float-Operation umzusetzen. Das ist wie ein Schuss von hinten durch > die Brust ins Auge. Indem man darauf hereinfällt, dass überall von Zweierpotenzen die Rede ist, und dann keine andere Potenzfunktion in C findet. Zwei historisch bedingte Fehlkonstruktionen.
Nosnibor schrieb: > Indem man darauf hereinfällt, dass überall von Zweierpotenzen die Rede > ist, und dann keine andere Potenzfunktion in C findet. Zwei historisch > bedingte Fehlkonstruktionen. Interessant! Wie ist es denn ..... Bist du ein Gegner des Binärsystems, oder hast es nur nicht verstanden?
Nosnibor schrieb: > my2ct schrieb: >> Wie kommt man auf die Idee, eine eigentlich simple Bit-Operation (shift) >> per float-Operation umzusetzen. > Indem man darauf hereinfällt, dass überall von Zweierpotenzen die Rede > ist, und dann keine andere Potenzfunktion in C findet. Zwei historisch > bedingte Fehlkonstruktionen. Ich sehe es eher so, dass man keinen Plan hat, was da tatsächlich auf der Hardware passieren muss, damit aus einer Zahl ein binäres Muster wird. > my2ct schrieb: >> Das ist wie ein Schuss von hinten durch die Brust ins Auge. Besonders, wenn man dann nicht mal weiß, welche Datentypen man da eigentlich verwendet und welche eklatanten Einschränkungen (Rundungsfehler) sie haben. Der nächste logische Schritt wäre, wenn jetzt noch ein float-Wert auf Gleichheit abgefragt wird. Andre M. schrieb: > _delay_ms(2000); Wenn man in jedem Zweig der if-Abfrage diesen Programmfehler einbaut (ein 2-Sekunden-Delay IST vergeudete Rechenzeit und damit ein Programmfehler), dann könnte man ihn dort rausnehmen und statt der Copy-Paste-Orgie nur 1 einziges Mal hinten anfügen.
:
Bearbeitet durch Moderator
HildeK schrieb: > Ja, die Division und Multiplikation ist ein wenig umständlicher. Man > muss für die erste LED halt die 1 setzten und dann kann man mit einer > Multiplikation mit 2 die weiteren ansprechen. Auch wenn man statt der eigentlich erforderliche Schiebeoperation eine Multiplikation verwendet, dokumentiert man damit nur, dass ein heftiges Defizit bei Grundlagen der Bitoperationen besteht und man nie auf Assemblerebene ohne HW-Multiplizierer programmiert hat. Die "wahren" Programmierer werden jetzt argumentieren, dass der Compiler diesen Schwachsinn schon wieder weg optimieren wird - Recht haben sie wahrscheinlich. Blindes Vertrauen in die Fähigkeiten der Leute, die den Compiler gebaut haben, statt gleich zu schreiben, was man eigentlich möchte.
Wolfgang schrieb: > Auch wenn man statt der eigentlich erforderliche Schiebeoperation eine > Multiplikation verwendet, dokumentiert man damit nur, dass ein heftiges > Defizit bei Grundlagen der Bitoperationen besteht und man nie auf > Assemblerebene ohne HW-Multiplizierer programmiert hat. Ich habe die alternative Variante im Wissen genannt, dass eine Integer-Mulitplikation oder Division mit Faktor 2 vom Compiler sicher in eine Schiebeoperation umgewandelt wird. In der Hoffnung, dass es der TO leichter versteht, der ja von der Potenzfunktion ausgegangen ist und dem Schiebeoperationen weniger geläufig sind. Wie gesagt, es war als Alternative genannt; nachdem ich auf die Schiebeoperation hingewiesen hatte!
Viele Wege führen bekanntlich nach Rom:
1 | #include <stdio.h> |
2 | #include <stdlib.h> |
3 | #include <unistd.h> |
4 | |
5 | unsigned char mask[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; |
6 | unsigned char *pmask[]={".......*","......*.",".....*..","....*...","...*....","..*.....",".*......","*......."}; |
7 | |
8 | unsigned char port; |
9 | unsigned char i; |
10 | |
11 | int main() |
12 | {
|
13 | |
14 | while (1) |
15 | {
|
16 | printf("%s\r\n",pmask[i&7]); // portsimulation |
17 | |
18 | port=mask[i++&7]; |
19 | sleep(1); |
20 | }
|
21 | }
|
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.