Forum: Mikrocontroller und Digitale Elektronik LED Würfel ATTINY13


von erfusta (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe diesen Schaltplan nachgebaut: 
http://www.avr-asm-tutorial.net/avr_de/wuerfel/wuerfel3.gif
Jedoch mit einem Unterschied, ich habe den GND der LEDs nicht auf den 
AVR gelegt, sondern die positive Seite auf den AVR, ein Test-Programm 
zeigt auch, dass alle LEDs leuchten (... wenn ich alle outputs auf on 
setze).

Ich bin neu in der AVR Programmierung, mein Ziel sollte es sein, dass 
der AVR wenn ich den Taster auf PB4 betätige eine random Zahl zwischen 1 
und 6 generiert, diese dann mittels der LEDs ausgibt.

Meinen Code habe ich angehängt. Wenn ich diesen Code so verwende, dann 
blinkt die mittlere LED herum, in unregelmäßigen Abständen, alle anderen 
LEDs leuchten durchgehend.

Wo liegt mein Fehler? Ich habe verschiedenste Varianten probiert, keine 
davon hat je ordentlich funktioniert.

Danke!

Gruß

von holger (Gast)


Lesenswert?

>Wo liegt mein Fehler?

Eine oder mehrere ODER Verknüpfungen setzen keine bereits
gesetzten Bits zurück!

von Thomas E. (thomase)


Lesenswert?

holger schrieb:
>>Wo liegt mein Fehler?
>
> Eine oder mehrere ODER Verknüpfungen setzen keine bereits
> gesetzten Bits zurück!

Auf den ersten Blick sollte "PORT =" statt "PORT |=" reichen.

mfg.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

erfusta schrieb:
> Wo liegt mein Fehler? Ich habe verschiedenste Varianten probiert, keine
> davon hat je ordentlich funktioniert.
1
      PORTB &= ~ (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3);

 So wie ich das sehe, wird nur PB0 gelöscht und dann mit PB1-PB3 OR-ed.

: Bearbeitet durch User
von M. S. (elpaco)


Lesenswert?

>
1
   if ( PINB ^ ( 1<<PINB4 ) );

Du fragst den Taster mit XOR ab.

Taster gedrückt: 1 XOR 1 = 0
Taster nicht gedrückt= 0 XOR 1 = 1

Verwende also ein & statt ^.

eventuell solltest du in Erwägung ziehen, den Taster zu entprellen. Du 
hast zwar ein delay von 100 ms drin, da kann aber bei etwas längerem 
Tastendruck auch mehrmals auslösen.

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Marc Vesely schrieb:
>> Wo liegt mein Fehler? Ich habe verschiedenste Varianten probiert, keine
>> davon hat je ordentlich funktioniert.
1
      PORTB &= ~ (1<<PB0) | (1<<PB1) | > (1<<PB2) | (1<<PB3);
>  So wie ich das sehe, wird nur PB0 gelöscht und dann mit PB1-PB3 OR-ed.

 NACHTRAG:
 Und PB1-PB3 setzst du damit auch auf 1.

: Bearbeitet durch User
von Thomas E. (thomase)


Lesenswert?

Marc Vesely schrieb:
> Und PB1-PB setzst du damit auch auf 1.

Das nun wieder nicht.

Aber ohne Klammern drumrum wird nur PB0 auf 0 gesetzt.

mfg.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Thomas Eckmann schrieb:
>Marc Vesely schrieb:
>> Und PB1-PB setzst du damit auch auf 1.
>
> Das nun wieder nicht.

 Hmmmm.
 Bist du sicher damit ?

von Thomas E. (thomase)


Lesenswert?

Marc Vesely schrieb:
> Bist du sicher damit ?
Ja.

Bit0 wird gelöscht, das Geodere dahinter ist Unsinn und wird 
wegoptimiert.

mfg.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Thomas Eckmann schrieb:
> Ja.
>
> Bit0 wird gelöscht, das Geodere dahinter ist Unsinn und wird
> wegoptimiert.

 LOL.
 Gib's zu, du hast ins .lss gekiekt ?

von Thomas E. (thomase)


Lesenswert?

Marc Vesely schrieb:
> Gib's zu, du hast ins .lss gekiekt ?

Nein, warum?

Da steht:
   PORTB &= ~ (1<<PB0) | (1<<PB1) | > (1<<PB2) | (1<<PB3);

PORTB &= 0xFE | 0x02 | 0x04 | 0x08

0xFE | 0x02 | 0x04 | 0x08 = 0xFE

Und dann ist nur noch ein Bit zu löschen.

genau genommen wird es nicht wegoptimert, sondern das ist eine 
Konstante, die errechnet und eingesetzt wird. Da der Compiler schlau 
ist, nimmt er für das eine Bit auch den passenden Befehl, anstatt 
Read-Modify-Write. Das ist allerdings eine Optimierung.

Geht also schön schnell, funktioniert aber nicht wie vom TO erwartet.

mfg.

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Thomas Eckmann schrieb:
> PORTB &= ~ (1<<PB0) | (1<<PB1) | > (1<<PB2) | (1<<PB3);
> PORTB &= 0xFE | 0x02 | 0x04 | 0x08

 LOL nochmal.
 Hab gar nicht drüber nachgedacht.

von erfusta (Gast)


Lesenswert?

Hallo,

danke erstmal für die Antworten.

Marc Vesely schrieb:
> So wie ich das sehe, wird nur PB0 gelöscht und dann mit PB1-PB3 OR-ed.

Du hast recht, ja. Wie bekomme ich es in einer Zeile zusammen, alle zu 
löschen?
>PORTB &= ~ (1<<PB0) ~ (1<<PB1) ~ (1<<PB2) ~(1<<PB3);
funktioniert ja nicht. Oder muss ich da für jeden Port eine eigene Zeile 
machen?

M. S. schrieb:
> Du fragst den Taster mit XOR ab.
>
> Taster gedrückt: 1 XOR 1 = 0
> Taster nicht gedrückt= 0 XOR 1 = 1
>
> Verwende also ein & statt ^.

Danke, werde ich versuchen. Was ich nicht ganz verstehe, der Taster ist 
in dem Schaltplan auf GND, somit sollte er den Eingang des AVRs auf 0 
setzen, lieg ich damit richtig?

M. S. schrieb:
> eventuell solltest du in Erwägung ziehen, den Taster zu entprellen. Du
> hast zwar ein delay von 100 ms drin, da kann aber bei etwas längerem
> Tastendruck auch mehrmals auslösen.

Stimmt, danke, werde ich machen.


Danke!

Gruß

von erfusta (Gast)


Lesenswert?

erfusta schrieb:
> Du hast recht, ja. Wie bekomme ich es in einer Zeile zusammen, alle zu
> löschen?
>>PORTB &= ~ (1<<PB0) ~ (1<<PB1) ~ (1<<PB2) ~(1<<PB3);
> funktioniert ja nicht. Oder muss ich da für jeden Port eine eigene Zeile
> machen?

Ich habe es nun so geschafft:
> PORTB &= ~ (1<<PB0) & ~ (1<<PB1) & ~ (1<<PB2) & ~ (1<<PB3);

Damit hätte ich schon mal den Lampen-Test vor der eigenen 
Würfel-Anwendung funktionierend bekommen. :)

