Forum: Mikrocontroller und Digitale Elektronik Frage zum Verständnis in C


von Phillip H. (philharmony)


Lesenswert?

Moin,
Ich stehe grade etwas auf dem Schlauch.
Wenn ich in einer Funktion ein Ergebnis habe und das in einer globalen 
Variable speichern möchte, ist dann
1
main
2
{
3
int Wert;
4
Wert= funktion(2,5);
5
}
6
7
int funktion(para11, para2)
8
{ int result;
9
  result=para1 + para2;
10
  return result;
11
}
das selbe wie
1
main
2
{
3
int Wert;
4
funktion(2,5);
5
}
6
7
void funktion(para1, para2)
8
{ Wert = para1+para2;
9
}
?
Bei all den pointern und zuweisungen und all dem Lesen über Strings bin 
ich da grade echt verwirrt...

von Uwe .. (uwegw)


Lesenswert?

Das zweite funktioniert nicht, weil Wert in funktion nicht bekannt ist. 
Damit Wert eine globale Variable ist (und das Programm funktioniert), 
muss sie außerhalb von main stehen.

von Phillip H. (philharmony)


Lesenswert?

Äh logisch, Tipfehler im Beispielcode, ich sag ja, ich bin verwirrt, ich 
sollte Pause machen ;)
Wenn Wert ausserhalb steht dann geht es auf beide Arten oder?

von Stefan B. (forscher)


Lesenswert?

Phillip,
das zweite Beispiel wird einen Fehler beim Übersetzen bringen, da "Wert" 
in der funktion eine unbekannte Variable ist. Die Deklaration von "Wert" 
innerhalb von main ist auch nur innerhalb von main sichtbar.
Das ist eine lokale Variable deren Inhalt beim verlassen von main 
verloren geht.
Stefan

von STK500-Besitzer (Gast)


Lesenswert?

>Wenn Wert ausserhalb steht dann geht es auf beide Arten oder?

Ja.

von Micha .. (mig)


Lesenswert?

Zunächst hast du hier weder Pointer noch globale Variablen definiert.
Globale Variablen (global--> überall) werden vor der main fkt. 
deklariert.
Diese Variablen kann man dann von überall ansprechen.
Eigendlich seltener genutzt, da man sie schnell bei größeren Programmen 
versehendlich doppelt anspricht. (Irgendwie ist man bei der 
Namensvergebung meist doch nicht so kreativ)

Funktionen kennen nur die Variablen die
1. ihnen übergeben werden
2. Global deklariert wurden
3. in der Funktion selbst deklariert wurden
Du musst beachten, jede Variable IN einer Funktion wird nach dessen 
beenden "vergessen".
Ausnahme ist noch alles was static deklariert wird.(versuch das später)

Bei Pointern hingegen wird direkt auf die Adresse der Variablen 
zugegriffen.
Dazu muss der Funktion aber die Adresse übergeben werden.

//Bsp.:
//in der main:
...
//aufruf der funktion
myfunction(&Variable);
...

//die Funktion
void myfunction( *Variable)
{
*Variable = 5;
}

von Phillip H. (philharmony)


Lesenswert?

Danke, langsam komme ich wieder rein.
Nochmal grad die nächste (saublöde?) Frage (kann das grade nicht testen 
da ich nur mitm Notepad schreibe, Compiler etc hab ich hier nicht aufm 
Schlepptop):
Wie übergebe ich einer Funktion ein Array? Pointer auf die erste Stelle 
oder?
In der Funktion soll eine Schleife laufen die die einzelnen 
Array-Elemente verarbeitet.
1
int Wert, array[]{2,5,7};
2
main
3
{ funktion(array, sizeof(array));
4
}
5
6
void funktion(int* quelle, unsigned char durchläufe)
7
{ unsigned char i;
8
  while(i=0;i++;durchläufe)
9
  { Wert += quelle[i];
10
  }
11
}

von Peter (Gast)


Lesenswert?

Das 2. Beispielt geht auch, unter gewissen bedingungen (Compiler)

Siehe: http://ridiculousfish.com/blog/page/3/
           -> February 5th, 2006

Das ganze ist aber soweit ich weiss kein Standard mehr.

von Phillip H. (philharmony)


Lesenswert?

