Hallo,
ich habe ein kleines Logikproblem.
Und zwar habe ich eine Matrize, die beispielsweise wie folgt aussieht:
1
1: 00000000
2
2: 00000000
3
3: 00000000
4
4: 00011100
5
5: 00000000
6
6: 00000000
7
7: 00000000
8
8: 00000000
nun möchte ich dieses Muster um 90° nach rechts drehen damit es wie
folgt aussieht:
1
1: 00000000
2
2: 00000000
3
3: 00000000
4
4: 00000100
5
5: 00000100
6
6: 00000100
7
7: 00000000
8
8: 00000000
Das ganze steht in einem Array und ich möchte dann mithilfe einer
Schleife das ganz umbauen...Nur ich komme einfach nicht zu einer Lösung
1
intoriginal_muster[8];
2
intgedrehtes_muster[8];
3
inti=0;
4
while(i<8){
5
original_muster[i]=//nnnnnnnn? und nun? n'tes (1-8) Bit ist i'tes Bit von original_muster[8-n]
6
i++;
7
}
Meine Beschreibung im Kommentar stimmt, allerdings weiß ich nicht wie
ich das nun programmieren soll...
Über Hilfe wäre ich sehr dankbar.
Gruß und schönen Abend,
Michael
Wenn's nicht gerade ein hochoptimierter Algorithmus sein muss, dann ist
es der Logik nach mit dem Vertauschen der X- und Y-Koordinaten zwischen
Lesen und Schreiben (in einen Zwischenpuffer) zu erledigen. In einem
Basic-artigen Pseudocode sähe das etwa so aus:
for x=0 to xmax-1
for y=0 to ymax-1
buf[x,y]=orig[y,x]
next y
next x
... oder?
Michael N. schrieb:> und woher bekomme ich n?> Wie verpacke ich das wiederrum in ne schleife?>> Programmiere zu selten auf Bitebene um das schnell zu verstehen...
Ach, und in deiner gewohnten Hochsprache gibt es keine Schleifen und
Schleifenindex-Variablen?
Das hat nicht zufällig was mit einem Grafikdisplay zu tun?
Hatte in dem Zusammenhang mal die gleiche Anwendung...
Wie Simon richtig schreibt:
Du brauchst zwei Schleifen, eine für die Bytes und eine für die Bits.
Falls es ein µC ohne Barrelshifter ist (z.B. AVR): Versuche den Code so
zu optimieren, daß Du immer nur um eine Bit-Stelle weiterscheiben mußt,
da der AVR für jede Stelle einen Befehl braucht.
Das selbe hab ich noch als Inline-Assembler rumliegen, mithilfe des
Carry-Bits und intelligentem Stack-Mißbrauch :-P
In dem Projekt musste ich das regelmäßig auf 768 bytes anwenden. Die
Assembler-Variante war glaub Faktor 3 schneller als in C.
Ich such heut Abend mal und stells hier ein.
So, hier mit etwas Verspätung die versprochene Routine, auf die Schnelle
in ne undokumentierte C-Funktion verpackt :-P
Was mich gerade beim ausprobiern verwundert: Zum Einlesen des Arrays in
die Register-Variablen benutzt der Compiler brav ldd (load with
displacement). Beim Schreiben erzeugt er ein meiner Meinung nach
unglaublich umständliches Konstrukt. Ich hab mich bei sowas schon oft
getäuscht und musste dann zugegeben, dass der Compiler teilweise echt
clever vorgeht. Hier kann ich mir aber nicht vorstellen, dass das nicht
effizienter und mit weniger Code geht und er auch problemlos drauf
kommen könnte.
Hier der entsprechende Ausschnitt des lss-files.
Einlesen des in-Arrays in die Register-Variablen:
1
c0=in[0];
2
2cc:7081ldr23,Z
3
c1=in[1];
4
2ce:6181lddr22,Z+1;0x01
5
c2=in[2];
6
2d0:5281lddr21,Z+2;0x02
7
c3=in[3];
8
2d2:4381lddr20,Z+3;0x03
9
c4=in[4];
10
2d4:3481lddr19,Z+4;0x04
11
c5=in[5];
12
2d6:2581lddr18,Z+5;0x05
13
c6=in[6];
14
2d8:9681lddr25,Z+6;0x06
15
c7=in[7];
16
2da:8781lddr24,Z+7;0x07
17
.
18
.
19
.
Und später Zurückschreiben ins out-array:
1
out[0]=c0;
2
314:7c93stX,r23
3
out[1]=c1;
4
316:1196adiwr26,0x01;1
5
318:6c93stX,r22
6
31a:1197sbiwr26,0x01;1
7
out[2]=c2;
8
31c:1296adiwr26,0x02;2
9
31e:5c93stX,r21
10
320:1297sbiwr26,0x02;2
11
out[3]=c3;
12
322:1396adiwr26,0x03;3
13
324:4c93stX,r20
14
326:1397sbiwr26,0x03;3
15
out[4]=c4;
16
328:1496adiwr26,0x04;4
17
32a:3c93stX,r19
18
32c:1497sbiwr26,0x04;4
19
out[5]=c5;
20
32e:1596adiwr26,0x05;5
21
330:2c93stX,r18
22
332:1597sbiwr26,0x05;5
23
out[6]=c6;
24
334:1696adiwr26,0x06;6
25
336:9c93stX,r25
26
338:1697sbiwr26,0x06;6
27
out[7]=c7;
28
33a:1796adiwr26,0x07;7
29
33c:8c93stX,r24
30
33e:1797sbiwr26,0x07;7
31
340:0895ret
Ich versteh ja, dass er die Adresse des out-arrays im X-Registerpaar
bekommt und das kein load with displacement anbietet. aber zumindest das
sbiw und folgende adiw hätte er zusammenfassen können. Und wenn er noch
etwas schlauer ist, sichert er Z, kopiert X nach Z und benutzt Z wieder
mit displacement.
Achso, ich hab mit AvrStudio 6.0.1843, also AVR Toolchain 3.4.0.663 /
GCC 4.6.2 und Optimierung -Os compiliert.
Gibts für das seltsame Verhalten nen Grund, der sich mir nur nicht
erschließt?
Gruß, Alex
Warum alles so kompliziert ?
Viel einfacher und pragmatisch wäre es, sie einfach gedreht auszulesen,
also etwa in der entsprechenden Routine Zeilen- und Spaltenindex zu
vertauschen ...
Ich würde gern mal einen Schritt zurück machen...
Michael N. schrieb:> nun möchte ich dieses Muster um 90° nach rechts drehen
Warum?
Warum an dieser Programmstelle?
Wo wird das Muster erzeugt?
Wie wird es ausgegeben?
Evtl. reicht es, wenn du dein mentales Modell an irgendeiner Stelle um
90° drehst...
(Dieser Satz ist ernst gemeint!)
@Martin: kommt darauf an, was du damit noch machen möchtest. Wenn du nur
einzelne Werte brauchst, geb ich dir recht. Wenn du tatsächlich das
gesamte Array brauchst, ist das in einem Rutsch sicher schneller. Ob der
OP das schneller braucht, ist dann wieder eine sehr berechtigte Frage.
@Lothar: da hast du absolut recht.
Nachdem der OP geschrieben hat, dass es für eine LED-Matrix ist vermute
ich einfach mal, dass er z.B. für Bit-Angle-Modulation ein Ausgabe-Array
erzeugen will. dann kommt er ums vollständig drehen wohl nicht rum.
Und außerdem glaube ich, dass du im asm nicht vorgeben kannst, wie
deiner Funktion die Parameter zu übergeben sind :) (siehe Zuordnung x
und z)
Aber grundsätzlich hast du recht, das Arrays ein- und auslesen lässt
sich bestimmt noch vereinfachen. Wieso müssen die Arrays volatile sein?
Ich habe es aus einem bestehenden Programm übernommen, wo das
Zurückschreiben des Ergebnisses nochmal anders funktioniert. Ist also
nur auf die schnelle zusammengestrickt gewesen.
Jaja, und das "clc" ist auch für die Füße, und der Eingangsparameter
hätte ein "const" verdient.
Alexander v. Grafenstein schrieb:> Und außerdem glaube ich, dass du im asm nicht vorgeben kannst, wie> deiner Funktion die Parameter zu übergeben sind :) (siehe Zuordnung x> und z)
Im Inline-Assembler-Cookbook (
http://www.nongnu.org/avr-libc/user-manual/inline_asm.html ) wird es
unter "Input and Output Operands" so beschrieben.
Ich habe es ausprobiert, und es hat funktioniert. Das List-File sieht
auch gut aus.
> Aber grundsätzlich hast du recht, das Arrays ein- und auslesen lässt> sich bestimmt noch vereinfachen. Wieso müssen die Arrays volatile sein?
Müssen sie in diesem Fall nicht, aber wenn andere Teile des Programms
auf mo zugreifen, sollte der Compiler schon wissen, dass er die vor
Verwendung nachladen muss. Das gilt zwar insbesondere für ISRs, aber
soweit ich das verstehe, eben auch, wenn z.B.
1
mo[1]=blah;
2
BitsDrehen8x8(mi,mo);
3
hurz=mo[1];// hurz != blah !!!
Suche mal nach
"In most situations, a much better solution would be to declare the
pointer destination itself volatile"
> Ich habe es aus einem bestehenden Programm übernommen, wo das> Zurückschreiben des Ergebnisses nochmal anders funktioniert. Ist also> nur auf die schnelle zusammengestrickt gewesen.
In den 80ern habe ich mal ähnlich einen Nadeldrucker mit HGC-Grafikdaten
gefüttert. Deinen Beitrag habe ich mir zum Anlass genommen, in das
Inline Assembler Cookbock reinzuschauen.