von M. S. (elpaco)


Lesenswert?

erfusta schrieb

> Wie bekomme ich es in einer Zeile zusammen, alle zu
> löschen?
>>PORTB &= ~ (1<<PB0) ~ (1<<PB1) ~ (1<<PB2) ~(1<<PB3);
> funktioniert ja nicht. Oder muss ich da für jeden Port eine eigene Zeile
> machen?
1
PORTB &= ~( (1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3) );
im Klartext:
1
PORTB &= ~(0b00000001|0b00000010|0b00000100|0b00001000);
2
= PORTB &= ~(0b00001111);
3
= PORTB &= 0b11110000;


> Was ich nicht ganz verstehe, der Taster ist
> in dem Schaltplan auf GND, somit sollte er den Eingang des AVRs auf 0
> setzen, lieg ich damit richtig?

Sorry, habe ich nicht bemerkt. Dann funktioniert dein XOR, Standardmäßig 
würde man es dann so machen:
1
if( ! (PINB & (1<<PINB4)) )
2
{
3
...
4
}

Siehe auch:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Digitale_Signale

: Bearbeitet durch User
von erfusta (Gast)


Angehängte Dateien:

Lesenswert?

M. S. schrieb:
> im Klartext:

Danke, deine Version ist kürzer, als die die ich im Post davor durch 
probieren herausgefunden habe. Ich habe diese nun übernommen.

M. S. schrieb:
> Sorry, habe ich nicht bemerkt. Dann funktioniert dein XOR, Standardmäßig
> würde man es dann so machen:

Hab ich probiert. Ich hab die Anwendung umgeschrieben, ich will einfach 
mal testweise bei einem Tastendruck alle LEDs zum leuchten bringen. 
Siehe Anhang. Funktioniert allerdings kein bisschen, und ich hab auch 
keine Ahnung wieso. Sämtliches herumspielen mit Operatoren hat nichts 
gebracht.

Hast du noch eine Idee?

Danke!

Gruß

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

erfusta schrieb:
> Du hast recht, ja. Wie bekomme ich es in einer Zeile zusammen, alle zu
> löschen?

erfusta schrieb:
> Ich habe es nun so geschafft:
>> PORTB &= ~ (1<<PB0) & ~ (1<<PB1) & ~ (1<<PB2) & ~ (1<<PB3);

Thomas Eckmann schrieb:
> Auf den ersten Blick sollte "PORT =" statt "PORT |=" reichen.

 Auf den zweiten Blick auch.
 Lass die bitfummelei, du setzst PortB eh auf Null.

von M. S. (elpaco)


Lesenswert?

Hast du genau wie im Schaltplan nur den Taster zwischen den Pin und GND? 
Dann solltest du einen Pull-Up Widerstand (z.B. 10 kOhm) zwischen VDD 
und ebendiesen Pin hängen, oder direkt den Pin mit VDD verbinden und den 
internen Pull-Up aktivieren. Das hat den Hintergrund, dass der Pin sonst 
bei geöffnetem Schalter "in der Luft" hängt, durch den PullUp wird er 
auf ein definiertes Potential (VDD, also "1") gezogen.

von erfusta (Gast)


Lesenswert?

M. S. schrieb:
> Hast du genau wie im Schaltplan nur den Taster zwischen den Pin
> und GND?
> Dann solltest du einen Pull-Up Widerstand (z.B. 10 kOhm) zwischen VDD
> und ebendiesen Pin hängen, oder direkt den Pin mit VDD verbinden und den
> internen Pull-Up aktivieren. Das hat den Hintergrund, dass der Pin sonst
> bei geöffnetem Schalter "in der Luft" hängt, durch den PullUp wird er
> auf ein definiertes Potential (VDD, also "1") gezogen.

Ja, das habe ich. Hm. Also mit taster auf GND habe ich aktuell keine 
Chance?

Dann werde ich das morgen auf VDD umlöten.

von erfusta (Gast)


Lesenswert?

Nachtrag: Wenn ich den interen Pullup aktiviere, und den Taster 
betätige, so müsste mein Wert auf dem Eingang doch 0 sein, oder?

von erfusta (Gast)


Lesenswert?

Yep, ich habs.
>  PORTB |= (1<<PB4);    /* internen Pull-Up an PC7 aktivieren */

Danach funktioniert der Code aus dem letzten Anhang. Mal schauen, ob ich 
das Ding nun fertig bekomme. Danke! :)

von M. S. (elpaco)


Lesenswert?

Doch, natürlich hast du eine Chance mit Taster auf GND. Ist eben die 
Frage, ob Active High, oder Active Low. Nur in beiden Fällen muss der 
Taster im geöffneten Zustand über einen Widerstand auf das jeweils 
andere Potential verbunden sein, da er sonst ja nirgends angeschlossen 
wäre und der Pin einfach "irgendwas" liest.

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Eing.C3.A4nge_.28Wie_kommen_Signale_in_den_.C2.B5C.29 
-> Taster und Schalter

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

erfusta schrieb:
> Danach funktioniert der Code aus dem letzten Anhang. Mal schauen, ob ich
> das Ding nun fertig bekomme. Danke! :)

 Vorschlag:
 Mach mal eine function z.B. RollDice.
 Da machst du dann deine rand(), Abfrage usw.
 Und lass mal die Wurfel langsam ausrollen, etwa so:
1
   uint16_t dly = 200;
2
   uint8_t count;
3
4
   for (count=1; count < 6; count++) {
5
      num = rand()%6+1;
6
      PORTB = 0x10;
7
8
      if ( num == 1 )
9
      {
10
        PORTB |= (1<<PB0);
11
        ...
12
        ...
13
      }
14
15
      _delay_ms(dly);
16
      dly += 100;
17
   }

von erfusta (Gast)


Lesenswert?

Marc Vesely schrieb:
> Vorschlag:
>  Mach mal eine function z.B. RollDice.
>  Da machst du dann deine rand(), Abfrage usw.
>  Und lass mal die Wurfel langsam ausrollen, etwa so:

Danke, werde ich probieren.

Ich habe es gestern im Übrigen noch geschafft das Ganze zum laufen zu 
bekommen.
Interessantwerweise Würfelt der Würfel immer die gleichen Zahlen, sprich 
die random Funktion ist bei mir nicht wirklich random ...
Nach dem Einschalten: 2-6-4-1, jedes mal gleich.