Ok, eins nach dem andern, vergesst mal den zweiten Code.
Mein Problem ist das: Ich habe seit über einem Jahr nicht mehr 
Programmiert, Microcrontroller bedient etc. Jetzt muß ich am Projekt 
weitermachen, hatte dazu ne glaube ich recht Brauchbare Idee und habe 
jetzt das Gefühl daß das auf einmal unendlich kompliziert wird.
Ich hatte vor einem Jahr auch schon einige Programme geschrieben die auf 
dem Atmel wunderbar liefen, ohne ein einziges mal irgendwelche Pointer 
benutzen zu müssen (auch wenn ich inzwischen so halbwegs verstehe was es 
damit auf sich hat und mir ist auch klar daß ohne Pointer beim 
Programmaufruf immer nur der WERT der Parametzer übergeben wird).
Ich versuche gerade ein bisschen Struktur in die ganze Sache zu 
bringen...

von G. Ast (Gast)


Lesenswert?

Wie wäre es, wenn du dir schnell mal nen C-Compiler auf deinem 
Schlepptop installierst? Dann könntest du schon einmal Syntaxfehler 
selber suchen.

Bitte höre auch auf, Variablen am Wortanfang groß zu schreiben oder 
Umlaute zu nutzen.

while(i=0;i++;durchläufe)

das sollte wohl eine for-schleife werden.

von Peter D. (peda)


Lesenswert?

Phillip Hommel schrieb:
> Jetzt muß ich am Projekt
> weitermachen, hatte dazu ne glaube ich recht Brauchbare Idee und habe
> jetzt das Gefühl daß das auf einmal unendlich kompliziert wird.


Dann vergiß erstmal, Programme aus dem Ärmel zu schütteln.
Schalte den PC ab, nimm Papier und Bleistift und mache erstmal nen 
Programmablaufplan.

Schon Egon Olsen hat nichts ohne Plan gemacht.


Und wenn Du grundsätzliche Fragen zu C hast, installiere AVRStudio + 
WINAVR und simuliere einfach mal einige Sachen.


Peter

von Phillip H. (philharmony)


Lesenswert?

Sorry, der Umlaut ist natürlich nur im Beispieltext vorhanden, ging mir 
da ja um die Funktion. Was ist das Problem an großgeschriebenen 
Variablen? (ernsthafte Frage).
Ich werd das für heute mal beiseite legen, mir raucht grad so die 
Birne...

von bartsch (Gast)


Lesenswert?

Uiuiui ...

- Nutzung einer globalen Variable anstatt die Return-Funktionalität zu 
verwenden
- die "for"-Schleife wird dir nicht ganz tun was sie soll, Tipp: 
durchlaeufe=sizeof(array)/sizeof(int)

Fazit: Hier sollte jemand einen C-Grundkurs belegen.

von G. Ast (Gast)


Lesenswert?

> Was ist das Problem an großgeschriebenen Variablen? (ernsthafte Frage).

Es ist kein Problem. Es erhöht einfach die Lesbarkeit des Quelltextes, 
da sich viele Leute an diese Vereinbarung halten.
Stichworte: Coding Style, Coding Rule, ...

Ansonsten siehe Peter und bartsch.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> > Was ist das Problem an großgeschriebenen Variablen? (ernsthafte Frage).
>
> Es ist kein Problem. Es erhöht einfach die Lesbarkeit des Quelltextes,
> da sich viele Leute an diese Vereinbarung halten.

Das ist eine reine Konvention.
Es gibt zwei unterschiedliche Varianten, aus mehreren Wörtern bestehende 
Symbolnamen zusammenzusetzen:

  mach_was_sinnvolles
  MachWasSinnvolles

Beide Varianten sind weit verbreitet, und beide Varianten werden von den 
Anhängern der jeweils anderen Variante aufs übelste verteufelt und für 
völlig unlesbar gehalten.

Hier soll es jeder so machen, wie er es für sich richtig hält. Nur 
konsistent muss das ganze dann sein, also auf gar keinen Fall ein 
Mischbetrieb aus beiden Varianten.

Bei der zweiten Variante werden oft auch den Variablentyp bezeichnende 
Präfixe verwendet, so daß man ohne die Deklaration zu sehen schon 
erkennen kann, worum es sich handelt:

  iCount
  pBuffer

