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 !!
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.
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
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.
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.
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.
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).
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.
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.
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 )
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.
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).
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
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.
@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
PORT_D5=(Testbyte>>2)&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.
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.
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
HildeK schrieb:> Ein eigenes Beispiel hatte ich mal hier genannt:> Beitrag "Re: Attiny85 Pin als Eingang"
1
if(LED1==EIN)LED0=EIN;// auch Abfragen sind möglich
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.
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):
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
sbrsr25,0
2
rjmp.+4
3
sbi0x0b,7
4
rjmp.+2
5
cbi0x0b,7// 10 Bytes
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
sbrsr25,0
2
cbi0x0b,7
3
sbrcr25,0
4
sbi0x0b,7// 8 Bytes
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.
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
>sbrsr25,0
2
>rjmp.+4
3
>sbi0x0b,7
4
>rjmp.+2
5
>cbi0x0b,7// 10 Bytes
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
>sbrsr25,0
2
>cbi0x0b,7
3
>sbrcr25,0
4
>sbi0x0b,7// 8 Bytes
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.
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:
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
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
bit=1/bit=0
2
sbrsr25,02/1
3
cbi0x0b,70/1
4
sbrcr25,01/2
5
sbi0x0b,71/0
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.
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 :-)
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.
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.
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.
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?!
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...
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
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?
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
PORTD^=_BV(0);
nehmen und bekommt eine in/eor/out Sequenz, oder man nimmt
1
PIND=_BV(0);
und bekommt ein
1
sbi PIND, 0
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.