Hallo zusammen, ich habe Layoutbedingt 8 Ausgänge auf diversen uC Pins verteilt. Nun möchte ich aber ein Byte in der richtigen Reihenfolge auf den gemischten Ausgängen ausgeben. Gibt es dazu eine effizientere Programmierung als diese: if (Testbyte & 0b00000001) PORT_D7 = 1; else PORT_D7 = 0; if (Testbyte & 0b00000010) PORT_D6 = 1; else PORT_D6 = 0; if (Testbyte & 0b00000100) PORT_D5 = 1; else PORT_D5 = 0; if (Testbyte & 0b00001000) PORT_D3 = 1; else PORT_D3 = 0; if (Testbyte & 0b00010000) PORT_C3 = 1; else PORT_C3 = 0; if (Testbyte & 0b00100000) PORT_C2 = 1; else PORT_C2 = 0; if (Testbyte & 0b01000000) PORT_C1 = 1; else PORT_C1 = 0; if (Testbyte & 0b10000000) PORT_C0 = 1; else PORT_C0 = 0; ich frue mich auf eure Hilfe !!
Gast
#5808174
PORT_D7 = Testbyte.0 ;Bit 0 PORT_D6 = Testbyte.1 ;Bit 1 usw.
Gast
#5808184
Philipp L. schrieb: > ich habe Layoutbedingt 8 Ausgänge auf diversen uC Pins verteilt. Da wäre es doch naheliegend, das Layout etwas gerade zu ziehen, bevor man sich solche Verrenkungen in der Software einhandelt. Oder guck dir an, wie andere das machen, z.B. bei Arduino für die 4 Byte LCD Daten. https://github.com/arduino-libraries/LiquidCrystal/blob/master/src/LiquidCrystal.cpp
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
Gast
#5808185
Für die 4 Bits der jeweiligen zwei Ports könnte man jeweils eine Translation table anlegen und dann 4 Bits zugleich schreiben, statt alle Bits einzeln.
Gast
#5808186
Wolfgang schrieb: > Philipp L. schrieb: >> ich habe Layoutbedingt 8 Ausgänge auf diversen uC Pins verteilt. > > Da wäre es doch naheliegend, das Layout etwas gerade zu ziehen, bevor > man sich solche Verrenkungen in der Software einhandelt. > > Oder guck dir an, wie andere das machen, z.B. bei Arduino für die 4 Byte > LCD Daten. > https://github.com/arduino-libraries/LiquidCrystal/blob/master/src/LiquidCrystal.cpp >
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
Das ist alles, aber sicher nicht effizient.
z.B. if (Testbyte & 0b00000100) PORT_D5 = 1; else PORT_D5 = 0; wird eifacher zu PORT_D5 = (Testbyte >> 2) & 1; ev. geht auch: PORT_D5 = Testbyte & 0b00000100; das hängt aber vom compiler & und mikrocontroller ab
Gast
#5808207
Master S. schrieb: > PORT_D5 = (Testbyte >> 2) & 1; > > > ev. geht auch: > > PORT_D5 = Testbyte & 0b00000100; > das hängt aber vom compiler & und mikrocontroller ab Das ist beides wahrscheinlich nicht effizienter als die Lösung des Threadstarters. Insbesondere, wenn die CPU keinen Barrel-Shifter hat.
Lass es ganz einfach so. Wenn dir den Assembler-Code ansiehst, der sich daraus ergibt ist das wirklich nicht die Welt an Anweisungen. Und lass dir von Leuten, die dir (d)ein optimiertes Layout madig reden wollen keinen Scheiß erzählen. Die ganze Industrie optimiert Layouts und passt in der Software an.
Gast
#5808224
Die Varianten werden wohl durch den Compiler herausoptimiert, in Assembler ist alles dasselbe. Also kommt nur auf gute Lesbarkeit an. Ich würde die Einzelbit-verarbeitung bevorzugen weil: Im nächsten Projekt brauchst du bestimmte Pins wegen Sonderfunktionen. Wenn das LCD dann ein komplettes Port belegt, und nur hier und da einzelne Pins zur Verfügung stehen, fängst du schon wieder von vorne an. Besser wär, einzelne Pins zu verwenden und im h-file als #define einzugeben.
abc.def schrieb: > Besser wär, einzelne Pins zu verwenden und im h-file als #define > einzugeben. Amen!
PORT_D7 = Testbyte.0 ;Bit 0 Bring den Fehler im Anhang...
Philipp L. schrieb: > PORT_D7 = Testbyte.0 ;Bit 0 > > Bring den Fehler im Anhang... kann der Compiler das so direkt? ich wäre jetzt von einer Struct mit 8 * 1 Bit mit dem Namen 0-7 ausgegangen. Eventuell muss noch ne union mit einem uint8_t außen drauf, wenn du nicht immer jedes Bit einzeln setzen/löschen willst.
Gast
#5808309
Philipp L. schrieb: > PORT_D7 = Testbyte.0 ;Bit 0 > > Bring den Fehler im Anhang... Darfst halt nicht jeden Blödsinn glauben... Abgesehen davon ist es egal was du fabrizierst, performant wird das in keinem Fall. Nicht nur das die Bits auf zwei Ports aufgeteilt sind, sie sind auch noch unzusammenhängend und was noch schlimmer ist, in umgekehrter Reihenfolge.
> Nicht nur das die Bits auf zwei Ports aufgeteilt sind, sie > sind auch noch unzusammenhängend und was noch schlimmer ist, in > umgekehrter Reihenfolge. Das ist mir bewusst, das Layout ist aber nur geringfügig größer als das MLF-package des uC´s. Da sind die 0,15mm (Abstand+Breite) der Leiterbahn schon groß. Leiterbahnlayout war da wichtiger als die Software.
Tim T. schrieb: > Philipp L. schrieb: >> PORT_D7 = Testbyte.0 ;Bit 0 >> >> Bring den Fehler im Anhang... > > Darfst halt nicht jeden Blödsinn glauben... ist von der Idee her (ist nicht meine gewesen) nicht so schlecht, da Fehlt halt noch dass er ne Struct braucht: struct st_name{ unsigned 0:1; unsigned 1:1; ... wobei ich nicht probiert habe ob 0,1,... gültige namen sind dann noch ne union union un_name{ struct st_name abc; uint8_t abcd; }; Ohne Gewähr und ungetestet, wird zwar nicht viel verändern am ASM/Hex der rauskommt, aber wird übersichtlicher (und denke ich war so gemeint, wie gesagt nicht meine Idee, nur meine Interpretation von dieser).
Gast
#5808317
Also ich sehe bei dir so einige Defizite, da solltest du dir nich unbedingt nen Kopf um die Performance beim Bitschubsen machen, zumal der Compiler da eh aus fast allem Genannten am Ende das Gleiche zaubert.
Gast
#5808319
Naja, übersichtlicher als 8 Statements ala: PORT_D5 = (Testbyte >> 2) & 1; wirds nicht, und schneller auch nicht, eher das Gegenteil.
wenn du einige zusammenhängende Pins und Bytes hast, die nur wild umsortiert werden müssen, könntest du eine kleine Lookup Tabelle erstellen. z.b. über D5,6,7 eine 3bit, oder über D3,5,6,7 eine 5 bit und für C0-3 eine 4bit lookup 4 bit sind 16 byte flash/ram was auch immer, das wird übrig sein maskier und shifte die entsprechenden bits für C0-3: (Testbyte & 0xF0) >> 4, und das als Index für ein array als deine Lookup Tabelle, das array legst du schön in den Flash und fertig. den Wert aus dem Array/Lookuptabelle veroderst du dann mit Port_C also Port_C = (Port_C & 0xf0) | Lookup_wert das & 0xf0 um C0-3 zu löschen, dass | um die neuen zu setzen, wenn du C4-7 nicht beeinflussen willst. die Frage ist halt auch welcher µC und ob z.b. die Ausgänge anders getaktet sind als der Core, dann wäre es eventuell gut möglichst wenig Zugriffe auf die Pins zu haben, und wie schnell/gleichzeitig die gesetzt werden müssen und worauf hin du optimierst.
Gast
#5808371
Master S. schrieb: > ev. geht auch: > > PORT_D5 = Testbyte & 0b00000100; > das hängt aber vom compiler & und mikrocontroller ab Wie?
Gast
#5808456
Normalerweise mache ich das so:
Am Anfang:
#define bitSet(a,b) (a |= (1<<b))
#define bitClear(a,b) (a &= ~(1 << b))
#define bitClr(a,b) (a &= ~(1 << b))
#define bitTest(a,b) (a & (1 << b))
#define true (0==0)
#define false (0!=0)
// display.h
// segment a
#define dispaOn bitClear(PORTB,2)
#define dispaOff bitSet (PORTB,2)
#define dispaDDR bitSet ( DDRB,2)
damit ist die Zuordnung von Signal zu Pin an einer eindeutigen Stelle
getroffen, und später kann bei Bedarf auch noch in low-aktiv oder
high-aktiv getauscht werden.
Vielleicht würde dir das hier helfen:
#define bitTransfer(a,b,c,d) if(bit( c , d )){bitSet( a , b
);}else{bitClear( a , b );}
Du gibst deine Signale nicht auf PORT aus, sondern byteweise in
Variablen. Von dort aus über bitTransfer zu den realen Ausgängen, die
aber auch beliebig verteilt sein können. Je nach Erfordernis beim
Routing oder wegen µC-Sonderfunktionen.
Generell ist es für mich lesbarer, wenn da steht:
bitSet (PORTB,2);
oder
if (bitTest(PINC,1)) { /* tuwas */ }
als wie ein Geschwurbel von << und !~
Warum macht man das Geschwurbel eigentlich? Finde ich überall.
( Das ist eine ernstgemeinte Frage an die Community )
Gast
#5808458
Weil der Shift-Operator zum Sprachumfang von C gehört, die bitSet-Funktion/Makro nicht. Und wer mit ner einfachen Verschiebung samt Bitmaskierung schon Probleme hat, macht irgendwas falsch.
Gast
#5808532
Es gibt hier gefühlt wöchentlich einen Thread, wo ein Anfänger nicht damit zurechtkommt. Muß man die Anfänger vergraulen? Gehört der uint16_t zum Sprachumfang von C? Ich brauche ein #include dafür. Also muß ich mit dem int weiterwursteln, das auf jeder Plattform eine andere Länge hat. Ja, ich habe manchmal Probleme mit C. Ich mache hobbymäßig 1 Projekt pro Jahr, und das auch abends zwischen 20:00 und 23:00 . Da bin ich nicht mehr so fit, und es ist mir lieber, wenns übersichtlich wär. Eine Tabelle aus BitSet kann ich da noch eher verstehen. Mit einer LookUp table, geschrieben vor 5 Jahren, die einer kleinen Änderung bedarf, wird es schon schwerer. Mache ich da etwas falsch, oder wie kann ich das besser machen? Wenn ich es nerdig wollte, würde ich Z80 Assembler nehmen (nicht AVR, der ist nur grottig).
Gast
#5808543
abc.def schrieb: > Gehört der uint16_t zum Sprachumfang von C? Ich brauche ein #include > dafür. Ja. Du brauchst auch für Funktionen aus der Standardbibliothek ein #include. abc.def schrieb: > Also muß ich mit dem int weiterwursteln, das auf jeder Plattform > eine andere Länge hat. Quatsch
Gast
#5808554
abc.def schrieb: > ... 1)) { /* tuwas */ } Ja. Bei so hochkonzentrierten Arbeiten muß man auch mal infantil sein dürfen. Keine Ahnung wie oft ich so etwas schon im Forum gelesen habe. Man kann aber auch zB. "Aktion" schreiben. Das klingt dann nicht so ausgefallen. Ist aber nur meine Meinung.
Gast
#5808560
@TO Mach es so wie von Thomas vorgeschlagen - laß es wie es ist. Eine kleine Optimierung wäre bei Deinem Code schon drin. Setze erst mal alle Ports auf 0 dann fällt schon mal der else Zweig weg (machst Du ja in DEinem 2. Codeansatz so), oder mach es so wie von Tim vorgeschlagen:
1 | |
Dann werden die Ports entsprechend dem Ergebnis der logischen Operation gesetzt. Wenn alle Ports gleichzeitig schalten sollen, dann kommst Du nicht um einen Puffer (IC) herum, aber dann kannst Du auch gleich ein neues Layout machen und alle Ausgänge auf einenPort legen.
Gast
#5808567
abc.def schrieb: > Es gibt hier gefühlt wöchentlich einen Thread, wo ein Anfänger nicht > damit zurechtkommt. Muß man die Anfänger vergraulen? Fällt dir nicht auch auf das sich bei den Anfängern was verändert hat? Früher war die Erwartungshaltung eine Andere, da hat man sich noch wirklich mit der Materie auseinander gesetzt und wenn mans dann immer noch nicht hin bekam eventuell auch gelassen. Heute wird wegen wirklich jedem Furz nachgefragt, aber immer nur für die aktuelle Problemestellung, bloß nicht an sich selbst arbeiten, könnte ja in Arbeit ausarten. Arduino und co haben ihr übriges dazu getan das jeder der ne LED irgendwie zum blinken bekommen hat, danach meint ein Spaceshuttle zu bauen. Mit den Grundlagen anfangen, warum, er hat ja schon ne Led blinken lassen, das hat er nicht nötig... > Gehört der uint16_t zum Sprachumfang von C? Ich brauche ein #include > dafür. Also muß ich mit dem int weiterwursteln, das auf jeder Plattform > eine andere Länge hat. Das empfinde ich auch als eine der größten Unzulänglichkeiten von C. Aber es hält dich auch keiner davon ab festzustellen wie groß ein short auf deiner Zielplattform ist und den dann benutzen. > Ja, ich habe manchmal Probleme mit C. Ich mache hobbymäßig 1 Projekt pro > Jahr, und das auch abends zwischen 20:00 und 23:00 . Da bin ich nicht > mehr so fit, und es ist mir lieber, wenns übersichtlich wär. Eine > Tabelle aus BitSet kann ich da noch eher verstehen. Mit einer LookUp > table, geschrieben vor 5 Jahren, die einer kleinen Änderung bedarf, wird > es schon schwerer. > Mache ich da etwas falsch, oder wie kann ich das besser machen? Das ist eben deine Sichtweise, für mich gehört der Shift und das Bitweise Und genauso zum Programm wie die geschweiften Klammern um einen Funktionsblock. Wirklich aktiv wahr nehm ich die nicht mehr. > Wenn ich es nerdig wollte, würde ich Z80 Assembler nehmen (nicht AVR, > der ist nur grottig). Also ich hab mit dem AVR Assembler überhaupt keine Probleme, benutz den aber auch nicht mehr sonderlich oft weil C selbst auf den kleinen Tinys das macht was ich will. Nur wenns mal wirklich ein exaktes Timing braucht wo ich keine Takte zu verschenken habe, oder ich irgendwelche schweinereien mache die man so nicht tun sollte (z.B. Missbrauch von ISR mit verändertem Rücksprungziel) hol ich den Assembler raus.
Zeno schrieb: > Setze erst mal alle Ports auf 0 dann fällt schon mal der else Zweig weg Sicher. Auch wenn sich ein bestimmtes bit in Testbyte nicht ändert, bzw. dauernd 1 ist, wird am entsprechendem PortPin munter gewackelt... P.S. 8 Abfragen, 8 rjmps und 8 Mal setzen oder rücksetzen ist auf jeden Fall dabei, ein guter Compiler macht das ohne Probleme und (fast) immer auf dieselbe Art und Weise, egal wie du die Abfrage in C schreibst.
Gast
#5808604
Zum umordnen von bits kann evtl. auch dieses schöne GCC built-in praktisch sein: https://gcc.gnu.org/onlinedocs/gcc-7.2.0/gcc/AVR-Built-in-Functions.html#AVR-Built-in-Functions
1 | |
2 | |
3 | |
Der generierte Code ist nicht zwingend minimal (verwendet bst/bld Instruktionen), aber man bekommt einen relativ gut lesbaren C-Code ohne unendliche if-else und mask-shift Sequenzen.
Markus schrieb: > Instruktionen), aber man bekommt einen relativ gut lesbaren C-Code ohne > unendliche if-else und mask-shift Sequenzen. Auch deswegen gibt es funktionen wo man solch verwurschtelten Code ablegen und dokumentieren kann, ohne dass die main() Bettlakenlänge erreicht.
Hallo zusammen,
ein anderer Ansatz wäre einen Ports auf Variablen zu spiegeln:
static volatile uint8_t outRegister;
isr timerX_ovf_vect{
// suche bit auf Vektor und schreibe asoziierten Ausgang
}
int main(void){
// nutze outRegister wie ein Port Register
}
Das funktioniert, wenn die Ausgaben Zeit unktitisch sind und der TimerX
schnell genug ist.
VG
Jörg
Gast
#5808718
Machen wir jetzt einen Wettbewerb um die unsinnigste Variante zu finden das miese Design noch mit dem schlechtesten Code zu verschlimmbessern?
Wenn es unbedingt schneller sein soll, mach dir eine Lookup-Table.
Gast
#5808769
abc.def schrieb: > Warum macht man das Geschwurbel eigentlich? Finde ich überall. > ( Das ist eine ernstgemeinte Frage an die Community ) Man muss es nicht machen. Im Forum gibt es von Peter D. die Datei sbit.h. Hier z.B.: Beitrag "Re: Frage zu Struktur für IO-Port bei AVRs" bzw. avrfreaks.net: https://www.avrfreaks.net/comment/711155#comment-711155 Ähnlich zu deinem Vorschlag wird dort dieses "Geschwurbel" dann sehr viel freundlicher in der Anwendung. Ein eigenes Beispiel hatte ich mal hier genannt: Beitrag "Re: Attiny85 Pin als Eingang"
HildeK schrieb: > Ein eigenes Beispiel hatte ich mal hier genannt: > Beitrag "Re: Attiny85 Pin als Eingang"
1 | |
Das ist genau dieselbe Abfrage die der TO hat. Und wenn man else dazuschreibt (was man sowieso muss), wird es auch genauso übersetzt. Und dass man anstatt 0b00000001 Pin_D7 und anstatt 0b10000000 Pin_C0 (oder Taster_1) definieren (und schreiben) kann ist auch klar. Philipp L. schrieb: > Gibt es dazu eine effizientere Programmierung als diese: Nein. Als Erstes: Es ist überhaupt nicht unübersichtlich und unverständlich. Als Zweites: Es ist am effizientestem und wird vom Compiler zu kürzestem Code übersetzt.
Gast
#5808993
Hab es mal zum Spaß zusammengebaut, alle Varianten bis auf die LUT landen bei einer SBRS, RJMP, SBI, RJMP, CBI Kette und brauchen 42 Takte, die mit 2 LUT braucht 25 Takte und auch minimal weniger Flash (6 Byte):
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | |
43 | |
44 | |
45 | |
46 | |
47 | |
48 | |
49 | |
50 | |
51 | |
Trotzdem würde ich eher die 1. Variante nehmen, da die 2. bei asynchronen Änderungen der übrigen Pins von Port C und D nicht sicher ist.
PortD:=(PinD and %11111011) or ((Testbyte and %00000001) SHL 2); Bit2 ist das zu setzende/löschende Bit. Das SHL um das Bit dem richtigen Bit des Ports zuzuordnen. If ... then dauert doch relativ lange. ..... ich liebe Pascal :-)
Tim T. schrieb: > Hab es mal zum Spaß zusammengebaut, alle Varianten bis auf die LUT > landen bei einer SBRS, RJMP, SBI, RJMP, CBI Kette und brauchen 42 Takte, > die mit 2 LUT braucht 25 Takte und auch minimal weniger Flash (6 Byte): Ja, aber nur weil der Compiler das ziemlich schlecht optimiert hat... if...then Variante wird 8 Mal zu folgenden Code übersetzt:
1 | |
2 | |
3 | |
4 | |
5 | |
Das sind 8*10 Bytes = 80 Bytes. + 2(mov am Start) + 2(rjmp am ende) ergibt 84 Bytes. Ergibt 8*5 Takte bei setzen und 8*4 Takte bei rücksetzen des bits. Mit besserer Optimierung könnte das zu folgendem Code werden:
1 | |
2 | |
3 | |
4 | |
Das sind 8*8 Bytes = 64 Bytes. + 2(mov am Start) + 2(rjmp am ende) ergibt 68 Bytes. Und ergibt immer 8*4 Takte = 32 Takte. Dass die lut Tabellen kompliziert und auch kompliziert zu ändern sind, ist wohl klar. Tim T. schrieb: > Trotzdem würde ich eher die 1. Variante nehmen, da die 2. bei > asynchronen Änderungen der übrigen Pins von Port C und D nicht sicher > ist. Genau. Bei der if..then Variante können sich die übrigen Pins beliebig ändern. Zeitunterschied zwischen PORTD.7 und PORTC.0 beträgt max. 7*4 Takte = 28 Takte oder 1.75us bei 16MHz, falls das in diesem Fall relevant sein sollte.
Gast
#5809214
Marc V. schrieb: > Tim T. schrieb: >> Hab es mal zum Spaß zusammengebaut, alle Varianten bis auf die LUT >> landen bei einer SBRS, RJMP, SBI, RJMP, CBI Kette und brauchen 42 Takte, >> die mit 2 LUT braucht 25 Takte und auch minimal weniger Flash (6 Byte): > > Ja, aber nur weil der Compiler das ziemlich schlecht optimiert hat... > if...then Variante wird 8 Mal zu folgenden Code übersetzt: >
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
> Das sind 8*10 Bytes = 80 Bytes. > + 2(mov am Start) + 2(rjmp am ende) ergibt 84 Bytes. > Ergibt 8*5 Takte bei setzen und 8*4 Takte bei rücksetzen des bits. > Mit besserer Optimierung könnte das zu folgendem Code werden: >
1 | |
2 | |
3 | |
4 | |
5 | |
> Das sind 8*8 Bytes = 64 Bytes. > + 2(mov am Start) + 2(rjmp am ende) ergibt 68 Bytes. > Und ergibt immer 8*4 Takte = 32 Takte. Hmm, ich komm da auf andere Werte: Angenommen das Bit ist gesetzt, dann braucht sbrs 2 Takte, das cbi wird übersprungen, also 0 Takte, sbrc überspringt nicht, also 1 Takt und das sbi hat 2 Takte, macht bei mir in Summe 5 Takte, bei 8 Bits also 8 * 5 = 40 Takte (Andersrum sinds natürlich auch 40 Takte). Wenn ich dann noch das mov am Anfang und den rjmp mitrechne, bin ich bei 43 Takten. > Dass die lut Tabellen kompliziert und auch kompliziert zu ändern sind, > ist wohl klar. Jop, hatte nur mal bock es zu machen. > Tim T. schrieb: >> Trotzdem würde ich eher die 1. Variante nehmen, da die 2. bei >> asynchronen Änderungen der übrigen Pins von Port C und D nicht sicher >> ist. > > Genau. > Bei der if..then Variante können sich die übrigen Pins beliebig ändern. > Zeitunterschied zwischen PORTD.7 und PORTC.0 beträgt max. > 7*4 Takte = 28 Takte oder 1.75us bei 16MHz, falls das in diesem Fall > relevant sein sollte. Nicht ganz (s.o.) aber vom Prinzip her richtig.
Gast
#5809230
Mit __builtin_avr_insert_bits ist es IMHO gut lesbar und braucht nur 20 Takte. PORTC/D lassen sich auch gut relativ synchron zuweisen (einfach statt direkter Zuweisung in temp. variable speichern) avr-gcc -mmcu=attiny88 -O3 -Wall -Wextra -c -o foo.o foo.c:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
avr-objdump -d foo.o:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
Insgesamt 42 Byte Flash.
Gast
#5809231
Hi
>...bin ich bei 43 Takten.
Mit acht mal
bst Rd,b
bld Rd,b
bin ich bei 16 Takten. Dazu noch ein out/sts mit 1/2 Takten ist man bei
15/16 Takten.
MfG Spess
Gast
#5809236
Hi Korrektur: Dazu noch ein out/sts mit 1/2 Takten ist man bei 17/18 Takten. MfG Spess
Gast
#5809255
Na und? ICH würde mich an hand-optimiertem ASM-Code erfreuen, aber ist das nötig? Entweder kann man sich "umständlich" leisten, dann darf jedes Bit einzeln in grenzwertig schlechter Hochsprachen-Syntax abgehandelt werden, oder es wird knapp, dann muss es "richtig optimiert" worst case in ? µs erledigt sein. Schau doch erst mal ganz gelassen, ob "umständlich" nicht schnell genug ist.
Tim T. schrieb: > Angenommen das Bit ist gesetzt, dann braucht sbrs 2 Takte, das cbi wird > übersprungen, also 0 Takte, sbrc überspringt nicht, also 1 Takt und das > sbi hat 2 Takte, macht bei mir in Summe 5 Takte, bei 8 Bits also 8 * 5 = > 40 Takte (Andersrum sinds natürlich auch 40 Takte). Wenn ich dann noch > das mov am Anfang und den rjmp mitrechne, bin ich bei 43 Takten. Du rechnest falsch.
1 | |
2 | |
3 | |
4 | |
5 | |
spess53 schrieb: > Dazu noch ein out/sts mit 1/2 Takten ist man bei > 17/18 Takten. 2 * 10 Takte = 20 Takte + 2(mov) + 2(rjmp) = 24 Takte Und das Problem mit asynchronen Änderungen der übrigen Pins bleibt bestehen. Die ganze Diskussion ist aber umsonst. Die Variante mit if..else ist übersichtlich und schnell genug, alles andere ist entweder komplizierter, länger oder langsamer.
Gast
#5809259
Jacko schrieb: > Na und? > ICH würde mich an hand-optimiertem ASM-Code erfreuen, aber ist > das nötig? > > Entweder kann man sich "umständlich" leisten, dann darf jedes > Bit einzeln in grenzwertig schlechter Hochsprachen-Syntax > abgehandelt werden, oder es wird knapp, dann muss es "richtig > optimiert" worst case in ? µs erledigt sein. > > Schau doch erst mal ganz gelassen, ob "umständlich" nicht > schnell genug ist. Also ich finde ja, dass zwei Zeilen C mit builtin sehr gut lesbar sind. Wird in diesem Fall sehr wahrscheinlich nichts effizienteres geben. Man muss halt mal die Dokumentation zur Toolchain gelesen haben (RTFM...), damit man so was findet :-)
Gast
#5809282
Sbi und cbi sind 2 Takt Instruktionen, komisch, ist aber so...
1 | |
2 | |
3 | |
4 | |
5 | |
Tim T. schrieb: > Sbi und cbi sind 2 Takt Instruktionen, komisch So komisch ist das nicht, es wird intern read-modify-write gemacht. Ein OUT ist dagegen nur ein write.
Gast
#5809571
Peter D. schrieb: > Tim T. schrieb: >> Sbi und cbi sind 2 Takt Instruktionen, komisch > > So komisch ist das nicht, es wird intern read-modify-write gemacht. Und genau das finde ich ja komisch, warum sind die Bits nicht in einzeln beschreibbaren FF? > Ein OUT ist dagegen nur ein write. Das ist auch klar.
Gast
#5809573
Marc V. schrieb: > Zeno schrieb: >> Setze erst mal alle Ports auf 0 dann fällt schon mal der else Zweig weg > > Sicher. > Auch wenn sich ein bestimmtes bit in Testbyte nicht ändert, bzw. > dauernd 1 ist, wird am entsprechendem PortPin munter gewackelt... Er hatte einen zweiten Ansatz gepostet, wo er vor jedem if auf Null setzt -warum auch immer. DAs hatte ich als Basis für meinen Post genommen. Besser ist natürlich der Ansatz von Tim, da spart man sich if Gewurschtel und die Ports wackeln nur wenn sie wackeln sollen.
Es wird vermutlich nicht viel besser gehen, aber es gibt noch ne Lösung mit einer LookUpTable. 2 x 256 Byte, eins für Port C und eins für Port D. Wenn du noch genügend Flash übrig hast. Ich hatte mal das Problem, aber da waren die Bits innerhalb eines Ports verdreht. Da ging das sehr gut und es war nichtmal maskieren nötig. Das müsstes du hier allerding machen wenn die anderen Bits der Ports noch anderweitig in Verwendung sind.
Gast
#5809591
Tim T. schrieb: > Peter D. schrieb: >> Tim T. schrieb: >>> Sbi und cbi sind 2 Takt Instruktionen, komisch >> >> So komisch ist das nicht, es wird intern read-modify-write gemacht. > > Und genau das finde ich ja komisch, warum sind die Bits nicht in einzeln > beschreibbaren FF? Ja, manchmal sollte man eventuell mal nen Moment länger drüber Nachdenken, dann wäre mir direkt aufgefallen das so eine Schaltung natürlich aufwändiger ist und mehr Platz im Chip braucht. Ich gehe mal davon aus das ein SBI intern nur den Port mit einem Register verODERt worin das entsprechende Bit gesetzt ist und ein CBI es mit einem invertiert gesetztem Register verUNDet?!
Gast
#5809594
Rangi J. schrieb: > Es wird vermutlich nicht viel besser gehen, aber es gibt noch ne Lösung > mit einer LookUpTable. 2 x 256 Byte, eins für Port C und eins für Port > D. Wenn du noch genügend Flash übrig hast. > Ich hatte mal das Problem, aber da waren die Bits innerhalb eines Ports > verdreht. Da ging das sehr gut und es war nichtmal maskieren nötig. Das > müsstes du hier allerding machen wenn die anderen Bits der Ports noch > anderweitig in Verwendung sind. Die LUT müssen garnicht so groß sein, 2*16 Byte reichen und diese Lösung steht auch schon etwas weiter oben, ist aber langsamer als das GCC __builtin_avr_insert_bits bzw. die Bitstore/Load Geschichte...
Gast
#5809736
Tim T. schrieb: > Und genau das finde ich ja komisch, warum sind die Bits nicht in einzeln > beschreibbaren FF? Weil du dir den falschen Prozessor ausgesucht hast - die meisten haben keine 1-Bit-Ports, sondern nur 8bit oder mehr. Ausnahme sind z.B. 8051-Derivate. Wenn es dir zu viel Mühe ist oder du es nicht hinkriegst die Bits entsprechend zusammenzusetzen musst du eben den Prozessor wechseln. Georg
Gast
#5809745
georg schrieb: > Tim T. schrieb: >> Und genau das finde ich ja komisch, warum sind die Bits nicht in einzeln >> beschreibbaren FF? > > Weil du dir den falschen Prozessor ausgesucht hast - die meisten haben > keine 1-Bit-Ports, sondern nur 8bit oder mehr. Ausnahme sind z.B. > 8051-Derivate. Wenn es dir zu viel Mühe ist oder du es nicht hinkriegst > die Bits entsprechend zusammenzusetzen musst du eben den Prozessor > wechseln. > > Georg Oh Mann, immer wieder erstaunlich wie partiell manche Leute Informationen verarbeiten. Ist es echt so ungewöhnlich mal den ganzen verdammten Thread zu lesen bevor man seinen Senf dazu senftet?
Gast
#5809773
Peter D. schrieb: > Tim T. schrieb: >> Sbi und cbi sind 2 Takt Instruktionen, komisch > > So komisch ist das nicht, es wird intern read-modify-write gemacht. > Ein OUT ist dagegen nur ein write. So einfach ist das nicht, denn sbi/cbi verhalten sich äußerlich bei mittlerweile nicht mehr ganz so neuen AVRs (~neuer als ATmega8) nicht immer wie RMW. Intern ist es evtl. RMW, aber das Verhalten passt nicht dazu. Wer z.B. einen Ausgang togglen möchte, kann
1 | |
nehmen und bekommt eine in/eor/out Sequenz, oder man nimmt
1 | |
und bekommt ein
1 | |
Dadurch wird nur das PIND0 bit getoggelt. Würden sbi/cbi einen "normalen" RMW ausführen und andere bits in PIND wären 1, dann würden die ebenfalls getoggelt. Der Spezialfall hier ist also, dass die PINx Register in der Lesephase durch sbi/cbi immer 0 zurückgegeben. sbi/cbi selbst machen also evtl. tatsächlich RMW, aber es sieht nicht bei allen Registern so aus.
Gast
#5809780
Markus schrieb: >
1 | |
gemeint war natürlich
1 | |
und es geht natürlich nur mit sbi, nicht cbi.
Ich danke euch.
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.