(das vorangestellte i steht für int, das vorangestellte p für Pointer).

Das ganze gipfelt in der sogenannten "ungarischen Notation", die von 
Charles Simonyi in der Firma Microsoft entwickelt wurde.

Das ist natürlich auch äußerst umstritten, die pro- und 
contra-Ungarisch-Diskussionen füllen locker eine kleine 
Stadtteilbibliothek.

Auch hier bin ich der Ansicht, daß das jeder so einsetzen soll, wie er 
es für richtig hält, solange er dabei auch langfristig konsistent 
bleibt.


Es gibt aber auch Konventionen, an die man sich unbedingt halten 
sollte:
Komplett in Großbuchstaben werden nur Macros geschrieben, also Dinge, 
die per #define definiert werden.
Bezeichner fangen nie mit einem Unterstrich an, das ist für 
Compilerdinge reserviert.

von Phillip H. (philharmony)


Lesenswert?

[quote]
- Nutzung einer globalen Variable anstatt die Return-Funktionalität zu
verwenden
[/quote]
Wenn ich genau einmal genau einen Wert zurückgeben möchte mache ich das 
natürlich per return. Es geht ja darum daß die Funktion eine Schleife 
beinhaltet die je durchlauf zb einen anderen Pin ausliesst und dessen 
Zustand in eine andere Stelle eines arrays abspeichern soll.
Daß ich in C alles andere als fit bin bestreite ich absolut nicht und 
ich danke auch allen für konstruktive Kritik und Hilfestellungen.
Vielleicht erkläre ich nochmal kurz was ich eigentlich machen möchte:
Der Atmel soll folgendes tun:
Es sollen nach einander PORTA, PORTB, PORTC, (D nicht, der wird anders 
verwendet) sowie der ADC und pins, an denen Gray-Encoder hängen 
ausgewertet werden. welche Pins wie belegt sind wir in einem setup-file 
festgelegt.
Darin stehen dann arrays wie
1
int porta_input_pins[]{zb 0,1,2,3,4}
2
int portb_input_pins[]{0,4,5,6}
3
int portc_input_pins[]{0,1}
4
int adc_input_pins[]{5,6,7} //es wird an anderer stelle 
5
//dafür gesorgt daß sich das mit den pins von porta nicht überschneidet.
6
dann noch
7
int porta_input_values[sizeof(porta_input_pins)]
8
int portb_input_values[sizeof(portb_input_pins)]
jetzt ist die Idee, in main eben die zugewiesenen pins von port a 
auszulesen, und ihren Zustand in die entsrechenden Stellen von 
porta_input_values zu speichern. Dazu kommen noch ein paar 
Vergleichs-Funktionen, die bei Ungleichheit gegenüber dem letzten 
Durchgang die Pin Nummer(bzw am Ende einen dem Pin zugewiesenen Namen 
als String) und den Zustand per UART an den PC schickt.
Das selbe dann eben auch noch mit dem ADC der die Position angehängter 
Potis ausliest und Zahlenwerte die per Drehencoder hoch oder 
runtergezählt werden.
Dazu sollen dann in der Haputschleife die einzelnen Funktionen in etwa 
so aufgerufen werden (nur schematisch, evtl Synthaxfehler ignorieren!)
1
void(?) funct_read_port(welcher_port, durchlaufe)
2
{ for (i=0,i<durchlaufe,i++)
3
  { porta_input_values[i] = getbit(PINA, porta_input_pins[i]) 
4
//der Zustand desjenigen pins der an Stelle i des
5
//zuweisungsarrays steht soll in Stelle i des 
6
//values-arrays gespeichert werden
7
  }
8
}
9
10
Aufruf:
11
12
funct_read_port(PORTA, sizeof(porta_input_pins))
13
//also soviele Durchläufe wie das Array elemente hat
14
//bei 0 wird direkt abgebrochen
Der Code soll dabei fertig stehen, sodaß man nur (später per GUI) im 
Setup-File eine "Pinbelegung" erstellen braucht und im Code selbst 
nichts rumschreiben muss(soll).

von Phillip H. (philharmony)


Lesenswert?