Jemand eine Idee wieso? Wird das evtl im RAM gespeichert?

Gruß

von Peter II (Gast)


Lesenswert?

erfusta schrieb:
> Jemand eine Idee wieso?

woher soll denn der zufall kommen? der µC macht das jedes mal das 
gleiche.

http://www.atmel.com/webdoc/AVRLibcReferenceManual/group__avr__stdlib_1gae23144bcbb8e3742b00eb687c36654d1.html

von Thomas E. (thomase)


Lesenswert?

erfusta schrieb:
> Jemand eine Idee wieso?

Die Startbedingung ist immer gleich. Da du nicht Uhrzeit und Datum 
dazurechnen kannst, um immer eine andere Startbedingung zu haben, musst 
du dem Zufall anders auf die Sprünge helfen.

Eine einfache Möglichkeit wäre, die Random-Funktion nach dem 
Programmstart einfach in einer Schleife laufen zu lassen, die mit 
Tastendruck beendet wird. Die Zeit vom Einschalten bis zum Tastendruck 
ist immer unterschiedlich. Dann bekommst du auch immer unterschiedliche 
Zahlen.

mfg.

von Peter II (Gast)


Lesenswert?

außerdem ist das auch nicht ganz richtig:

> rand()%6+1;

denn rand liefert kein vielfaches von 6, damit werden einige Zahlen 
bevorzugt und andere benachteiligt.

von tommyProg (Gast)


Lesenswert?

@Thomas Eckmann:

>>Marc Vesely schrieb:
>> Gib's zu, du hast ins .lss gekiekt ?

>>Nein, warum?
_________________________________________________________
>Da steht:
>   PORTB &= ~ (1<<PB0) | (1<<PB1) | > (1<<PB2) | (1<<PB3);

leuchtet mir ein, was es tut

>PORTB &= 0xFE | 0x02 | 0x04 | 0x08
>
>0xFE | 0x02 | 0x04 | 0x08 = 0xFE

Thomas, könntest Du bitte nochmal gena uerklären, was die beiden 
Anweisungen tun? und warum ist bei der unteren das "=" auf der rechten 
Position?


>Und dann ist nur noch ein Bit zu löschen.




>genau genommen wird es nicht wegoptimert, sondern das ist eine
>Konstante, die errechnet und eingesetzt wird. Da der Compiler schlau
>ist, nimmt er für das eine Bit auch den passenden Befehl, anstatt
>Read-Modify-Write. Das ist allerdings eine Optimierung.
>
>Geht also schön schnell, funktioniert aber nicht wie vom TO erwartet.
>
>mfg.

von Karl H. (kbuchegg)


Lesenswert?

tommyProg schrieb:
> @Thomas Eckmann:
>
>>>Marc Vesely schrieb:
>>> Gib's zu, du hast ins .lss gekiekt ?
>
>>>Nein, warum?
> ___________________________________________________________
>>Da steht:
>>   PORTB &= ~ (1<<PB0) | (1<<PB1) | > (1<<PB2) | (1<<PB3);
>
> leuchtet mir ein, was es tut
>
>>PORTB &= 0xFE | 0x02 | 0x04 | 0x08
>>
>>0xFE | 0x02 | 0x04 | 0x08 = 0xFE
>
> Thomas, könntest Du bitte nochmal gena uerklären, was die beiden
> Anweisungen tun?

Welche beiden?

> und warum ist bei der unteren das "=" auf der rechten
> Position?

Das ist keine C Anweisung.
Das ist einfach nur der Rechengang.
1
   1           ist einfach nur binär 00000001
2
   1 <<        diese binäre 1 wird nach links geschoben. Um wieviel?
3
   1 << PB0    Aha! Um PB0 Stellen. PB0, das ist einfach nur ein anderes
4
               Wort für 0. Also schieb mal 00000001 um 0 Stellen nach links
5
               Das Ergebnis ist binär 00000001. Das'binär' deute ich in
6
               weiterer Folge mit dem Präfix 0b an. Also 0b00000001
7
8
   ~( 1<<PB0)  die 0b00000001 werden also invertiert.
9
               Neues Zwischenergebnis ist also 0b11111110
10
11
               Und da mir binäre Schreibweise auf Dauer zu blöd ist,
12
               schreib ich dieselbe Zahl Hexadezimal auf. Jede 8 Bit
13
               Binärzahl lässt sich ach als 2 stellige Hex-Zahl darstellen
