Hallo zusammen!
Ich würde gerne recht effektiv 3 Pins eines Ports parallel setzen.
Möchte LEDs ansteuern aber den restlichen Port unberührt lassen.
Grund für das parallele Setzen ist ein 2x5 LED_Array.
Ich werde es dann mal vorstellen wenn es soweit funktioniert.
erst versuchte ich es mit:
1
temp&=0x03;//temp vorbereiten
2
PORTA&=~0x03;//pins clearen
3
PORTA|=temp;//pins setzen
natürlich bekommt man hier bei hohen Frequenzen ein zu geringes
Tastverhältnis.
Ganz gut geht es mit:
Steven () schrieb:> Weil ich 2 Ports möglichst schnell hintereinander ändern will.
definiere 'möglichstr schnell' und auch warum das bei einer LED-Matrix
so wichtig ist.
Ob die LED jetzt nach 1 Millionstel Sekunde brennen oder nach 2 kann
kein Mensch feststellen. Und nachdem die LED umgeschaltet wurden brennen
sie dann sowieso wieder 1 Millisekunde oder länger ehe dann der nächste
Wechsel in entweder 1 oder 2 Millionstel Sekunden erfolgt.
Du optimierst etwas, wo es kaum was zu optimieren gibt.
void LEDBar_setLEDs(uint8_t temp){
....
DDRA |= LEDBar_Mask_A; //Ports einschalten
DDRB |= LEDBar_Mask_B;
}
und du beschwerst dich über die Laufzeit vom Port setzen?
Spar doch einfach mal die Zeit ein, die du problemlos einsparen kannst!
Welchen Sinn soll das haben, wenn du die Pins wieder und immer wieder
auf Ausgang stellst? Die vergessen das nicht. Einmal, beim Programmstart
einstellen, reicht doch dicke aus.
Hallo Karl Heinz,
auch wenn es sehr wohl etwas unsinnig ist, hat mich das im Allgemeinen
mal interessiert, weil ich schon ein paar mal darauf gestoßen bin.
Diese Optimierung also, um es mal zu wissen, Du kannst es ja als Übung
betrachten.
Mir ist es eben aufgefallen, dass ohne diese Optimierung bei hoher
Aktuallisierungsfrequenz ein paar LEDs schwach leuchten. Und deswegen
dieser Schritt. Ich wollte auch nicht einfach die Frequenz ändern
sondern dem Grund auf die Schliche kommen.
Folgendes ist gerade mein Projekt. Ein LED-Bargraph mit 10LEDs mit 6
Pins steuern, das ganze mit dem Attiny24. Nebenbei will ich SPI und I2C
freihalten.
//LEDs sind so verschaltet:
// PA0 PA1 PA2 PB0 PB1 PA0 PA1 PA2 PB0 PB1
// A A A A A K K K K K
// 0 1 2 3 4 5 6 7 8 9 LED_s
// K K K K K A A A A A
// PB2 PB2 PB2 PB2 PB2 PB2 PB2 PB2 PB2 PB2
//
// Einzelne LED ansteuern:
// LED PB2 PB1 PB0 PA2 PA1 PA0
// 0 0 0 0 0 0 1
// 1 0 0 0 0 1 0
// 2 0 0 0 1 0 0
// 3 0 0 1 0 0 0
// 4 0 1 0 0 0 0
// 5 1 1 1 1 1 0
// 6 1 1 1 1 0 1
// 7 1 1 1 0 1 1
// 8 1 1 0 1 1 1
// 9 1 0 1 1 1 1
Die DDR-Sache ist noch ein Überbleibsel von der letzten Version, dort
hatte ich die Ports auf Tristate solange sich was geändert hat. Hindert
das möglichst zeitnahe Ändern der Ports aber nicht. Kann also raus...
...
Gruß Steven
Steven () schrieb:> auch wenn es sehr wohl etwas unsinnig ist, hat mich das im Allgemeinen> mal interessiert, weil ich schon ein paar mal darauf gestoßen bin.> Diese Optimierung also, um es mal zu wissen, Du kannst es ja als Übung> betrachten.
Na, ja.
Was willst du da
PORTB = (PORTB&~LEDBar_Mask_B)|savePortB;
groß optimieren?
Ohne mir jetzt den Assembler Output angesehen zu haben, erwarte ich,
dass der Compiler das übersetzt zu (LEDBar_Mask_B ist eine Konstante?)
in register, PORTB
andi register, Maskenbyte
or register, register in dem savePortB hergerichtet wurde
out PORTB, register
kannst dir ja mal ansehen, wieviele Taktzyklen das sind und was das bei
deiner Taktfrequenz in Zeit ausmacht.
> Mir ist es eben aufgefallen, dass ohne diese Optimierung bei hoher> Aktuallisierungsfrequenz ein paar LEDs schwach leuchten.
Ja. Das ist aber was anderes.
Das nennt sich Ghosting und kommt daher, dass du eben nicht beide Ports
exakt gleichzeitig umschaltest / umschalten kannst.
Du musst
erst die LED auf jeden Fall abschalten
dann die neuen Einstellungen machen
und zum Abschluss dann die Einstellung, die die LED wieder
zum Leuchten bringt
Das Auge ist da sehr empfindlich. Wir sehen es auch, wenn LED nur ganz
kurz, ein paar µs lang brennen.
Der entscheidende Punkt ist, dass du die LED als erstes auf jeden Fall
abschalten musst. Dann manipulierst du den einen Port und wenn du dann
den 2.te Port manipulierst, erst dann dürfen die LED (mit der
veränderten Konfiguration) erneut zu leuchten beginnen.
Schaltest du nicht ab, dann hast du kurzzeitig einen Zwischenstand an
den LED, so dass andere als die gewollten Leuchten. Und das siehst du.
>Was willst du da>PORTB = (PORTB&~LEDBar_Mask_B)|savePortB;>groß optimieren?
Nichts, das funktioniert wunderbar. Ich dachte es gibt ein Trick in C
den ich noch nicht kenne.
>Ghosting
Ja, hinzu kommt das Problem, dass ich das nicht einfach ausschalten
kann. Wenn ich alle 6Pins auf logisch Low lege, sind 5LEDs an.
Wenn ich alle 6Pins auf logisch High lege, sind 5LEDs an.
Ohje, da seh ich selbst den Wald vor lauter Bäume nicht mehr.
Natürlich ist alles aus, wenn alles logisch Low ist.
Trotzallem: Schon alleine wegen
-erst auschchalten (Bits löschen)
-dann bits setzen
trat das "Ghosting" auf.
Deswegen belasse ich jetzt vorerst das funktionierende:
PORTA = savePortB;
PORTB = savePortB;
Und für zukünftige Projekte weis ich jetz, dass ich mehrere Bits auf
einem PORT parallel verändern kann ohne die anderen zu beeinflussen.
Steven () schrieb:>>Was willst du da>>PORTB = (PORTB&~LEDBar_Mask_B)|savePortB;>>groß optimieren?>> Nichts, das funktioniert wunderbar. Ich dachte es gibt ein Trick in C> den ich noch nicht kenne.>>>Ghosting> Ja, hinzu kommt das Problem, dass ich das nicht einfach ausschalten> kann. Wenn ich alle 6Pins auf logisch Low lege, sind 5LEDs an.> Wenn ich alle 6Pins auf logisch High lege, sind 5LEDs an.
Tja
// PA0 PA1 PA2 PB0 PB1 PA0 PA1 PA2 PB0 PB1
// A A A A A K K K K K
// 0 1 2 3 4 5 6 7 8 9 LED_s
// K K K K K A A A A A
// PB2 PB2 PB2 PB2 PB2 PB2 PB2 PB2 PB2 PB2
scheisse verschaltet.
was hängt extern zwischen Portpin und LED?
Dann mach mir mit 6Pins oder weniger einen besseren Vorschlag.
An PA0..2 und PB0..1 hängt jeweils ein 330R Widerstand davor. Sonst
nichts. PB2 ist einfach eine Leitung an 5Kathoden und 5Anoden.
Steven () schrieb:> Dann mach mir mit 6Pins oder weniger einen besseren Vorschlag.>> An PA0..2 und PB0..1 hängt jeweils ein 330R Widerstand davor. Sonst> nichts. PB2 ist einfach eine Leitung an 5Kathoden und 5Anoden.
Mutig.
Aber:
Wenn du einen Pin auf Eingang schaltest, kann er weder Strom senken noch
Strom liefern. Das könnte ein Ansatzpunkt sein. Selbst wenn ein Portpin
dann schon auf 1 ist, schaltet das lediglich den pullup hinzu und der
reicht nicht, damit eine LED leuchten kann. (hoffe ich mal)
Jetzt muss man 'nur noch' eine Eiertanzsequenz finden
// PA0 PA1 PA2 PB0 PB1 PA0 PA1 PA2 PB0 PB1
// A A A A A K K K K K
// 0 1 2 3 4 5 6 7 8 9 LED_s
// K K K K K A A A A A
// PB2 PB2 PB2 PB2 PB2 PB2 PB2 PB2 PB2 PB2
erst mal PB2 auf Eingang.
Hmm. das sollte eigentlich schon ausreichen, dass keine einzige LED mehr
leuchten kann.
danach die neue Belegung für PA0:2 PB0:2 ausgeben
und PB2 wieder auf Ausgang
probier das mal. Könnte klappen.
Dein Glück ist, dass jede einzelne LED von PB2 abhängig ist.
>Mutig
Ich wollte Platz sparen.
>Wenn du einen Pin auf Eingang schaltest,>kann er weder Strom senken noch Strom liefern.
Ja, ich hatte sogar das PUD-Flag gesetzt um die Pullups auszuschalten.
Zu dem Zeitpunkt sah der Code noch etwa so aus:
1
voidLEDBar_setLEDs_old(uint8_ttemp){
2
DDRA&=~LEDBar_Mask_A;//Auf Eingang schalten
3
DDRB&=~LEDBar_Mask_B;
4
5
if(temp&(1<<5))temp^=0x1F;//Invertiert die ersten 5 Bits,
Aber trotzdem die Ghostings auch trotz Ports als Eingang mit gesetztem
PUD-Flag!
Woher das kommt würde mich auch interessieren...
P.S. daher übrigends auch diese DDRA und B Befehle, die ich in einem
vorherigen Post vergessen hatte rauszunehmen.
Im Moment lasse ich die Ports einfach auf Ausgang. Solange die Ports
sich unmittelbar nacheinander ändern sieht man bei 1MHz internal Clock
keine Ghostings.