So, habe mal über alles geschlafen und mir heute wieder AVR-Studio 
installiert.
Soweit lief das auch alles in der Simulation so wie ich mir das 
vorgestellt hatte.
Was mich jetzt aber stutzig macht, ist ich einige der vorigen Posts so 
verstanden habe, als wäre die Benutzung von globalen Variablen eines der 
absoluten No-Gos in C, und im AVR-GCC Tutorial wird es auch so 
beschrieben "manchmal geht es leider nicht anders sodaß man sich diesem 
Teufelszeug doch bedienen muss".
Aus anderen Sprachen mit denen ich früher gearbeitet habe (VB, Delphi) 
ist das dagegen ganz normale Anwendung. Daher würde mich mal 
interessieren wo denn in C dabei das große Problem liegt.
Wenn es nämlich GEHT (und so sieht es in der simulation aus), dann 
verstehe ich nicht warum ich mir aus meiner bescheidenen Einsicht das 
Leben unendlich kompliziert gestalten soll und mit Pointern um mich 
werfen soll wenn ich doch einfach einen zentralen Speicherbereich 
festlegen kann in dem alles gespeichert wird was ich will und auf den 
ich jederzeit zugreifen kann.
Vielleicht könnte mir das jemand erklären?

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Phillip Hommel schrieb:
> Was mich jetzt aber stutzig macht, ist ich einige der vorigen Posts so
> verstanden habe, als wäre die Benutzung von globalen Variablen eines der
> absoluten No-Gos in C, und im AVR-GCC Tutorial wird es auch so
> beschrieben "manchmal geht es leider nicht anders sodaß man sich diesem
> Teufelszeug doch bedienen muss".

Alles was "global" ist kannst du bedenkenlos auch global machen (und bei 
Interrupts z.B. hat man meist garkeine Andere möglichkeit als globale 
Variablen zu nutzen), nur Funktionsrückgaben über globale Variablen 
"macht man nicht" da das häufig zu Problemen führen kann (z.B. bei 
Rekursionen) und die Wiederverwendbarkeit des Codes stark einschränkt.

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Ich würde sagen, dass es eine Art Glaubensfrage ist. Es ist keineswegs 
verboten, globale Variablen zu verwenden (spart auch Platz auf dem 
Stack). Oft ist es aber sinnvoll lokale Variablen einzusetzen, da der 
Compiler diese direkt auf die Register verteilen kann und keinen 
RAM-Speicher benötigt.

Globale Variablen bergen bei größeren Projekten das Risiko, dass man sie 
nicht immer lokal (im Quellcode) sehen kann. Oft passiert es dann, dass 
man eine lokale Variable mit gleichem Namen verwendet.

Es ist halt nicht verboten, globale Variablen zu verwenden (sonst gäbe 
es sie nicht). Man sollte aber überlegen, ob sie Sinn machen.

von Phillip H. (philharmony)


Lesenswert?

Ok dankeschön. Hab grade auch noch nen recht interessanten Artikel 
entdeckt wo von Seiteneffekten gesprochen wird, klingt schon 
eileuchtend, ast dann aber wieder eher eine Sorgfaltsfrage.
Ich denke wenn mal globale Variablen vernünftig kennzeichnet (zb mit 
prefix "glob" oder wie auch immer) sollte das gehen.
Also kriege ich für mein o.g. Beispiel dann doch nicht von allen Seiten 
auf den Deckel? Das hatte ich nämlich vorher so verstanden.
Daß man natürlich eher Parameter übergibt und einfache Funktionen per 
return "antworten" lässt ist mir auch klar, ich sehe nur ehrlich gesagt 
auch echt keine andere Möglichkeit, meine Loop-Pinabfrage anders 
abzuspeichern oder sehe ich das jetzt wieder falsch?

von G. Ast (Gast)


Lesenswert?

Hallo Phillip, komm mit erhobenen Händen raus!
Stelle dich, hier spricht die C-Polizei!

Naja, soweit wird es nicht kommen. Versuch dein Problem zu lößen, wenn 
es geht, ist gut.
Mach deine Erfahrungen, ist bisher der beste Lehrmeister.
Irgendwann wirst du konsistenten Programmierstil zu schätzen wissen. 
Genauso wie du lernst, abzuschätzen was eine globale Variable (vll. auch 
static) Wert oder nicht Wert ist.

