Forum: Compiler & IDEs Zeiger von PORTs (ATmega16)


von Friedrich Feichtinger (Gast)


Lesenswert?

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
struct PORTS
2
3
{
4
5
  unsigned char *port;
6
7
  unsigned char pin;
8
9
};
Die kann dann etwa so aussehen: (Es existieren bereits mehrere solche 
structs für verschiedene Aufgaben)
1
struct PORTS power_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

von Stefan E. (sternst)


Lesenswert?

unsigned char *port;
->
volatile unsigned char *port;

von Friedrich Feichtinger (Gast)


Lesenswert?

Vielen Dank, da wär ich nie drauf gekommen!

mfg Fritz

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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

von Friedrich Feichtinger (Gast)


Lesenswert?

>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.
1
void set_rail(unsigned char railNr, unsigned char trainNr)
2
3
{
4
5
  rail[railNr] = trainNr;
6
7
  //while(!eeprom_is_ready());  // wait while EEPROM is not ready
8
9
  eeprom_write_byte(railNr, trainNr);
10
11
}

Wieder einmal funktioniert die Sache auch, aber der Compiler gibt eine 
Warunung aus:
1
warning: passing argument 1 of eeprom_write_byte makes pointer from integer without a cast
seltsam ist nur, dass die analoge Funktion:
1
eeprom_read_block(rail, 0x00, 8);
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

von Einer (Gast)


Lesenswert?

Für mich als eingefleischten Pascal Programmierer ist das auch immer 
Qualvoll.

von gast (Gast)


Lesenswert?

Klar, die Funktion will 'ne Adresse. Im 2. Bleistiel wird 
(korrekterweise) die Anfangsadresse des Array's (!) übergeben, denn rail 
== &rail[0]. ;)

von Stefan E. (sternst)


Lesenswert?

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.

von Friedrich Feichtinger (Gast)


Lesenswert?

>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:
1
static inline void __attribute__ ((always_inline))
2
eeprom_write_byte (uint8_t *addr,uint8_t value);

mfg Fritz

von Stefan E. (sternst)


Lesenswert?

> 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);

von gast (Gast)


Lesenswert?

grrrr...
1
eeprom_write_byte((&railNr, trainNr);
nicht wild casten (jedenfalls nicht so), Adressoperator anwenden! (oder 
gleich der untergeordneten Funktion 'nen Pointer (eine Adresse) 
übergeben.
Soweit mein bescheidener Bildungsstand.

mfg

von Stefan E. (sternst)


Lesenswert?

gast wrote:
> grrrr...
>
1
eeprom_write_byte((&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).

von gast (Gast)


Lesenswert?

wo?
1
void set_rail(unsigned char railNr, unsigned char trainNr)
2
3
{
4
5
  rail[railNr] = trainNr;
6
7
  //while(!eeprom_is_ready());  // wait while EEPROM is not ready
8
9
  eeprom_write_byte(railNr, trainNr);
10
11
}
Entschuldigt meine Blindheit!

von Stefan E. (sternst)


Lesenswert?

Wo was?

von Friedrich Feichtinger (Gast)


Lesenswert?

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

von Friedrich Feichtinger (Gast)


Lesenswert?

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

von Stefan E. (sternst)


Lesenswert?

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)"

von Friedrich Feichtinger (Gast)


Lesenswert?

Tatsächlich!

Tut mir leid, dass muss ich irgendwie übersehen haben, sorry.

mfg Fritz

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.