PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Register an Funktion übergeben



EDatabaseError
01.11.2008, 11:25
Hallo,
wie kann ich die Adresse eines Registers an eine Funktion übergeben?


uint8_t outSet(uint8_t *port, uint8_t pin, uint8_t level) {
uint8_t *DDR = 0;

if (*port == PORTA) { *DDR = DDRA; }
if (*port == PORTB) { *DDR = DDRB; }
if (*port == PORTC) { *DDR = DDRC; }
if (*port == PORTD) { *DDR = DDRD; }

asm("nop");

if (level) {
*port |= (pin << *port);
} else {
*port &= ~(pin << *port);
}

return level;
}

Aufruf: outSet(&PORTA,3,1);

Nur der Compiler meldet: ../main.c:84: warning: passing argument 1 of 'outSet' discards qualifiers from pointer target type


Was mache ich falsch?
Gruß

sternst
01.11.2008, 12:14
uint8_t outSet(volatile uint8_t *port, uint8_t pin, uint8_t level) {

Außerdem:

if (*port == PORTA) { *DDR = DDRA; }
->
if (port == &PORTA) { DDR = &DDRA; }

Aber wozu das, du verwendest DDR doch gar nicht?

PicNick
01.11.2008, 12:27
Diese Warnung bringt er gerne, wenn man mit Pointer arbeitet, das sagt garnix.

Übrigens: es ist nicht notwendig, aus den Pointer das DDRx Register zu ermitteln: Alle IO Register haben die gleiche struktur


typedef struct {
uint_8_t Pin; // in
uint_8_t Ddr; // control
uint_8_t Port; // out
} IO_REG;

// Aufruf
outSet((IO_REG*)&Pinb, 3, 1 )


uint8_t outSet(IO_REG* port, uint8_t pin, uint8_t level)
{
port->Ddr |= (1 << pin); // DDR auf Output

if (level)
port->Port |= (1 << pin); // Port.pin = 1
else
port->Port &= ~(1 << pin); // Port.pin = 0
return level;
}



Eventuell mit ausreichend "volatile"s beflastern

sternst
01.11.2008, 12:34
Diese Warnung bringt er gerne, wenn man mit Pointer arbeitet, das sagt garnix.


Das sagt in diesem Fall, dass das Ziel vom Zeiger port in der Funktion nicht mehr volatile ist, und das ist alles andere als "garnix".

thewulf00
01.11.2008, 12:41
Du weißt das vielleicht, weil Du Dich auskennst. Aber mir, PicNick und dem Topic-Eröffner sagte diese Meldung offensichtlich "garnix".

sternst
01.11.2008, 12:54
Du weißt das vielleicht, weil Du Dich auskennst. Aber mir, PicNick und dem Topic-Eröffner sagte diese Meldung offensichtlich "garnix".

Es besteht aber ein wichtiger Unterschied zwischen "das sagt garnix" und "das sagt mir garnix". PicNick sagt mit dem Satz, dass die Warnung quasi keine Bedeutung hat und einfach ignoriert werden sollte, und das ist ein ziemlich schlechter Rat.

PicNick
01.11.2008, 13:59
@sternst: jetzt ist die Spannung der Laien am Höhepunkt:
sag' uns doch endlich, was genau passiert, wenn wir die Warnung ignorieren und das Programm einfach starten.

sternst
01.11.2008, 14:20
sag' uns doch endlich, was genau passiert, wenn wir die Warnung ignorieren und das Programm einfach starten.

In diesem konkreten Fall wohl nichts. Aber wenn du z.B. bei dieser Funktion diese Warnung ignorierst, hast du bei eingeschalteter Optimierung eine sehr gute Chance auf eine Endlosschleife (außer natürlich, das Register ist bei Betreten der Funktion schon null):


void WaitForZero ( uint8_t *port ) {
while (*port);
}

...

WaitForZero(&PINC);

zerush
01.11.2008, 14:32
[...] was genau passiert, wenn wir die Warnung ignorieren und das Programm einfach starten.

Warnungen einfach zu ignorieren ist, so wie ich finde, generell eine sehr schlechte Angewohnheit. Es ist zwar so, dass oft nicht schlimmes passiert, wenn man es tut, manchmal (siehe sternst`s Beispiel) hat es aber unangenehme Fehler zur Folge, wo man unnötig lange nach einer Lösung sucht. Daher mein Rat: Immer den Code so schreiben, dass keine Warnungen mehr vorhanden sind!

EDatabaseError
01.11.2008, 17:11
Hab mir mal PicNics Vorschlag näher angeschaut..
Über die Typendefinition hab ich automatisch DDR,PIN und PORT? Wenn ja wäre dies ja super.

typedef struct {
uint8_t PIN;
uint8_t DDR;
uint8_t PORT;
} IO_REG;

uint8_t outSet(IO_REG* port, uint8_t pin, uint8_t level) {
port->DDR |= (1 << pin); //DDR as output

if (level) {
port->PORT |= (1 << pin);
} else {
port->PORT &= ~(1 << pin);
}

return level;
}

uint8_t inGet(IO_REG* port, uint8_t pin, uint8_t pullup) {
port->DDR &= ~(1 << pin); //DDR as input

if (pullup) {
port->PORT |= (1 << pin);
} else {
port->PORT &= ~(1 << pin);
}

if (port->PIN & (1 << pin)) {
return 1;
} else {
return 0;
}
}

Könnt ja nochmal über diesen code schauen. Compiliert mit 0 warnings. Noch nicht getestet.

Gruß

PicNick
01.11.2008, 18:04
Ja, die drei Register für ein IO port sind immer gleich aufsteigend hintereinander
+0 PINx
+1 DDRx
+2 PORTx

Bei inGet(...) gibt es nur ein theoretisches Risiko: die Zeit zwischen Pullup einschalten und Pin abfragen ist sehr kurz, ev. ist da noch kein stabiler Zustand auf der Leitung (von wegen Kapazitäten etc.).

EDatabaseError
01.11.2008, 18:24
wie lange sollte man den elektonen zeit geben?.. mehrere nops?..
muss man das PIN register übergeben oder kann man in die Funktion auch den Port übergeben?
bspw: outSet((IO_REG*)&PORTB, 3, inGet((IO_REG*)&PORTB,2,1) );

EDatabaseError
01.11.2008, 19:15
ok.. hat sich erledigt.. da sie aufeinanderfolgend sind sollte das erste übergeben werden. also PINA.. dann ist das nächste DDRA..

zerush
01.11.2008, 21:05
du kannst natürlich auch den PORT übergeben, dann musst du halt in deiner Funktion ein wenig umrechnen...

D.h. am Anfang von inGet und outSet musst du noch port -= 2; schreiben.
Dann musst du allerdings auch wirklich immer &PORTx übergeben.

PicNick
02.11.2008, 10:26
Dann ist die Sache aber nicht mehr wirklich koscher. denn dann ist ja das funktions-argument nicht wirklich korrekt. Und das wiederum betrachte ich als "bäh", andere stören sich mehr an Warnings
Ich glaube schon, dass man sich daran gewöhnen kann, immer "PINx" zu verwenden.

EDatabaseError
02.11.2008, 14:10
genau so mache es ich jetzt auch.

Warnings sind halt "unschön" manche kann man zwar ignorieren aber mir ist es immer lieber wenn da steht das er mit 0 warnings compiliert hat ;)