von Tente (Gast)


Lesenswert?

Beachtet wenn du void vor deine Funktion setzt, du keinen Parameter 
zurück gibs.

von Mark B. (markbrandis)


Lesenswert?

Läubi .. schrieb:
> da das häufig zu Problemen führen kann (z.B. bei
> Rekursionen)

Rekursive Funktionen setzt man auf kleinen Mikrocontrollern sowieso 
nicht ein (in MISRA-C z.B. sind sie verboten).

von Klaus W. (mfgkw)


Lesenswert?

Was ich als pauschale Aussage auch nicht unterschreiben würde...
MISRA ist nicht die Bibel, und Rekursion kann sinnvoll sein,
wenn man weiß was man tut.
MISRA verbietet ja alles, was in C Spaß macht (fast alles,
Zeiger glaube ich sind erlaubt, oder?).

Wenn ich mit bsearch in einem sortierten Feld suche, nehme ich
Rekursion. Da kann MISRA sauer werden oder nicht.

von Mark B. (markbrandis)


Lesenswert?

Klaus Wachtler schrieb:
> Was ich als pauschale Aussage auch nicht unterschreiben würde...
> MISRA ist nicht die Bibel, und Rekursion kann sinnvoll sein,
> wenn man weiß was man tut.
> MISRA verbietet ja alles, was in C Spaß macht (fast alles,
> Zeiger glaube ich sind erlaubt, oder?).

Ja - mit Einschränkungen ;-)

> Wenn ich mit bsearch in einem sortierten Feld suche, nehme ich
> Rekursion.

Auf einem Mikrocontroller? Was sortiersuchst Du denn so? :-)

von Klaus W. (mfgkw)


Lesenswert?

Bisher nichts, aber wenn ich z.B. eine Art Kommandointerpreter
bräuchte mit einer Kiste voll Schlüsselwörtern, würde ich
dafür lieber binäre Suche nehmen als linear zu suchen.

Das generelle Problem mit Rekursion, worauf du vielleicht
hinauswillst, ist daß man ggf. nicht sicher vorhersagen kann, wie
tief die Verzweigung ist und dementsprechend man nicht sicher
sagen kann, ob der Stack ausreicht - und folglich sicher
irgendwann nicht reichen wird.

Bei einem Fall wie binärer Suche gibt es aber eine sichere
Grenze (log2(Feldlänge)); deshalb habe ich es als Beispiel
dafür angeführt, weswegen ich ein generelles Verbot von
Rekursion nicht als zielführend erachte.

Wenn ich Rekursion generell verbiete ("kann ja schief gehen,
wenn man es falsch einsetzt"), muß ich mit der gleichen
Begründung die komplette Sprache C, Bier und vieles andere
verbieten.
Irgendwie ist mir das zu religiös. Zumindest brauche ich dann
kein C mehr.

von bartsch (Gast)


Lesenswert?

1
int porta_input_pins[]{0,1,2,3,4}
2
...
3
int porta_input_values[sizeof(porta_input_pins)]
Die Größenberechnung von porta_input_values ist noch flasch. sizeof 
liefert nicht die Anzahl der Elemente, sondern die Größe in Bytes. (Im 
vorliegenden Beispiel ist das kein Problem da das resultierende Array 
größer wird als nötig.)

Korrrekt wäre:
1
int porta_input_values[sizeof(porta_input_pins)/sizeof(int)]

Zur Verifikation:
1
printf("s=%ld vs. s/s=%ld",
2
    sizeof(porta_input_pins),
3
    sizeof(porta_input_pins)/sizeof(int))

von Mark B. (markbrandis)


Lesenswert?

Klaus Wachtler schrieb:
> Irgendwie ist mir das zu religiös. Zumindest brauche ich dann
> kein C mehr.

Dann nimmst Du halt Ada. ;-)

von Klaus W. (mfgkw)


Lesenswert?

"A, da" wo es keinen Compiler für die AVR gibt? :-)

Obwohl, müsste mit gcc doch gehen.

von Karl H. (kbuchegg)


Lesenswert?

