@Jörg Wunsch
Wenn ich wüste wonach genau, wäre die antwort OK. Aber ich kann hier
nicht mehrere hundert/Tausend Beiträge auf gut Glück durchlesen, um
eventuell auf ein ähnliches Prolem zu stossen. Ein Denkanstoss wäre
schon nett, dann kann ich nämlich die SuFu verwenden.
@Christof Krüger
JA.
Ich hab da was aus nem Projekt letztes Semester...
/* for bit_reverse: 3, fo an 8 pt FFT, 4 for 16 pt etc...*/
#define BIT_WIDTH 7
//__________________________FFT specific
functions_______________________________
/* Reversing the bits in an integer. No asm instruction
available for this -> slow */
int bit_reverse(int in) {
int rev=0;
int i;
for (i = 0; i < BIT_WIDTH; i++) {
rev = (rev << 1) | (in & 1);
in >>=1;
}
return rev;
}
Mit Bitwidth angeben wie lang (in Bit) der unzudrehende Wert ist. Also
beim AVR z.B. 8 für ein uint8_t oder 16 für einen uint16_t
also ich muss das selbe mit einer 8 bit zahl machen.
int bit_reverse(int in) {
int rev=0;
int i;
for (i = 0; i < BIT_WIDTH; i++) {
rev = (rev << 1) | (in & 1);
in >>=1;
}
return rev;
}
Das habe ich einfach von oben übernommen. ich muss dann bitwidth auf 8
setzen? Mwin größtes problem ist, das ich nicht weiß wie ich die
funktion in der main aufrufe. Kann mir das jemand sagen?
Hans Mildenberger schrieb:
> also ich muss das selbe mit einer 8 bit zahl machen.>> int bit_reverse(int in) {> int rev=0;> int i;>> for (i = 0; i < BIT_WIDTH; i++) {> rev = (rev << 1) | (in & 1);> in >>=1;> }> return rev;> }>> Das habe ich einfach von oben übernommen. ich muss dann bitwidth auf 8> setzen? Mwin größtes problem ist, das ich nicht weiß wie ich die> funktion in der main aufrufe. Kann mir das jemand sagen?
So wie jede andere Funktion auch
Entschuldige meine delitantische Antwort, aber es geht nicht :-(
int main (int argc, char *argv[])
{
ausgangswert = 01101100
ergebnis= bit (ausgangswert);
}
int bit_reverse(int in) {
int rev=0;
int i;
for (i = 0; i < BIT_WIDTH; i++) {
rev = (rev << 1) | (in & 1);
in >>=1;
}
return rev;
}
Es kommen fogende fehlermeldungen:
invalid suffix "b01100000" on integer contant
In function ínt main(int, char**)´:
ausgabewert undeclared (first use in function)
(Each undeclareded identifier is reported only once for each function it
appears in.)
bit reverse undeclared (first use in function)
in function int bit_reverse(int):
int bit reverse(int) used prior to declaration
[Build Error] [main.0] Error 1
1000 Dank das ihr euch die Zeit nehmt.
Da bleibt nur noch einer übrig.
Die anderen Fehlermeldungen gehen auch weg, wenn ich einfach das ich
ausgangswqert = 01100001´; geschrieben hätte.
In function ínt main(int, char**)´:
ausgabewert undeclared (first use in function)
(Each undeclareded identifier is reported only once for each function it
appears in.)
[Build Error] [main.0] Error 1
Hans Mildenberger schrieb:
> Da bleibt nur noch einer übrig.> Die anderen Fehlermeldungen gehen auch weg, wenn ich einfach das ich> ausgangswqert = 01100001´; geschrieben hätte.
Ja. Nur hätte das etwas ganz anderes gemacht als du dir auch nur in
deinen wildesten Träumen vorstellen kannst.
Oder sagen dir Oktalzahlen irgendetwas :-)
> In function ínt main(int, char**)´:> ausgabewert undeclared (first use in function)> (Each undeclareded identifier is reported only once for each function it> appears in.)> [Build Error] [main.0] Error 1
Den behebst du jetzt schön selber.
Der Compiler schreibt ja schon hin, was faul ist.
#define smax 8
#include <stdio.h>
int bit_reverse(int in) {
int rev=0;
int i;
for ( i=0; i < smax; i++)
{
rev = (rev << 1 )| (in & 1);
in >>1;
}
return rev;
}
int main(int argc, char *argv[])
{
int ausgangswert = 0x6C;
int ergebnis = bit_reverse(ausgangswert);
while(1)
{
printf("ergebnis = %d\n", ergebnis); }
}
So sieht mein Programm inzwischen aus. Läuft auch fehlerfrei. Allerdings
bekomme ich immer die Ausgabe "ergebnis = 0".
Kann mir das jemand erklären?
Hans Mildenberger schrieb:
> #define smax 8> #include <stdio.h>> int bit_reverse(int in) {> int rev=0;> int i;> for ( i=0; i < smax; i++)> {> rev = (rev << 1 )| (in & 1);> in >>1;> }> return rev;> }>>> int main(int argc, char *argv[])> {> int ausgangswert = 0x6C;> int ergebnis = bit_reverse(ausgangswert);> while(1)> {> printf("ergebnis = %d\n", ergebnis); }> }>> So sieht mein Programm inzwischen aus. Läuft auch fehlerfrei. Allerdings> bekomme ich immer die Ausgabe "ergebnis = 0".> Kann mir das jemand erklären?
Wenn du den obigen Code kompilierst, solltest du eine Warnung bekommen:
1
um.c: In function ‘bit_reverse’:
2
um.c:9: warning: statement with no effect
Wenn du Dir dann nochmal Zeile 9 anschaust:
1
in>>1;
Und mit dem Code von oben vergleichst:
1
in>>=1;
Stellst du fest das da ein Zeichen fehlt.
Sebastian
Die Methode von AVR ist richtig nett (und locker doppelt so schnell wie
die Schleife), habe ich so noch nicht gesehen, obwohl es eigentlich
ziemlich logisch ist.
Allerdings nicht unbedingt für Anfänger geeignet, was das Verständnis
betrifft.
Aber für jemanden der meint er kann schon programmieren eine nette
Fingerübung zum Nachvollziehen :-)
Hallo Peter,
die ist ja noch besser. Allerdings nur auf Rechner verwendbar bei denen
man ein bitadressierbares move von und zum Carry hat. Hat der AVR oder
PIC das?
Wieder was gelernt :-)
> Wie drehe ich eine Bitreihenfolge mit WinAVR um??
Man sollte für solche Aufgaben immer eine Funktion verwenden die einen
anderen Programmierer maximal verwirrt ;-) Just für diesen Zweck habe
ich vor etwas längerer Zeit folgende C Funktion geschrieben:
Mit x übergibt man die zu spiegelnden Daten, mit bits gibt man die
Anzahl der Bits die gespiegelt werden. Will man nur ein Byte spiegeln
nimmt man "bit_swap(x, 8)". Man kann aber auch nur zum Beispiel 5 Bits
spiegeln lassen oder 13, ganz egal...
klaus schrieb:
> Man sollte für solche Aufgaben immer eine Funktion verwenden die einen> anderen Programmierer maximal verwirrt ;-) Just für diesen Zweck habe> ich vor etwas längerer Zeit folgende C Funktion geschrieben:
Ziel verfehlt :-)
Damit kannst du gestandene Lisp Programmierer nicht übertölpeln. Die
schnallen sofort, dass du eine CAR (na ja) / CDR Zerlegung einer Liste
von Bits auf C Art machst und aus den bearbeiteten Einzelteilen wieder
eine neue Liste von Bits zusammensetzt :-)
Frei nach dem Motto:
Eine Liste wird umgedreht indem man die Liste in das erste Element und
den Rest zerlegt. Dann dreht man den Rest um und hängt das erste Element
hinten drann.
(Schöne Arbeit!)
Ein sehr schönes Beispiel für die Unsinnigkeit von Rekursionen.
Diese Routine maximiert wirklich alles negative:
- höchster Codeverbrauch
- höchster SRAM-Verbrauch
- höchste Zyklenzahl
Peter
Peter Dannegger schrieb:
> Am schönsten gehts aber in 8051 Assembler:
Nein in ARM (Thumb-2) Assembler: RBIT r0, r0 ;-)
Gruß
Marcus
http://www.doulos.com/arm/
Die Rekursion ist auch klasse.
Vor allem wenn man einen Hardwarestack mit der maximalen Tiefe von (4?)
hat :-))
War das nicht bei einigen Microcontrollern so?
Ich denke wir sind uns alle einig. Die Funktionen sind alle nicht so
einfach verständlich wie die Schleife, aber manchmal muss es einfach
schneller sein, und da sind durchaus auch Speziallösungen sinnvoll.
Schön waren die Lösungen allemal.
Gruß, Udo
klaus schrieb:
> Man sollte für solche Aufgaben immer eine Funktion verwenden die einen> anderen Programmierer maximal verwirrt ;-) Just für diesen Zweck habe> ich vor etwas längerer Zeit folgende C Funktion geschrieben:>>>
Wer auf einem Mikrocontroller rekursive Funktionen programmiert, der
gehört mindestens erschossen, besser noch sollte er sein Studium
komplett wiederholen müssen ;-)
Wohin gehst du?
Ins kino.
Was läuft?
Quo vadis!
Was bedeutet das?
Wohin gehst du?
Ins kino.
Was läuft?
Quo vadis!
Was bedeutet das?
Wohin gehst du?
Ins kino.
Was läuft?
Quo vadis!
Was bedeutet das?
Wohin gehst du?
Ins kino.
Was läuft?
Quo vadis!
Was bedeutet das?
Wohin gehst du?
Ins kino.
Was läuft?
Quo vadis!
Was bedeutet das?
Wohin gehst du?
Ins kino.
Was läuft?
Quo vadis!
Was bedeutet das?
Peter Dannegger schrieb:
> klaus schrieb:>>>>> size_t bit_swap(size_t x, size_t bits)>> {>> return bits ? (x & 1) << (bits - 1) | bit_swap(x >> 1, bits - 1) :>> 0;>> }>>>>> Ein sehr schönes Beispiel für die Unsinnigkeit von Rekursionen.> Diese Routine maximiert wirklich alles negative:> - höchster Codeverbrauch> - höchster SRAM-Verbrauch> - höchste Zyklenzahl
Rekursionen sind nicht generell unsinnig, sondern werden nur traditio-
nell in manchen Programmiersprachen häufiger genutzt als in anderen.
Da Karl Heinz weiter oben den LISP-Programmierer ins Spiel gebracht hat:
Dieser würde die Funktion (wenn er sich überhaupt in die C-Niederungen
herablässt :)) so schreiben:
1
size_tbit_swap2h(size_tx,size_tbits,size_tr){
2
returnbits?bit_swap2h(x>>1,bits-1,r<<1|x&1):r;
3
}
4
5
size_tbit_swap2(size_tx,size_tbits){
6
returnbit_swap2h(x,bits,0);
7
}
Dabei ist bit_swap2h eine Hilfsfunktion, die von bit_swap2 aufgeru-
fen wird. Da der Compiler in diesem Fall die Rekursion auflöst, brauchen
beide Funktionen zusammen ziemlich genau gleich viel Programmbytes,
Datenbytes und Taktzyklen wie die folgende, C-typischere Implementierung
mittels einer Schleife:
1
size_tbit_swap3(size_tx,size_tbits){
2
size_tr=0;
3
while(bits--){
4
r=r<<1|x&1;
5
x>>=1;
6
}
7
returnr;
8
}
Der einzig verbleibende Nachteil der rekursiven Variante ist also, dass
sie für einen C-Only-Programmierer nicht sofort verständlich ist ;-)
>Der einzig verbleibende Nachteil der rekursiven Variante ist also, dass>sie für einen C-Only-Programmierer nicht sofort verständlich ist ;-)
Ok, dann zeig mit doch mal den Lisp Interpreter für den AVR oder PIC :-)
und die Ausführungszeit ist auch genausoschnell wie bei der Variante von
Peter :-))))
Gruß und Spass, Udo
Merke: nicht jeder nicht-Lisp-Fan ist ein C-Only-Programmierer oder die
Crux mit der hinreichenden und notwendigen Voraussetzung :-))
Udo R. S. schrieb:
>> Der einzig verbleibende Nachteil der rekursiven Variante ist also,>> dass sie für einen C-Only-Programmierer nicht sofort verständlich ist>> ;-)>> Ok, dann zeig mit doch mal den Lisp Interpreter für den AVR oder PIC> :-) und die Ausführungszeit ist auch genausoschnell wie bei der> Variante von Peter :-))))
Ich habe ja nicht dafür plädiert, auf AVRs und PICs in LISP zu program-
mieren, sondern wollte nur aufzeigen, dass rekursive Programmierung —
richtig eingesetzt — bzgl. der von Peter genannten Kriterien nicht
schlechter als iterative Programmierung sein muss.
Ich behaupte aber auch nicht, dass sie besser ist ;-)
(nicht, dass jetzt alle Programmiereinsteiger meinen, sie dürften keine
Schleifen mehr verwenden)
Ist es möglich den Code von Peter noch zu beschleunigen?
;C: ACC:
MIRROR: MOV C, ACC.1 ;1 76543210
RLC A ;7 65432101
MOV ACC.2, C ;7 65432701
MOV C, ACC.3 ;2 65432701
RLC A ;6 54327012
MOV ACC.4, C ;6 54367012
MOV C, ACC.5 ;3 54367012
RLC A ;5 43670123
MOV ACC.6, C ;5 45670123
SWAP A ;5 01234567
RET
Martin schrieb:
> Ist es möglich den Code von Peter noch zu beschleunigen?
1
;Input: A
2
;Output: A
3
4
;1.Brute force: 6 / 8 Cycle, 259 Byte
5
MIRROR1:
6
JZ MIRR1 ;0: leave unchanged
7
MOVC A, @A+PC ;mirror 1 to 0FFh (max 255 entries in table!)
8
MIRR1:
9
RET
10
MB SET 1
11
REPT 255 ;use Keil Assembler to expand this macro
12
DB ((MB AND 1) SHL 7)+((MB AND 2) SHL 5)+((MB AND 4) SHL 3)+((MB AND 8) SHL 1)+((MB AND 10h) SHR 1)+((MB AND 20h) SHR 3)+((MB AND 40h) SHR 5)+((MB AND 80h) SHR 7)
es geht doch mit sehr viel weniger code
out porta, R16
in R16, portb
jetzt nur
PinA0 mit PinB7
PinA1 mit PinB6
PinA2 mit PinB5
PinA3 mit PinB4
PinA4 mit PinB3
PinA5 mit PinB2
PinA6 mit PinB1
PinA7 mit PinB0
verbinden und fertig.