Moin,
ich experimentiere grad ein wenig für ein kommendes Projekt und brauche
grade mal einen Denkanstoß (liegt vielleicht an der Uhrzeit aber ich
will, dass es jetzt geht :D )
Kann ich die Ports eines Atmegas (im Mom am Atmega8515L 8PU, sollte aber
allgemein funktionieren) "durchzählen" lassen. Also wie z.B. mit i++ von
z.B. PORTA PA0 bist PA7 hochzählen lassen? Man könnte sich das wie ein
Lauflicht vorstellen.
Gruß
Christopher
Chrsitopher Rohe schrieb:> Kann ich die Ports eines Atmegas (im Mom am Atmega8515L 8PU, sollte aber> allgemein funktionieren) "durchzählen" lassen. Also wie z.B. mit i++ von> z.B. PORTA PA0 bist PA7 hochzählen lassen?
Jein, nicht bitweise. Aber die Adressen der Register PORT[ABCD] liegen
in gleichmäßigen Abstand voneinander im Speicher. Das it mindestens beim
atmega8515 so, bei den anderen Prozessoren sollte man das verifizieren
("Register Summary" im Datenblatt), ist aber höchstwahrscheinlich so.
Dann kann man im Prinzip sowas machen (ungetesteter code):
1
uint8_t *p;
2
uint8_t i;
3
4
for (p = &PORTA; p <= &PORTD; p += (&PORTA - &PORTB)) {
5
for (i = 0; i < 8; i++)
6
*p |= (1 << i);
7
}
Diese Schleife sollte die Pins PA0,..,PA7,PB0,...,PB7,....,PD7
nacheinander auf 1 setzen.
Wie gesagt, das ist nur mal eben freihändig hingeschrieben, wenn es
nicht funktioniert sollte aber doch das Prinzip erkennbar sein.
Viele Grüße,
Simon
kannst du, du mußt aber binär zählen (effektiv mit 2 multiplizieren).
beispielsweise
LDI R16,1
OUT PORTn,R16
damit leuchtet deine LED am niederwertigsten bit/pin auf.
alles weitere würde ich mit einer bitverschiebung machen.
loop:
ROL R16 (rotate left, ROL heißt's jedenfalls beim x86 assembler)
OUT PORTn,R16
<delay> (warteschleife, sonst flackern deine LEDs mit 1-2 MHz)
RJMP loop
habe jetzt den genauen AVR assembler-befehl für die bit-rotation mit
überlauf nicht im kopf, da schau da bitte nochmal ins datenblatt.
EDIT: war wer schneller.
Oh, ich sehe gerade, dass bei dem atmega8515 auch noch ein PORTE
existiert, das aus diesem Raster rausfällt. Also: Nicht darauf
verlassen, immer im Datenblatt nachgucken ob es passt...
Viele Grüße,
Simon
register mit 0x01 laden, nach portA ausgeben, register
links/rechtsshiften über carry und wieder ausgeben, usw.
vllt. noch mit etwas wartezeiten dazwischen
> for (p = &PORTA; p <= &PORTD; p += (&PORTA - &PORTB)) {
5
> for (i = 0; i < 8; i++)
6
> *p |= (1 << i);
7
> }
8
>
Bei diesem Code bleiben die LEDs an, es läuft also ein Band, kein Punkt.
Ich habe gehört, dass Konstrukte wie (1<<i) relativ langsam sind.
1
uint8_t *p;
2
uint8_t i;
3
4
for (p = &PORTA; p <= &PORTD; p += (&PORTA - &PORTB)) {
5
*p = 1;
6
for (i = 0; i < 8; i++)
7
*p = *p<<1;
8
}
Simon Budig schrieb:> Oh, ich sehe gerade, dass bei dem atmega8515 auch noch ein PORTE> existiert, das aus diesem Raster rausfällt. Also: Nicht darauf> verlassen, immer im Datenblatt nachgucken ob es passt...>> Viele Grüße,> Simon
Dann macht man eben ein Array mit Pointern auf die jeweiligen PORTs.
Dann ist man von den Adressen unabhängig.
Ui. Noch richtig was los hier um diese Uhrzeit.
Wie immer zu spät merke ich das ich Infos unterschlagen habe:
1. Ich programmiere in C
2. Ich bin noch recht unerfahren beim Programmieren von µC
@Simon: Wie Luk4s anmerkt läuft bei deinem Code kein Punkt sondern die
Ports schalten nach und nach alle auf 1
@Luk4s: Bei PORTA = PORTA>>1; bzw. PORTA = PORTA<<1; passiert aber das
gleiche ^^
Luk4s K. schrieb:> Bei diesem Code bleiben die LEDs an, es läuft also ein Band, kein Punkt.
Ja, habe ich hier in Kauf genommen, weil es mir um das Prinzip der
Adressierung ging (aber s.u.).
> Ich habe gehört, dass Konstrukte wie (1<<i) relativ langsam sind.Eigentlich sollte der C-Compiler das direkt in eine SBI-Instruktion
übersetzen. Sollte nicht wirklich aufwendig sein...
(hab gerade nachgeguckt: Ok, SBI kostet zwei Taktzyklen und ist damit
eine der langsameren.)
> Dann macht man eben ein Array mit Pointern auf die jeweiligen PORTs.> Dann ist man von den Adressen unabhängig.
Ja, das ist vermutlich sinnvoll. Prozessorunabhängig (wie vom OP
gewünscht) wird man es aber vermutlich nicht wirklich hinkriegen - bei
manchen AVRs fehlt z.B. PORTA...
In meiner Schleife ist noch ein Bug, das Increment-statement der äußeren
for-schleife sollte natürlich sinnvollerweise
1
p += (&PORTB - &PORTA)
heißen.
Und die eine Warnung kriegt man noch weg, wenn man *p als volatile
deklariert...
Viele Grüße,
Simon
Simon Budig schrieb:>> Ich habe gehört, dass Konstrukte wie (1<<i) relativ langsam sind.>> Eigentlich sollte der C-Compiler das direkt in eine SBI-Instruktion> übersetzen. Sollte nicht wirklich aufwendig sein...
Das wird schwierig für den Compiler, solange i keine Konstante sondern
eine Variable ist.
OK. Wenn der Compiler sich zu Loop-Unrolling entschliesst, könnte er
dieses Baby knacken.
Chrsitopher Rohe schrieb:> @Simon: Wie Luk4s anmerkt läuft bei deinem Code kein Punkt sondern die> Ports schalten nach und nach alle auf 1
Das sollte aber für einen alten Bitschieber-Spezi nicht wirklich das
Porblem sein.
> @Luk4s: Bei PORTA = PORTA>>1; bzw. PORTA = PORTA<<1; passiert aber das> gleiche ^^
... Nicht ... wirklich
Es ist aber trotzdem eher ungeschickt. Eine zusätzliche Variable, in der
der 1-er geschoben wird könnte besser sein. Die Chancen, dass der
Compiler diese Variable in einem Registr halten kann sind sehr gut. Bei
PORTA <<= 1 muss hingegen jedesmal der PORTA erst ausgelesen werden um
den Wert dann um 1 Stelle zu schieben.
Chrsitopher Rohe schrieb:> Ui. Noch richtig was los hier um diese Uhrzeit.>> Wie immer zu spät merke ich das ich Infos unterschlagen habe:>> 1. Ich programmiere in C> 2. Ich bin noch recht unerfahren beim Programmieren von µC>> @Simon: Wie Luk4s anmerkt läuft bei deinem Code kein Punkt sondern die> Ports schalten nach und nach alle auf 1>> @Luk4s: Bei PORTA = PORTA>>1; bzw. PORTA = PORTA<<1; passiert aber das> gleiche ^^
Bei PORTA = PORTA<<1; läuft die LED vom LSB zum MSB. Als Startwert ist
für PORTA demnach 1 zu setzen.
Bei PORTA = PORTA>>1; läuft die LED vom MSB zum LSB. Als Startwert ist
für PORTA demnach 128 zu setzen.
Karl heinz Buchegger schrieb:> Simon Budig schrieb:>>>> Ich habe gehört, dass Konstrukte wie (1<<i) relativ langsam sind.>>>> Eigentlich sollte der C-Compiler das direkt in eine SBI-Instruktion>> übersetzen. Sollte nicht wirklich aufwendig sein...>> Das wird schwierig für den Compiler, solange i keine Konstante sondern> eine Variable ist.
Stimmt. Ich habe die "Instruction Set Summary" nicht richtig gelesen. Da
hat SBI zwei Operanden: "P,b" und das b muss schon zur Compile-Zeit
feststehen...
Viele Grüße,
Simon
Nicht getestet, sollte aber so passen.[/code]
Das sieht schon sehr gut aus. Das werde ich nachher (ist ja schon
Freitag ^^) mal genau unter die Lupe nehmen und auf meine Bedürfnisse
anpassen. Dankö und noch eine gute Nacht! Macht nicht mehr so lange :D