bartsch schrieb:
>
1
int porta_input_pins[]{0,1,2,3,4}
2
> ...
3
> int porta_input_values[sizeof(porta_input_pins)]
> Die Größenberechnung von porta_input_values ist noch flasch. sizeof
> liefert nicht die Anzahl der Elemente, sondern die Größe in Bytes. (Im
> vorliegenden Beispiel ist das kein Problem da das resultierende Array
> größer wird als nötig.)
>
> Korrrekt wäre:
>
1
int porta_input_values[sizeof(porta_input_pins)/sizeof(int)]
>
> Zur Verifikation:
>
1
printf("s=%ld vs. s/s=%ld",
2
>     sizeof(porta_input_pins),
3
>     sizeof(porta_input_pins)/sizeof(int))

Abgesehen davon finde ich die ganze angedachte Systematik ziemlich 
umständlich und eigentlich unnötig aufwändig.

Anstelle des Arrays porta_input_pins tut es auch ein einzelner unsigned 
char. Angeforderte Port-Pins werden dort durch ein 1 Bit repräsentiert. 
Sprich dieser uchar dient gleichzeitig als Mask, mit der das PIN 
Register geundet wird um nur noch die ineterssierenden Bits übrig zu 
lassen. Der Pin Inhalt wird auf einmal eingelesen, mit der Maske geundet 
mit einer Previous Kopie des vorhergehenden Pin-Zustands ge-xodert und 
es bleiben die Bits übrig, die sich geändert haben.

Das ganze braucht keine 20 Takte und ist linear runterprogrammiert. Im 
Vergleich zu so einer Schleifenlösung x-fach schneller.

Lediglich das auseinanderpfriemeln einer Benutzereingabe bzw. die 
Anzeige der überachten Pins wird (leicht) komplexer. Aber nicht wirklich 
gravierend komplexer.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Mark Brandis schrieb:
> Läubi .. schrieb:
>> da das häufig zu Problemen führen kann (z.B. bei
>> Rekursionen)
>
> Rekursive Funktionen setzt man auf kleinen Mikrocontrollern sowieso
> nicht ein (in MISRA-C z.B. sind sie verboten).
Ich wollte auch eher sagen warum man im Allgemeinen Rückgaben nicht 
über globale Variablen machen sollte.
Ansonsten tritzt das Problem natürlich auch auf wenn an zwei Stellen die 
gleiche Funktion aufgerufen wird.

von Karl H. (kbuchegg)


Lesenswert?

Globale Variablen haben einfach den Nachteil, dass sie dir einen guten 
Teil an Flexibilität aus einer Funktion herausnehmen.

Wartung und Weiterentwicklung, sowohl eines kompletten Programms als 
auch einer spezifischen Funktion, werden mit globalen Variablen 
erschwert. Je kleiner man den Sichtbarkeitsbereich von Variablen 
gestalten kann, desto leichter ist zu überblicken, was mit diesen 
Variablen wann, wo und warum passiert.

Im Hinblick auf Weiterverwendbarkeit von Funktion sind globale Variablen 
eigentlich immer kontraproduktiv.


Klar ist allerdings auch, dass man dieses Dogma der Nichtbenutzung von 
globalben Variablen auf einem µC wie einem (kleineren) AVR nicht 
vernünftig durchziehen kann. IRQ-Kommunikation ist eine Sache, die 
Überschaubarkeit des SRAM Verbrauchs ist eine andere Sache. Hier haben 
globale Variablen den Vorteil, dass man schon zur Compilezeit schon 
abschätzen kann, welchen Speicherverbrauch das Programm wirklich haben 
wird.

Ich versuch die Sache so zu halten:
Schleifenvariablen bleiben funktionslokal. Benötigt eine Funktion nur 
wenige lokale Variablen, dann mach ich das auch. Extensive 
Datenstrukturen werden global angelegt.

von Phillip H. (philharmony)


Lesenswert?

