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:
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
uint8_t*ptr=(uint8_t*)0x32;// PORTD
2
*ptr|=(1<<0;
Das mit dem Zeiger deklarieren würde ich gerne schicker durch ein Makro
verpacken..
wenn nur schreibend, dann verhindern, dass der Ausdruck so wie er da
steht irgendwo zugewiesen werden kann, im einfachsten Fall einen dummy
Block davor.
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.
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.
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)
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:
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:>
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:> 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
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:
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.
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.
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.
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.
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".
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:
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
typedef struct sMyS{
2
signed action : 5;
3
unsigned port : 3; // for values see Ports enumeration
4
}MyS;
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
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.
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.
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
typedefstructsMyS{
2
int8_taction;
3
uint8_tport;// for values see Ports enumeration
4
}MyS;
5
6
voiddoSmth(constMyS*i_d){
7
// ...
8
*getPort((Ports)i_d->port)=5;
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 ->
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.