www.mikrocontroller.net

Forum: Compiler & IDEs Zeiger von PORTs (ATmega16)


Autor: Friedrich Feichtinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
struct PORTS

{

  unsigned char *port;

  unsigned char pin;

};
Die kann dann etwa so aussehen: (Es existieren bereits mehrere solche 
structs für verschiedene Aufgaben)
struct PORTS power_config[N_POWER] = {

  

  {&PORTA,(1<<0)},

  {&PORTA,(1<<1)},

  {&PORTA,(1<<2)},

  {&PORTA,(1<<3)},

  {&PORTA,(1<<4)},

  {&PORTA,(1<<5)},

  {&PORTA,(1<<6)},

  {&PORTA,(1<<7)},

  

  {&PORTC,(1<<7)},

  {&PORTC,(1<<6)},

  {&PORTC,(1<<5)}

  

};
Wenn man dann zb. den Gleisabschnitt Nr. 5 Einschalten möchte muss man 
nur:
*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

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
unsigned char *port;
->
volatile unsigned char *port;

Autor: Friedrich Feichtinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank, da wär ich nie drauf gekommen!

mfg Fritz

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.htm...

Autor: Friedrich Feichtinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.
void set_rail(unsigned char railNr, unsigned char trainNr)

{

  rail[railNr] = trainNr;

  //while(!eeprom_is_ready());  // wait while EEPROM is not ready

  eeprom_write_byte(railNr, trainNr);

}

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

Autor: Einer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Für mich als eingefleischten Pascal Programmierer ist das auch immer 
Qualvoll.

Autor: gast (Gast)
Datum:

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

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Friedrich Feichtinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Es geht bei der Warnung darum, dass du einem Pointer direkt einen Wert >zuweist.

Hm, das stimmt.

Ich hab jetzt mal so geschrieben:
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:
static inline void __attribute__ ((always_inline))
eeprom_write_byte (uint8_t *addr,uint8_t value);

mfg Fritz

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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);

Autor: gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
grrrr...
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

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
gast wrote:
> grrrr...
>
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).

Autor: gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wo?
void set_rail(unsigned char railNr, unsigned char trainNr)

{

  rail[railNr] = trainNr;

  //while(!eeprom_is_ready());  // wait while EEPROM is not ready

  eeprom_write_byte(railNr, trainNr);

}
Entschuldigt meine Blindheit!

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wo was?

Autor: Friedrich Feichtinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Friedrich Feichtinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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)"

Autor: Friedrich Feichtinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tatsächlich!

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

mfg Fritz

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.