Hallo Experten,
ich möchte einen 74HC595 zur Ansteuerung von LEDs verwenden. Im Prinzip
ist mir klar, was der IC macht, aber im Datenblatt bin ich über /G und
/SCLR gestolpert. Werden diese Pins unbedingt benötigt? Oder kann ich
die Pins einfach fest auf LOW legen, wenn ich weder das Shift Register
klären noch die Ausgänge zurücksetzen will?
Darüber hinaus würde ich mich freuen, wenn Ihr mal über die folgende
Funktion schauen würdet, die die Werte für die LEDs ins Schieberegister
schieben und zuletzt die Werte in das Speicherregister übernehmen soll.
Der uC ist ein AVR ATTiny2313 mit 1 MHz-Quarz. Da mir langsam der Flash
eng wird, würde ich mich insbesondere über Tipps zur Grössenoptimierung
freuen.
beide Pins, G und SCLR sind active Low. D.h. sie machen die ihnen
zugedachte Operation, wenn der Pin auf Low gezogen ist.
G ist der Output Enbale
legst du den fest auf Low, dann ist der Output auf Dauerenable.
Genau das was du willst
SCLR ist der Clear Eingang
legst du den fest auf Low, geht der IC auf Dauerclear.
NICHT das was du willst. D.h. den Pin legst du auf Vcc
Zu deiner Funktion:
Das hier
bit_is_set(val, i) ? \
ist eine Operation, die du nicht machen willst. Du willst auf einem AVR
keine Bitoperationen machen, bei denen die Bitnummern keine fixen Werte
sind. Denn dafür (für variable Werte) hat der AVR keine
Prozessorinstruktion. D.h das ist eine 'teure' Operation.
Was du statt dessen machen willst, ist eine Maske mit einem 1 Bit und
anstelle, dass du dir jedesmal eine neue Maske mit einer 1 an
Bitposition i generierst, schiebst du einfach die Maske um 1 Stelle
weiter
Die asm("nop") kannst du dir auch sparen. Der 595 ist schnell genug,
dass du vom AVR aus 'volle Kanne' drauf los gehen kannst.
Die Line Continuation ( '\' ) brauchst du hier nicht. Die brauchst du
nur bei Preprozessor Makros. In C darfst du zwischen 2 Worte immer
beliebig viele Leerzeichen und Zeilenumbrüche machen.
1
voidshiftIt8(uint8_tval)
2
{
3
uint8_tmask=0x01;
4
5
while(mask!=0x00)
6
{
7
if(val&mask)
8
PORTD|=(1<<PD2);
9
else
10
PORTD&=~(1<<PD2);
11
12
PORTD|=(1<<PD3);
13
PORTD&=~(1<<PD3);
14
15
mask<<=1;
16
}
17
18
PORTD|=(1<<PD4);
19
PORTD&=~(1<<PD4);
20
}
> Da mir langsam der Flash> eng wird, würde ich mich insbesondere über Tipps zur> Grössenoptimierung freuen.
mit aktiviertem Optimizer wird die Funktion nicht besonders lang sein.
Generell kann man da ohne konkreten Code meistens wenig sagen. Lass dir
vom Compiler ein Map-File generieren und sieh nach, welche Funktionen
den meisten Platz brauchen.
Als Faustregel:
* mach einen großen Bogen um Gleitkommarechnerei.
* keine _delay_ms mit variablen Werten
* Optimizer aktivieren
* immer den kleinsten benötigten Datentyp nehmen
* nicht sinnlos rumcasten
Das sollte eigentlich normalerweise Programme ergeben, die schon sehr
dicht am Optimum liegen. Ein bischen besser als der Compiler kriegt es
ein guter Assembler Programmierer schon hin, aber die paar Prozent
machens normalerweise nicht aus.
Hallo Karl-Heinz,
vielen Dank für Deine schnelle (und tolle) Antwort.
Karl Heinz Buchegger schrieb:> Zu deiner Funktion:>> Das hier> bit_is_set(val, i) ? \> ist eine Operation, die du nicht machen willst. Du willst auf einem AVR> keine Bitoperationen machen, bei denen die Bitnummern keine fixen Werte> sind. Denn dafür (für variable Werte) hat der AVR keine> Prozessorinstruktion. D.h das ist eine 'teure' Operation.>> Was du statt dessen machen willst, ist eine Maske mit einem 1 Bit und> anstelle, dass du dir jedesmal eine neue Maske mit einer 1 an> Bitposition 1 generierst, schiebst du einfach die Maske um 1 Stelle> weiter
Das ist ein ausgesprochen schicker Trick, vielen Dank!
> Die asm("nop") kannst du dir auch sparen. Der 595 ist schnell genug,> dass du vom AVR aus 'volle Kanne' drauf los gehen kannst.
Gilt das auch, wenn ich den AVR mal mit 20 MHz takte? Im Datenblatt des
IC steht was von 59 MHz, die NOPs hatte ich eigentlich nur zur
Sicherheit eingebaut.
> Die Line Continuation ( '\' ) brauchst du hier nicht. Die brauchst du> nur bei Preprozessor Makros. In C darfst du zwischen 2 Worte immer> beliebig viele Leerzeichen und Zeilenumbrüche machen.
Ich finde das so besonders lesbar, (cond) ? (1) : (0) ist ja eh kein so
gebräuchliches Konstrukt.
>
1
>voidshiftIt8(uint8_tval)
2
>{
3
>uint8_tmask=0x01;
4
>
5
>while(mask!=0x00)
6
>{
7
/*...*/
8
>mask<<=1;
9
>}
10
/*...*/
11
>}
12
>
Wow. Sehr elegant und trotzdem prima lesbar!
Vielen Dank,
Karl
Karl Käfer schrieb:> Ich finde das so besonders lesbar, (cond) ? (1) : (0) ist ja eh kein so> gebräuchliches Konstrukt.
Wenn du willst, kannst du natürlich auch den ?: operator benutzen.
1
(val&mask)?PORTD|=(1<<PD2):PORTD&=~(1<<PD2);
oder so formatiert
1
(val&mask)?PORTD|=(1<<PD2)
2
:PORTD&=~(1<<PD2);
Der springende Punkt ist aber der: Wenn ein Statement über mehrere
Zeilen geht, dann brich einfach um. Du brauchst dazu keinen Continuation
Character '\'!
Den brauchst du nur in Makros
#define TEST PORTD |= \
( 1 << PD0 );
um dem Präprozessor anzuzeigen, dass die nächste Zeile auch noch zum
Makro gehört. Denn für den Präprozessor hört die Zeile (! der arbeitet
ja textbasiert(*)) eben beim Zeilenvorschub auf.
(*) stimmt nicht ganz. Eigentlich tokenbasiert. Aber er betrachtet immer
nur 1 Zeile.
Karl Käfer schrieb:>> Die asm("nop") kannst du dir auch sparen. Der 595 ist schnell genug,>> dass du vom AVR aus 'volle Kanne' drauf los gehen kannst.>> Gilt das auch, wenn ich den AVR mal mit 20 MHz takte? Im Datenblatt des> IC steht was von 59 MHz
Da der AVR es nicht schafft, seinen Takt zu verdreifachen, sollte
klar sein, dass es geht: selbst mit nur einem Takt pro IO-Befehl
muss der Impuls bei 20 MHz halt noch 50 ns breit werden. Mal unter
der Annahme, dass du den 74HC595 nicht nur mit 2 V sondern mit 5 V
betreibst, liegen die 50 ns über allen vom Datenblatt geforderten
Mindestzeiten deutlich drüber.
@Karl Käfer
wenn du noch weiter sparen willst, bei gleichzeitiger Erhöhung der
Geschwindigkeit, dann kannst du auch die SPI oder das USI verwenden -
wenn nicht schon anderweitig benutzt und die entsprechenden PIN's müssen
natürlich auch frei sein.
Sascha
Hallo,
Karl Heinz Buchegger schrieb:> Du bist gut, weißt du das?
Naja, ich gebe mir Mühe.
> Du hast problemlos das entscheidende 'wichtige' Pattern rausdestilliert.
Schon richtig -- aber mir ging es ja gerade um die effiziente und
elegante Erzeugung der verAND-baren Bitmaske.
> Gefällt mir.
Och menno! Jetzt hatte ich wirklich gehofft, Fratzbuch wenigstens hier
mal entkommen zu sein. ;-)
Danke (auch Euch, Jörg und Sascha!),
Karl