14
               ohne dass man gross rechnen muss. Einfach die 8 Bit in der
15
               Mitte in2 4-Bit Einheiten teilen und getreu
16
17
               0000    0             1000    8
18
               0001    1             1001    9
19
               0010    2             1010    A
20
               0011    3             1011    B
21
               0100    4             1100    C
22
               0101    5             1101    D
23
               0110    6             1110    E
24
               0111    7             1111    F
25
26
               neu anschreiben.
27
               Aus 0b11111110 wird also 1111 1110 und das wird Hexadezimal
28
               als 0xFE geschrieben.

dasselbe für die anderen Teilausdrücke.
Aus (1<<PB1) wird 0x02
Aus (1<<PB2) wird 0x04
Aus (1<<PB3) wird 0x08

und dann oderst du die Einzelteile zusammen
1
   Hex        Binär
2
3
    0xFE      0b11111110
4
 |  0x02      0b00000010
5
-------------------------
6
 ergibt       0b11111110
7
 |  0x04      0b00000100
8
-------------------------
9
 ergibt       0b11111110
10
 | 0x08       0b00001000
11
-------------------------
12
  ergibt      0b11111110

0b11111110, das ist aber nichts anders als Hexadezimal 0xFE

Das Ergebnis von
1
    ~ (1<<PB0) | (1<<PB1) | > (1<<PB2) | (1<<PB3);
isr also ausgerechnet die Zahl 0xFE.

Und mit der wird dann das PORT Register verundet.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Und nimm den Kommentar am Anfang raus
1
/*
2
 * main.c
3
 * 
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
...

sowas ist lächerlich.
Du kannst kaum programmieren, tust aber so, als ob du bei den Grossen 
mitspielst. Das ist genauso lächerlich, wie die Skifahrer, die sich kaum 
auf den Bretteln halten können aber die tollste und teuerste Ausrüstung 
haben und auf der Hütte angeben, wie schnell sie nicht die Streif runter 
gefahren wären.

: Bearbeitet durch User
von Thomas E. (thomase)


Lesenswert?

tommyProg schrieb:
> Thomas, könntest Du bitte nochmal gena uerklären, was die beiden
> Anweisungen tun? und warum ist bei der unteren das "=" auf der rechten
> Position?

Wenn man noch am überlegen ist, wie man es schreiben soll, hat 
Karl-Heinz, sofern er online ist, schon die perfekte Erklärung fertig:

Karl Heinz schrieb:
> Das ist keine C Anweisung.
> Das ist einfach nur der Rechengang.

mfg.

von erfusta (Gast)


Lesenswert?

Hallo,

Karl Heinz schrieb:
> sowas ist lächerlich.
> Du kannst kaum programmieren, tust aber so, als ob du bei den Grossen
> mitspielst. Das ist genauso lächerlich, wie die Skifahrer, die sich kaum
> auf den Bretteln halten können aber die tollste und teuerste Ausrüstung
> haben und auf der Hütte angeben, wie schnell sie nicht die Streif runter
> gefahren wären.

Zunächst einmal, vielen Dank für deine guten Erklärungen bzlg den Bits, 
ich werde mich weiter damit beschäftigen.
Danke auch an alle anderen, mein Würfel funktioniert nun erstmal, ich 
werde nun eure Kommentare Stück für Stück einarbeiten, und mich 
versuchen zu verbessern.

Zu deinem letzten Kommentar: Ich bin doch sehr erstaunt darüber.
Ich habe im Startpost sowie im weiteren Verlauf deutlich klar gemacht, 
dass ich Anfangs absolut keine Ahnung hatte was ich tat, und das ich ein 
absoluter Anfänger bin.
Als Anfänger nutzt man auch IDEs, mit vordefinierten Templates. Nicht 
jeder konnte mit vim und avr-gcc auf der Konsole bei seinem ersten 
Projekt herumjonglieren.
Meine IDE, in dem fall Geany, fügt diesen Text automatisiert ein, ich 
habe ihn nicht weiter beachtet, und mich nicht darum kümmern.

Ich werde aber in Zukunft darauf achten, dass meine IDEs nichts, was 
meinem "Skill-Level" nicht entsprechen könnte, einfügt, ok? :)

Nein, mal im Ernst: Wie gesagt, deine Erklärungen haben mir viel 
geholfen, wirklich Danke dafür. Das letzte war aber meiner Meinung nach 
sinnloses herumgebashe, da ich oft erwähnt habe, dass ich Anfänger bin 
...

Gruß

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.