Ich habe 10 LEDs, der Wert, der angezeigt werden soll, ist zwischen 0
und 10. Dieser sollen folgendermaßen angezeigt werden:
1 von 10:
X---------
5 von 10:
XXXXX-----
8 von 10:
XXXXXXXX--
(X = an, - = aus)
ich habe in C fogenden Code geschrieben:
(bit 1-8 der LEDs an portC, bit 9-10 an portD 1-2)
1
//Bereich anpassen, dass der Wert zwischen 0-10 ist
2
Wert/=35;
3
4
5
show=pow(2,Wert)-1;
6
/*2 hoch Wert ergibt immer ein vielfaches von 2, also ergibt sich folgendes:
7
Wert = 2 -> 0010000000 minus 1 ergibt -> 1100000000
8
Wert = 5 -> 0000010000 minus 1 ergibt -> 1111100000
9
*/
10
11
12
//Variable "Show" an Ports geben
13
14
PORTC=show;
15
16
if(show>=511)
17
PORTD|=(1<<PD1);
18
else
19
PORTD&=~(1<<PD1);
20
21
if(show>=1023)
22
PORTD|=(1<<PD2);
23
else
24
PORTD&=~(1<<PD2);
Es funktioniert zwar, ist aber nicht sehr schnell.
Würde mich über Vervesserungsvorschläge freuen, ist mein erstes Programm
auf einem Mikrocontroller in C.
PS: Verwende einen ATmega32
das ganze wird auf 10 Reihen gemultiplext, also brauch ich
10 x ca.30 pro Sekunde, damit es für das Auge schön anzusehen ist.
Das ist natürlich nicht das einzigste, was in der Schleife hängt. Habe
aber bei Begin der Stelle ein Bit gesetzt und am Ende zurückgesetzt. Das
Oszi hat mir dann verraten, dass das Ganze im Vergleich zum Rest viel
Zeit in anspruch nimmt.
Jano schrieb:> Es funktioniert zwar, ist aber nicht sehr schnell.> Würde mich über Vervesserungsvorschläge freuen,
Der ganze Teil, wie du aus einer Zahl von 0 bis 9 eine entsprechende
Anzahl an LED einschaltest ist viiiiieeeeel zu kompliziert. Insbesondere
pow() ist da so richtig die brachiale Holzhammermethode.
Du hast 10 mögliche Eingangswerte als Ergebnis deiner Division durch 35.
Diese 10 Werte liegen dann auch noch im Bereich 0 bis 9. Da kann man
ruhig ein Array mit 10 Werten anlegen. Mit dem erhaltenen Rechenergebnis
geht man als Index in das Array und kriegt ein Bitmuster raus, welches
so gestaltet ist, dass man es nur noch auf den Port geben muss und eine
entsprechende Anzahl von LED leuchtet.
Kein Mensch muss dazu irgendetwas kompliziert über Logarithmen
ausrechnen (was pow() tun muss)
> (bit 1-8 der LEDs an portC, bit 9-10 an portD 1-2)
Und gewöhn dir an, dass wir bei 0 zu zählen anfangen.
Ein Byte hat 8 Bit, die von 0 bis 7 durchnummeriert werden.
/*2 hoch Wert ergibt immer ein vielfaches von 2, also ergibt sich folgendes:
2
Wert = 2 -> 0010000000 minus 1 ergibt -> 1100000000
3
Wert = 5 -> 0000010000 minus 1 ergibt -> 1111100000
4
*/
normalerweise werden zahlen mit dem MSB link geschrieben (du schreibst
doch auch nicht 01^2=4201, oder?)
> ist aber nicht sehr schnell.
ist definitionssache. "nicht optimal" triffts eher, du könntest beide if
in eine schiebeoperation und bitmaske zusammenfassen, dann reduzierst
den code
wir wissen ja nicht mal was in welcher "schleife" abgearbeitet wird. Ich
vermute mal ganz stark das
Wert /= 35;
show = pow(2, Wert) - 1;
jeweil in der Ausgabe-Schleife der Matrix drin sind. Das hat dort aber
überhaupt nichts zu suchen. Man berechnet die Matrix vorher und die
ausgabe sorgt nur dafür das sie angzeigt wird.
Karl Heinz Buchegger schrieb:> Du hast 10 mögliche Eingangswerte als Ergebnis deiner Division durch 35.> Diese 10 Werte liegen dann auch noch im Bereich 0 bis 9. Da kann man> ruhig ein Array mit 10 Werten anlegen. Mit dem erhaltenen Wert geht man> als Index in das Array und kriegt ein Bitmuster raus, welches so> gestaltet ist, dass man es nur noch auf den Port geben muss und eine> entsprechende Anzahl von LED leuchtet.
also beim Initialisieren:
1
uint16_tVorlage[10];
2
uint16_tVorlage2[10];
3
4
5
Vorlage[0]=0;
6
Vorlage[1]=1;
7
Vorlage[2]=3;
8
...
9
10
11
12
Vorlage2[0]=0;
13
...
14
Vorlage2[9]=1;
15
Vorlage2[10]=3;
und dann
PORTC = Vorlage[Wert];
PORTD = Vorlage2[Wert];
Jano schrieb:> also beim Initialisieren:>> uint16_t Vorlage[10];> uint16_t Vorlage2[10];>>> Vorlage[0] = 0;> Vorlage[1] = 1;> Vorlage[2] = 3;> ...
* du kannst das alles in einem Aufwasch machen.
* Zahlensysteme!
Da du es hier mit Bits zu tun hast (1 Bit regelt ja, ob eine LED
leuchtet oder nicht), ist Dezimal hier keine große Hilfe.
Schreibs halt einfach Binär hin, dann sieht auch ein Blinder
wie das Leuchtmuster ist
* Warum verwendest du uint16_t für etwas, was nicht größer als 8 Bit
sein wird? Machst du gerne Beschäftigungstherapie für deinen µC?
1
uint8_tMusterC[]={
2
0b00000000,// 0
3
0b00000001,// 1
4
0b00000011,// 2
5
0b00000111,// 3
6
0b00001111,// 4
7
0b00011111,// 5
8
0b00111111,// 6
9
0b01111111,// 7
10
0b11111111,// 8
11
0b11111111,// 9
12
0b11111111// 10
13
};
14
15
uint8_tMusterD[]={
16
0b00000000,// 0
17
0b00000000,// 1
18
0b00000000,// 2
19
0b00000000,// 3
20
0b00000000,// 4
21
0b00000000,// 5
22
0b00000000,// 6
23
0b00000000,// 7
24
0b00000000,// 8
25
0b00000001,// 9
26
0b00000011// 10
27
};
Alternativ hätte man natürlich auch ein einziges uint16_t Array nehmen
können, welches man bei der Ausgabe bytemässig zerlegt.
Jano schrieb:> edit: Das Array geht natürlich nur von 0-9, sorry für den schreibfehler> ;)
Es muss aber von 0 bis 10 gehen, dh. 11 Werte umfassen. Denn 'alle LED
aus' ist ja bei dir offensichtlich auch ein Zustand.
Jano schrieb:> PORTC = Vorlage[Wert];> PORTD = Vorlage2[Wert];
Damit beschreibst du aber den kompletten PORTD neu. Wenn da an anderen
Ausgängen sonst noch was hängt, veränderst du damit ungewollt deren
Zustand. PORTC kannst du komplett zuweisen, das ist kein Thema. Aber am
Port D musst du ein wenig sorgfältiger sein.
Erst die beiden untersten Bits (welches sind es jetzt eigentlich: PD0
und PD1 oder doch PD1 und PD2?) gezielt auf 0 setzen und dann den Wert
aus dem Array darüberodern.
@Karl Heinz Buchegger
stimmt natürlich, mit Bits viel leichter zu lesen.
Das mit den 8 Bit ist mir auch gerade aufgefallen, da hab ich mal wieder
etwas durcheinander gedacht ;)
ich habe ja oben noch geschrieben, dass ich es dann so setze:
PORTC = Vorlage[Wert];
PORTD = Vorlage2[Wert];
An Port D wird allerdings noch an anderen Pins etwas ausgegeben.
Ich bin mir nicht sicher ob ich da etwas übersehen habe, aber ich habe
in dem AVR-GCC Tutorial nicht gefunden, wie ich das jetzt am besten
setze.
(deswegen auch etwas umständlichs setzen des Port D im ersten Beitrag)
Jano schrieb:> oh du warst mit der Antwort schneller, wie ich mit meiner Frage.> Ja ist ein schreibfehler, sollte P0 und P1 sein.>> Was heißt darüberodern?
Eine Oder-Operation.
Mittels
PORTD |= ( 1 << PD0 );
würdest du PD0 auf 1 setzen.
Mittels
PORTD |= ( 1 << PD0 ) | ( 1 << PD1 );
würdest du PD0 und PD1 auf 1 setzen.
Mittels
PORTD |= MaskeD[Wert];
würdest du die Bits 0 bzw 1 auf 1 setzen, je nachdem ob sie in der Maske
gesetzt sind.
Aber!
Du kannst die so nicht mehr auf 0 bringen. Mit dem Oder kannst du sie
nur auf 1 ziehen. Macht aber nichts. Ziehst du eben die beiden Bits auf
jeden Fall erst mal auf 0 und dann je nach Bedarf (was eben das
Maskenbyte sagt) die entsprechenden Bits auf 1
PORTD = ( PORTD & ~0x03 ) | MaskeD[Wert];
> in dem AVR-GCC Tutorial nicht gefunden, wie ich das jetzt am> besten setze.
Weil du hier Dinge kombinieren musst.
2 Grundtechniken (Bit setzen, Bit löschen) zu einer Einheit
zusammenbauen.
Jano schrieb:> das ganze wird auf 10 Reihen gemultiplext, also brauch ich> 10 x ca.30 pro Sekunde, damit es für das Auge schön anzusehen ist.>> Das ist natürlich nicht das einzigste, was in der Schleife hängt. Habe> aber bei Begin der Stelle ein Bit gesetzt und am Ende zurückgesetzt. Das> Oszi hat mir dann verraten, dass das Ganze im Vergleich zum Rest viel> Zeit in anspruch nimmt.
Das lässt mich Schlimmeres zum Themenkreis 'Multiplexen' erahnen.
Karl Heinz Buchegger schrieb:> Das lässt mich Schlimmeres zum Themenkreis 'Multiplexen' erahnen.
Komm, Jano, trau dich und lass aus der Vermutung Gewissheit werden:
poste deinen Code als Anhang...
Multiplexen hat in der Mainloop nichts zu suchen. Das gehört immer in
den Timerinterrupt!
Die Mainloop muß die Ausgabedaten nur aufbereiten und im SRAM bereit
stellen.
Peter