Nochmal zwischendruch vielen vielen Dank für die zahlreichen Tips und 
hilfen. Ich bin in meiner Denkweise glaube ich noch nicht so wirklich 
auf C getrimmt, wenn ich auch dem PC programmiere sind mir ein paar 
Bytes oder Taktzyklen total egal, auf nCs sieht das ganze scho necht 
anders aus.
Den Vorschlag von Karl Heinz finde ich total super, hab da auch schon 
ein bisschen rumprobiert.
Mein Problem liegt auch gar nicht in Code selbst, in dem habe ich ja 
eigentlich auch nur total simple Funktionen.
Mein Problem hängt eher in dem Setup-File, daß ich einbinden möchte, in 
dem die Pinvergabe gesetzt wird.
Die soll übersichtlich und auch für nicht-Programmierer einfach 
bearbeitbar sein. Ich würde also eine Reihe #defines benutzen:
1
#define ENABLED = 1;
2
#define DISABLED = 0;
3
4
#define PA_IN_PIN_0 ENABLED;
5
#define PA_IN_PIN_1 DISABLED;
6
...
7
#define PA_OUT_PIN_0 DISABLED;
8
#define PA_OUT_PIN_1 ENABLED;
9
//Das sollte eigentlich jeder verstehen.
Mein Problem fängt jetzt an, wenn ich die je 8 "ENABLED" und "DISABLED" 
Pins, zu der angesprochenen Maske zusammenfassen will.
Mit
1
#define PA_DDR_MASKE ((PA_OUT_PIN_0)|(PA_OUT_PIN_1<<1)|(PA_OUT_PIN2<<2)|...)
Klappt das nicht, ich bekomme an der Stelle in der Init-Funktion (wo 
auch der USART initialisiert wird etc), in der ich das DDRA dann mit der 
Maske setzen will die Fehlermeldung "...expecting ')' before ';' token"
1
DDRA = PA_DDR_MASKE;
Wenn ich an der stelle DDRA = 0x01; oder sowas setze geht es, also nehme 
ich an daß das Makro so nicht funktioniert. Kann ich das überhaupt vom 
Präprozessor machen lassen und wie?

von Karl H. (kbuchegg)


Lesenswert?

Phillip Hommel schrieb:

>
1
> #define ENABLED = 1;
2
> #define DISABLED = 0;
3
>
Wenn schon, dann

1
#define ENABLED    1
2
#define DISABLED   0

und
1
#define PA_IN_PIN_0 ENABLED
2
#define PA_IN_PIN_1 DISABLED

Das ganze hat nichts mit globalen Variablen zu tun, sondern einzig und 
alleine mit der Textersetzung des Präprozessors.
1
#define PA_DDR_MASKE ((PA_OUT_PIN_0)|(PA_OUT_PIN_1<<1)|(PA_OUT_PIN2<<2)|...)

Na, ob das leichter zu verstehen ist?
Das Problem für den 'Programmier-Anwender' ist ja nicht welcher Pin 
'enabled' ist oder 'nicht enabled' ist. Wenn du einen Code von jemand 
anderem bekommst, lautet die Fragestellung praktisch immer:
"Meine Hardware ist an diesem Pin angeschlossen. Wie teile ich das dem 
Programm mit."

von Phillip H. (philharmony)


Lesenswert?

OOOOOH man, klar, das Semikolon war das Problem.
Ja das sind keine Globalen Variablen mehr, das hatte ich ja inzwischen 
verstanden und versuche es nun nach einem Alternativ-vorschlag zu 
machen.
Der "Anwender" in meinem Fall bekommt eigentlich eine GUI, im Extremfall 
soll das bestehende setup-file zwischen
"////changes only below this line///"
und
"////do not change anything below this line////"
von hand in sofern geändert werden, daß in diese Zeilen eingetragen 
wird, an welchen Pins ein Schalter hängt, an welchen eine LED, an 
welchen ein Poti, ein Drehencoder oder PWM und 7Segment displays.
ENABLED bedeutet dabei einfach, "dieser Pin ist für die IN-Funktion 
(Schalter) aktiviert".
Das lange Marko braucht nicht vom Anwender verstanden werden, er ändert 
einfach nur
PA_IN_PIN_x
...
PB_IN_PIN_x
...
PC_IN_PIN_x
...
ADC_IN_PIN_x (ich weiß, hier muß ich noch prüfen daß nicht der gleiche 
pin für den IO und für den ADC Betrieb ENABLED wird, die GUI lässt sowas 
gar nicht zu).
...
GRAY_IN_PIN (immer 2)
...
PA_OUT_PIN_x
...
usw

Der rest soll eben im Code varbaut werden, aber natürlich auch da so 
übersichtlich und reproduzierbar/flexibel wie möglich.

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.