Nabend, Wie bekomme ich es hin, mit einem Makro z.B an Adresse 0x32 ( PORTD - mega32 ) zu schreiben?
Naj H. schrieb: > Nabend, > > Wie bekomme ich es hin, mit einem Makro z.B an Adresse 0x32 ( PORTD - > mega32 ) zu schreiben? Da fehlt Kontext. Auf den Port schreibt man mit:
1 | |
warum sollte es mit einem Macro anders sein?
Gast
#6020666
Dafür braucht man doch kein Makro! PORTD = value;
Stefanus F. schrieb: > Dafür braucht man doch kein Makro! > > PORTD = value; Ist mir soweit bewusst. Folgendes.. Ich habe eine Struktur.. In der habe ich mehrere IO Adresse drin. Von unterschiedlichen Ports.. Ich möchte mit einem Makro auf diese Adressen schreiben. z.B
1 | |
2 | |
Das mit dem Zeiger deklarieren würde ich gerne schicker durch ein Makro verpacken..
Gast
#6020682
z.B. wenn unsigned char ein geeigneter Typ für "Port-D" ist und die Adresse les und schreibbar ist:
1 | |
2 | |
3 | |
4 | |
5 | |
meist will man aber noch mehr mit einem Port machen, wie Bit-Zugriff etc. Wenn nur lesend, dann z.B.
1 | |
da Ports meist wirkliche IO beeinhalten, die sich ändert, d.h. jeder schreib-LeseZugriff durchgeführt werden sollte, mit volatile:
1 | |
2 | |
Gast
#6020690
wenn nur schreibend, dann verhindern, dass der Ausdruck so wie er da steht irgendwo zugewiesen werden kann, im einfachsten Fall einen dummy Block davor.
1 | |
Damit fallen aber all jene auf die Schnautze, die einzelne Statements nach if etc. nicht klammern. Darum selber noch if dabei, dann ist das egal
1 | |
Das liest zwar immer noch, wenn man einfach nur PORTD; schreibt, aber eine Zuweisung "x=PORTD" ist nicht möglich.
Gast
#6020693
In einem konkreten System gibt es aber in aller Regel - header files, die genau diese defines in optimaler Form beeinhalten - spezielle C-Compiler Konstruke wie __io oder @0x32 etc.
A. S. schrieb: >
1 | |
2 | |
3 | |
Seit wann können Preprocessor-Macros Overlaoding?
Gast
#6020702
Carl D. schrieb: > Seit wann können Preprocessor-Macros Overlaoding? A. S. schrieb: > Wenn ich kenne seinen PORTD nicht. Er muss sich für eine Variante entscheiden, egal ob von hier oder mitgeliefert. Wenn er mehrere haben will, steht es im frei, beliebig viele mit unterschiedlichen Namen zu nutzen, nur gäbe das für mich selten Sinn.
Ich wollt es eigentlich so haben.. Makro(Adresse) = Wert;
Gast
#6020708
Naj H. schrieb: > uint8_t *ptr = (uint8_t*)0x32; // PORTD > Das mit dem Zeiger deklarieren würde ich gerne schicker durch ein Makro > verpacken.. Meinst du so etwas?: #define PORT(addresse) ((uint8_t*)adresse) uint8_t *ptr = PORT(0x32)
Gast
#6020829
Naj H. schrieb: > Ich wollt es eigentlich so haben.. > Makro(Adresse) = Wert;
1 | |
2 | |
3 | |
4 | |
5 | |
Das wäre aber relativ obskur. Was machst Du damit?
Beitrag #6021005 wurde von einem Moderator gelöscht.
A. S. schrieb: > Naj H. schrieb: >> Ich wollt es eigentlich so haben.. >> Makro(Adresse) = Wert; > >
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
> Das wäre aber relativ obskur. Was machst Du damit?
Genau das habe ich gesucht.
Habe dazu noch eine Frage..
Wenn ich jetzt1 | |
Verwende merkt der Compiler folgendes an:
1 | |
Wieso? Wenn ich es wie folgt verwende, kommt keine Warnung..
1 | |
Gast
#6021431
Stefanus F. schrieb: > Dafür braucht man doch kein Makro! > > PORTD = value; ... und Milch kommt aus dem Tetrapack. Könnte es sein, dass sich hinter PORTD ein Makro verbirgt?
Naj H. schrieb: > cast to pointer from integer of different size Weil 0x32 nur ein byte ist, und kein integer in der Große eines Pointers. Also, die Adresse zuerst auf unsigned int casten:
1 | |
Eric B. schrieb: > Naj H. schrieb: >> cast to pointer from integer of different size > > Weil 0x32 nur ein byte ist, und kein integer in der Große eines > Pointers. > > Also, die Adresse zuerst auf unsigned int casten: >
1 | |
2 | |
3 | |
Warum klappt es dann wenn ich die Adresse + 0 rechne?
Gast
#6021514
Naj H. schrieb: > Warum klappt es dann wenn ich die Adresse + 0 rechne? Weil brainfuck_hater schrieb: > Könnte es sein, dass sich hinter PORTD ein Makro verbirgt? Recht hat.du musst einen echten Aufruf Posten, und dabei das Argument von IOTAB_PORT mit angeben. Also wenn es keine Zahl ist, dann wie es definiert ist.
Gast
#6021515
Naj H. schrieb: > Warum klappt es dann wenn ich die Adresse + 0 rechne? Weil brainfuck_hater schrieb: > Könnte es sein, dass sich hinter PORTD ein Makro verbirgt? Recht hat.du musst einen echten Aufruf Posten, und dabei das Argument von IOTAB_PORT mit angeben. Also wenn es keine Zahl ist, dann wie es definiert ist. Naj H. schrieb: > Genau das habe ich gesucht. Aber wohl kaum gewollt.
Naj H. schrieb: > Warum klappt es dann wenn ich die Adresse + 0 rechne? weil durch den Additionsoperator die operanden nach int promoted werden und damit auch das resultat int ist. und ein int ist in diesem Fall genauso groß wie ein pointer (16bit) Für genau solche zwecke gibt es eigentlich den Typ intptr_t
Gast
#6021588
Naj H. schrieb: > Wenn ich jetzt > > #define IOTAB_PORT( ADDRx ) (*((volatile uint8_t*)(ADDRx))) > > Verwende merkt der Compiler folgendes an: > cast to pointer from integer of different size > > Wieso? Wenn ich es wie folgt verwende, kommt keine Warnung.. > > #define IOTAB_PORT( ADDRx ) (*((volatile uint8_t*) (ADDRx+0))) Compiler und Version? Und ist das wirklich der echte Code? Eric B. schrieb: > Weil 0x32 nur ein byte ist, und kein integer in der Große eines > Pointers. Nein, das ist nicht richtig. 0x32 ist ein Integer-Literal ohne Suffix. Daher bekommt es als Typ den ersten Typ aus der Liste [int, long int], in den es reinpasst, und das wäre hier 'int'. Wie groß 'int' ist, hängt vom Compiler ab... Eric B. schrieb: > Also, die Adresse zuerst auf unsigned int casten: Nein, das ist genau so falsch. Es gibt kein Garantie, dass in ein 'unsigned int' ein Pointer reinpasst. Dafür gibt es die beiden Typen 'intptr_t' und 'uintptr_t'. In diese passt ein Pointer garantiert rein. Hier sollte man also zweckmäßigerweise auf intptr_t casten, bevor man in einen Pointer castet. Also:
1 | |
Gast
#6021616
Vlad T. schrieb: >> Warum klappt es dann wenn ich die Adresse + 0 rechne? > > weil durch den Additionsoperator die operanden nach int promoted werden Nein. Wir wissen nicht, was die "Adresse" ist. 0x32 ist nur vermutet. Vermutlich ist es ein Pointer auf einen Integer. Das +0 wirkt dann als dereferenzierung. Spekulationen macht aber keinen Sinn, solange der Up den Code nicht postet.
A. S. schrieb: > Nein. Wir wissen nicht, was die "Adresse" ist. 0x32 ist nur vermutet. > Vermutlich ist es ein Pointer auf einen Integer. Das +0 wirkt dann als > dereferenzierung. Nein. Das + bewirkt wie bereits erklärt eine Intergerpromotion, deshalb geht die Warnung weg. Dereferenzierung ist was ganz anderes (andere Baustelle) und geschieht mit einem Sternchen (im vorliegenden Fall das Sternchen ganz links) oder man könnte es auch mit eckigen Klammern dereferenzieren: #define IOTAB_PORT(ADDRx) ((volatile uint8_t*)((intptr_t)(ADDRx)))[0] Das ist ein Syntaxzucker der hier aber eher deplaziert wirken würde und besser an anderer Stelle glänzt, den benutzt man eher wenn man mit Arrays arbeitet und Pointeraddition und anschließendes Dereferenzieren (also der Zugriff auf das n-te Arrayelement) in einem Schritt kompakt hinschreiben will.
Gast
#6021814
Bernd K. schrieb: > Das + bewirkt wie bereits erklärt eine Intergerpromotion, Wenn Du das Argument kennst. Wir kennen es nicht. Es gibt keinen Code dazu vom TO, nur "ja, genau so was" und die Erkenntnis, dass er etwas (für einen Anfänger) komisches vor hat.
A. S. schrieb: > Wenn Du das Argument kennst. Wir kennen es nicht. Es gibt keinen Code > dazu vom TO, nur "ja, genau so was" und die Erkenntnis, dass er etwas > (für einen Anfänger) komisches vor hat. Jetzt hör auf zu lamentieren. Das ist aus der Fehlermeldung ganz klar zu erkennen. Naj H. schrieb: > cast to pointer from integer of different size "from integer" heißt, er hat einen Integer-Literal oder eine Integer Variable an der entsprechenden Stelle. "of different size" sagt, dass es != 16bit war. Ist unerheblich ob er ein Literal, was der Compiler als 8bit-wert behandelt hat, oder eine Variable mit 8bit Typ, übergeben hat. Der Fehler ist derselbe und ziemlich eindeutig. Ich glaube, es lehnt sich keiner zu weit aus dem Fenster, wenn man annimmt, dass er keine 32 oder 64bit Zahl/Variable übergeben hat. Zumal es dann weitere Fehler gehagelt hätte.
Gast
#6022241
Naj H. schrieb: > Ich habe eine Struktur.. In der habe ich mehrere IO Adresse > drin. Von unterschiedlichen Ports.. Und warum speicherst du die Adresse da als int und nicht direkt als volatile uint8_t*?
Zombie schrieb: > Naj H. schrieb: >> Ich habe eine Struktur.. In der habe ich mehrere IO Adresse >> drin. Von unterschiedlichen Ports.. > > Und warum speicherst du die Adresse da als int und nicht direkt als > volatile uint8_t*? Ich wollte wissen was jetzt im Endeffekt mehr Speicher benötigt.
Naj H. schrieb: > Ich wollte wissen was jetzt im Endeffekt mehr Speicher benötigt. Man kann ein Byte sparen, indem man nur das Low-Byte der Adresse speichert. Beim ATmega2561 geht das aber in die Hose, da liegen Port H, J, K und L über 0x0100.
Gast
#6022435
Naj H. schrieb: > Zombie schrieb: >> Naj H. schrieb: >>> Ich habe eine Struktur.. In der habe ich mehrere IO Adresse >>> drin. Von unterschiedlichen Ports.. >> >> Und warum speicherst du die Adresse da als int und nicht direkt als >> volatile uint8_t*? > > Ich wollte wissen was jetzt im Endeffekt mehr Speicher benötigt. Naja. Aber wenn Du n Adressen unterscheiden willst, dann muss die entsprechende Variable mindestens n verschiedene Werte annehmen können. Das wiederrum heisst, dass die Variable mindestens log2(n) Bits haben muss. Es spielt dabei überhaupt keine Rolle, ob das Bitmuster nun als Zeiger interpretiert wird oder als Integer. Der Informationsgehalt muss immer derselbe sein. Also auch die Anzahl der Bits. Ein anderes Beispiel: Wenn Du k verschiedene Zeichen unterscheiden können willst (also etwa 'A'-'Z', 'a'-'z', '0'-'9' und die Satzzeichen, also etwa den ASCII-Zeichensatz), dann sind das 128 verschiedene Zeichen. Um die als Bitmuster darstellen zu können, brauchst Du log2(128) = 7 Bits. Es ist völlig egal, ob Du diese Zeichen mit Ihrer Ordngungszahl (z.B. 0x31 = '1') oder als Zeichenliteral '1' hinschreibst. Das sind nur verschiedene Interpretationen des Bitmusters. Der Informationsgehalt, die Menge an Information, muss immer die selbe blieben.
Also macht es jetzt kein Unterschied ob ich das mit dem Marko mache oder direkt in der Struktur mit einem Zeiger?
Gast
#6022474
Naj H. schrieb: > Also macht es jetzt kein Unterschied ob ich das mit dem Marko mache oder > direkt in der Struktur mit einem Zeiger? Nun, es macht in jedem Fall keinen Unterschied in Bezug auf den dafür nötigen Speicher. Überhaupt machen Makros in nur einer Hinsicht einen Unterschied. Nämlich in der Lesbarkeit und Wartbarkeit von Code. Makros sind ja "einfach nur" Textersatz. Falls Du aber ein Verfahren ausdenkst, mit dem Speicher gespart wird - mal abgesehen von diesem Fall, in dem das offenbar nicht möglich ist -, dann spielt es keine Rolle ob Du dafür Makros verwendest oder nicht. Das sind zwei verschiedene Kategorien. Das eine, also Verwendung von Makros ist eine "Schreibweise", das andere, eine angepasste sparsame Repräsentation zu erdenken und Operationen darauf, sind "Algorithmen".
Peter D. schrieb: > Man kann ein Byte sparen, indem man nur das Low-Byte der Adresse > speichert. Kannst Du mir mal ein Beispiel zeigen?
Naj H. schrieb: > Also macht es jetzt kein Unterschied ob ich das mit dem Marko > mache oder > direkt in der Struktur mit einem Zeiger? wenn du deine Ports indirekt adressieren willst, nimm Pointer, die du genauso definierst, wie der Cast im Port-Zugriffsmacro (vor allem das volatile ist wichtig). Das ist der saubere Weg. Mit Zusatzwissen könnte man da ein paar einzelne Bytes sparen, aber das lohnt sich erst, wenn du wirklich merkst, dass es knapp wird. Dafür stellt man seinem zukünftigem Ich eventuell gemeine Fallen (siehe von Peda aufgeführtes Beispiel). Daher am besten den Port-Zugriff in einer inline-Funktion, die deine Struktur nimmt, kapseln und konsequent diese Funktion benutzen. Der Compiler optimiert den Zugriff schon weg. Wenn du wirklich viele Objekte deiner Struktur hast, und dich die Bytes wirklich schmerzen, könnte man natürlich die Ports durch Nummern abstrahieren und eine Pointertabelle anlegen. Das Würde in etwa so aussehen:
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 | |
Das hätte den Vorteil, dass du die Struktur auch noch als Bitset definieren könntest und nur 3bit für die Portnummern verwenden könntest. Allerdings heißt das auch, dass das Programm etwas langsamer wird, da der Compiler bei Zugriffen erst die Bits rauspopeln muss, wodurch auf der anderen Seite der Flashverbrauch geringfügig steigt.
1 | |
2 | |
3 | |
4 | |
Bevor man zu solchen Mitteln greift, wäre es wahrscheinlich aber eh ratsamer, den nächstgrößeren Controller zu benutzen.
Vlad T. schrieb: > Bevor man zu solchen Mitteln greift, wäre es wahrscheinlich aber eh > ratsamer, den nächstgrößeren Controller zu benutzen. Das sieht echt interessant aus! Muss ich mir mal genauer anschauen was da so passiert. Danke ;) Vlad T. schrieb: > Das hätte den Vorteil, dass du die Struktur auch noch als Bitset > definieren könntest und nur 3bit für die Portnummern verwenden könntest. Wie meinste das? Würdest Du bitte mal ein Beispiel bereitstellen?
Vlad T. schrieb: > typedef struct sMyS{ > signed action : 5; > unsigned port : 3; // for values see Ports enumeration > }MyS; Wieso hat action 5 Bits und port nur 3? Und wieso die Datentypen?
Naj H. schrieb: > Wieso hat action 5 Bits und port nur 3? > Und wieso die Datentypen? Weil ich das für mein Beispiel halt so festgelegt habe. Da es unwahrscheinlich ist, dass du mehr als 8 Ports hast, hab ich drei Bits genommen. Wie gesagt: ich würde es eh nicht so machen, nur wenn das Projekt fast fertig ist, und doch der Speicher knapp wird
Ich habe immer noch nicht gecheckt was Du mit dem Bitset meintest.. Wie würde das denn aussehen?
Gast
#6024524
Naj H. schrieb: > Ich habe immer noch nicht gecheckt was Du mit dem Bitset meintest.. Wie > würde das denn aussehen? Um es konkret zu machen wäre es einfacher, wenn Du die möglichen Adressen angibst. Die sind ja nicht beliebig, sondern 2 oder n konkrete.
Gast
#6024527
Meine Meinung: - Macros machen die meisten Probleme in C und C++. - Anfänger sollten keine Macros verwenden. Da werden Macros geschrieben, um nur ein paar Tasten Tipparbeit zu sparen. Die Seiteneffeke kommen dann Monate später, wenn man noch mal ein ++ an den Macroparameter hängt. Warum nicht eine Funktion schreiben. Das ist sauber, und der Compiler kann wunderbar die Syntax und Semantic checken. Und ein guter Compiler wird die Funktion ausrollen, wenn es z.B. nur eine Zuweisung ist. Da ist dann noch nicht einmal ein Performanceverlust. Und selbst 2019 gibt es noch Bücher zu C++, die man als Anfänger durcharbeiten könnte.
Naj H. schrieb: > Ich habe immer noch nicht gecheckt was Du mit dem Bitset meintest.. Wie > würde das denn aussehen? "Bitfelder" wäre der üblichere Begriff dafür: http://www.c-howto.de/tutorial/strukturierte-datentypen/bitfelder/
Teo D. schrieb: > Naj H. schrieb: >> Ich habe immer noch nicht gecheckt was Du mit dem Bitset meintest.. Wie >> würde das denn aussehen? > > "Bitfelder" wäre der üblichere Begriff dafür: > http://www.c-howto.de/tutorial/strukturierte-datentypen/bitfelder/ Mir ist schon bewusst was ein Bitfeld und was Strukturen sind! Was mir jedoch nicht ganz klar ist. Für was braucht es diese Struktur in dem Beispiel?
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
Das ist das was ich nicht verstehe.. Was soll "action" & "port" bewirken..
Naj H. schrieb: > Mir ist schon bewusst was ein Bitfeld und was Strukturen sind! Na dann nix für ungut! Naj H. schrieb: > Das ist das was ich nicht verstehe.. > Was soll "action" & "port" bewirken.. "action.., action..." Dito ?-/
Teo D. schrieb: > Naj H. schrieb: >> Mir ist schon bewusst was ein Bitfeld und was Strukturen sind! > > Na dann nix für ungut! > > Naj H. schrieb: >> Das ist das was ich nicht verstehe.. >> Was soll "action" & "port" bewirken.. > > "action.., action..." Dito ?-/ Bist Du im wahren Leben auch so "lustig" unterwegs? Ich würde das ganze jetzt so verstehen ->
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
Gast
#6024655
Mal ehrlich, wenn man so lange darüber diskutieren muss, dann kann es keine gute Idee sein. Als Machbarkeitsstudie im Hobby mag es noch OK sein. Im Job programmiert man aber so, dass andere den Quelltext verstehen und weiter entwickeln können. Da ist für solche Diskussionen kein Platz.
Naj H. schrieb: > Bist Du im wahren Leben auch so "lustig" unterwegs? Nich wirklich.... Nur ohne, lässt sich diese Form doch nicht ertragen. Naj H. schrieb: > Ich würde das ganze jetzt so verstehen -> Ja schon, nur mir war das zu sehr im Nebel gestochert. Die Entschuldigung war mir wichtiger.
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.