Hallo
Ich arbeite gerade an der Steuerung einer Modelleisenbahnanlage. Es sind
dabei mehrere ATmega 16 vernetzt und schalten Weichen, Gleisabschnitte
usw.
Um aus der Weichennummer auf den zu schaltenden Ausgang schließen zu
können habe ich eine struct deffiniert:
1
structPORTS
2
3
{
4
5
unsignedchar*port;
6
7
unsignedcharpin;
8
9
};
Die kann dann etwa so aussehen: (Es existieren bereits mehrere solche
structs für verschiedene Aufgaben)
1
structPORTSpower_config[N_POWER]={
2
3
4
5
{&PORTA,(1<<0)},
6
7
{&PORTA,(1<<1)},
8
9
{&PORTA,(1<<2)},
10
11
{&PORTA,(1<<3)},
12
13
{&PORTA,(1<<4)},
14
15
{&PORTA,(1<<5)},
16
17
{&PORTA,(1<<6)},
18
19
{&PORTA,(1<<7)},
20
21
22
23
{&PORTC,(1<<7)},
24
25
{&PORTC,(1<<6)},
26
27
{&PORTC,(1<<5)}
28
29
30
31
};
Wenn man dann zb. den Gleisabschnitt Nr. 5 Einschalten möchte muss man
nur:
1
*power_config[5].port|=power_config[5].pin;
(Das wird dann natürlich wieder von einer Funktion übernommen)
Das Ganze funktioniert eigentlich prima, einzig der Compiler gibt für
jeder dieser "{&PORTA,(1<<0)}" Zeilen eine Warnung aus, und das sind
eine Menge! :
"warning: initialization discards qualifiers from pointer target type"
Das soll wahrscheinlich heißen, dass es ihm nicht schmeckt, dass ein
PORT ein 'unsigned char' sein soll. Aber, naja, eine Byte ist immer noch
ein Byte ;)
Wie macht man so etwas richtig? Es ist zwar für die Funktion nicht
essential, aber die vielen Warnungen nerven doch ziemlich und 'trüben
den Glanz des ganzen Projektes' ;)
Vielen Danke für alle Beiträge
mfg Fritz
Friedrich Feichtinger wrote:
> Vielen Dank, da wär ich nie drauf gekommen!
Dazu muss man halt wissen, was genau ein "type qualifier" in C ist:
eins der drei Schlüsselworte const, volatile oder restricted.
Oder man liest die FAQ. ;-)
http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_port_pass
>Oder man liest die FAQ. ;-)<
Wenn ich mir alle FAQ's lesen würde, die es im web so gibt hätte ich
keine Zeit zum Programmieren mehr ;). Aber danke für den Link!
Jetzt will ich gleich noch mal eins nachwerfen, da es wohl in ein
ähnliches Themengebiet fällt. Ich will den EEPROM benutzen um wichtige
Werte (die Belegung des Schattenbahnhofes) über den stromlosen Zustand
hinaus zu sichern, und beim nächsten Einschalten wieder zu laden.
WICHTIG:
Diese Daten sollen auch beim Programmieren des µC nicht verändert
werden, sondern werden nur über Routinen im laufenden Programm
verändert.
Diese Funktion soll die Werte sowohl im RAM als auch im EEPROM
verändern.
keine Warnung erzeugt.
Vielleicht ist C zu kompliziert für mich, für mich ist ein Byte einfach
ein Byte und sonst nichts, egal ob es jetzt uint8 oder unsigned char
heißt ?!
Vielen Dank
mfg Fritz
eeprom_write_byte(railNr, trainNr);
->
eeprom_write_byte((uint8_t *)railNr, trainNr);
Sofern du die Daten im EEPROM selber organisieren willst.
Dass du beim zweiten Aufruf keine Warnung bekommst, liegt daran, dass du
eine 0 zuweist. Eine 0 als Wert für einen Pointer wird immer auch direkt
(ohne Cast) akzeptiert.
> Vielleicht ist C zu kompliziert für mich, für mich ist ein Byte einfach> ein Byte und sonst nichts, egal ob es jetzt uint8 oder unsigned char> heißt ?!
Es geht nicht um "unsigned char" <-> "uint8_t" (du könntest auch
schreiben eeprom_write_byte((unsigned char *)railNr, trainNr);). Es geht
bei der Warnung darum, dass du einem Pointer direkt einen Wert zuweist.
>Es geht bei der Warnung darum, dass du einem Pointer direkt einen Wert >zuweist.
Hm, das stimmt.
Ich hab jetzt mal so geschrieben:
1
eeprom_write_byte((uint8_t*)railNr,trainNr);
aber jetzt kommt eine neue Warnung:
warning: cast to pointer from integer of different size
Das versteh ich nicht. Ich hab mal in eeprom.h reingeschaut und da
steht:
> aber jetzt kommt eine neue Warnung:> warning: cast to pointer from integer of different size
Ein Pointer ist 16 Bit groß, dein railNr aber wohl nur 8 Bit.
eeprom_write_byte((uint8_t *)(uint16_t)railNr, trainNr);
> nicht wild casten (jedenfalls nicht so), Adressoperator anwenden! (oder> gleich der untergeordneten Funktion 'nen Pointer (eine Adresse)> übergeben.
Nein, denn railNr ist die Adresse.
Er will die Daten im EEPROM offensichtlich selber verwalten (mittels
eines Indexes).
Entschuldigt, das ist vielleicht nicht klar herausgekommen.
Stefan hat vollkommen recht. railNr ist die Addresse! Ich will das
EEPROM selbst verwalten.
rail[] ist eine globale Variable. Wenn dort ein Eintrag geändert wird,
dann soll er auch sofort im EEPROM geändert werden.
rail[0] wird also auch im EEPROM an der Adresse 0x00 abgespeichert,
rail[1] an 0x01 und so weiter. Da das immer nur ein Byte ist
funktioniert das so einfach.
d.h. wenn ich das Array rail[] beim Index railNr den Wert trainNr
zuweisen will dann rufe ich meine Funktion set_rail auf. Diese setzt
zuerst den Wert im Array:
rail[railNr] = trainNr;
und schreibt dann den selben Wert an die entsprechende Addresse im
EEPROM
eeprom_write_byte(railNr, trainNr);
Es ist also wirklich railNr und nicht &railNr!
mfg Fritz
Hallo
Ich hab jetzt das Problem gefunden:
Ein Pointer ist 16Bit lang und nicht 8Bit! D.h. ich muss zuerst auf
16Bit casten und dann auf einen Pointer:
eeprom_write_byte((uint8_t *)(uint16_t)railNr, trainNr);
Jetzt sind alle Warnungen verschwunden, vielen Dank an alle.
mfg Fritz
Friedrich Feichtinger wrote:
> Ich hab jetzt das Problem gefunden:>> Ein Pointer ist 16Bit lang und nicht 8Bit! D.h. ich muss zuerst auf> 16Bit casten und dann auf einen Pointer:>> eeprom_write_byte((uint8_t *)(uint16_t)railNr, trainNr);
:D
Genau das habe ich doch vor 3 Tagen schon geschrieben:
Beitrag "Re: Zeiger von PORTs (ATmega16)"