Hallo, drehe mich bei folgendenm Problem im Kreis. Variable "P" wird nicht übernommen; void setPort (char P, char bit) { P |= (1<<bit); } int main(void) { // mach was setPort(PORTB, 0); // mach was } Sobald ich in der oberen Funktion " PORTB |= (1<<bit); " einsetze, funktioniert die Zuweisung!
@bersison bitte unterlasse es in Zukunft den Threadtitel mit einem Unterstrich zu beginnen.
Schlag mal dein C-Buch im Kapitel "call by value <-> call by reference" auf und guck nach wie PORTB definiert ist.
zusätzlich zum Vorredner - achte auch darauf, wie schwer dein Compiler flucht. Dazu solltest du ihm das Fluchen erlauben (-Wall)
troll schrieb: > Schlag mal dein C-Buch im Kapitel "call by value <-> call by reference" > auf und guck nach wie PORTB definiert ist. Leider habe ich diesen Hinweis nicht verstanden. Geht´s auch etwas konkreter? Aus einem der Fachbücher habe ich den Tip. PORTB 0-7 ist als Ausgang definiert! Es kommen keine Warnmeldungen vom Compiler.
Hinweis 1 >>> "call by value <-> call by reference" <<< Hinweis 2 >>> guck nach wie PORTB definiert ist <<< Now it's your turn.
Darf man denn fragen was du eigentlich vorhast? Anders gefragt: Erfordert dein Vorhaben wirklich eine solche Funktionalität zur Laufzeit? Das schaut für mich nämlich (ohne den genauen Kontext zu kennen) eher nach einer Angelegenheit für ein Makro aus. Das würde dann nämlich während des Kompilierens expandiert werden und würde dir neben dem o.g. Problemen auch "Rechenzeit" einsparen.
__Son´s Bersi__ schrieb: > Leider habe ich diesen Hinweis nicht verstanden. Die Argumente einer Funktion sind immer eine Kopie. Wenn Du nun die Kopie änderst, ist das dem Original völlig wurscht. Es gibt nun 3 Lösungen: 1. Man weißt den Returnwert wieder dem Original zu. 2. Man übergibt einen Pointer auf das Original. 3. Man nimmt keine Funktion, sondern ein Macro.
Wenn du was an eine Funktion übergeben willst, dann soltest du dir auch gedanken darüber machen was du da wirklich übergibts! Also: was glaubst du, was "PORTB" ist? ... und nein, die Antwort ist nicht "42"!
Kaj schrieb: > Wenn du was an eine Funktion übergeben willst, dann soltest du dir auch > gedanken darüber machen was du da wirklich übergibts! > > Also: was glaubst du, was "PORTB" ist? > > ... und nein, die Antwort ist nicht "42"! nicht "42"? komisch... Die Originalidee habe ich aus einem Fachbuch, welches als Makro geschrieben war. Mir geht es jetzt aber um eine Funktion mit gleichem Inhalt! Konkrete Antworten auf folgende Fragen habe ich mir HIER erhofft; Was ist "PORTB" und vor allem, wie kann es an eine Variable übergeben werden?
__Son´s Bersi__ schrieb: > Was ist "PORTB" und vor allem, wie kann es an eine Variable übergeben > werden? http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_port_pass
__Son´s Bersi__ schrieb: > Was ist "PORTB" und vor allem, wie kann es an eine Variable übergeben > werden? Für Dich ist nicht relevant, was PORTB genau ist. Du kannst es wie eine globale Variable nutzen. Du hast schon einen grundsätzlichen Denkfehler an anderer Stelle:
1 | void meine_funktion(int x) |
2 | {
|
3 | x = 5; |
4 | }
|
5 | |
6 | int main(void) |
7 | {
|
8 | int a = 2; |
9 | meine_funktion(a); |
10 | printf("%i", a); |
11 | }
|
Was kommt da raus? 2. Warum? Weil an die Funktion der Inhalt von a übergeben wird. Also der Wert 2. Dass der vorher in der Variable a gestanden hat, weiß die Funktion nicht. Sie bekommt eine Kopie dieses Werts in der Variable x. Das ist eine neue Variable, die nur innerhalb von meine_funktion gültig ist. Diese neue Variable setzt sie auf 5 und kehrt zurück. Beim Zurückkehren der Funktion verliert x auch schon wieder seine Gültigkeit. Damit macht meine_funktion im Prinzip überhaupt nichts. Der Compiler wird das komplett wegoptimieren.
Fabian O. schrieb: > Für Dich ist nicht relevant, was PORTB genau ist. Du kannst es wie eine > globale Variable nutzen. Du hast schon einen grundsätzlichen Denkfehler Danke für die Info, aber bei meinem Bsp wird eine 0 oder 1 zurück gegeben. void setPort (char P, char bit) { P |= (1<<bit); } int main(void) { // mach was if (setPort(PORTB, 0) { // mach was } } Ich bin mir nicht sicher, ob der Fehler darin liegt, dass es sich bei der "PORTB"-Übergabe, um einen reinen String handelt, ich ihn aber als char-Wert deklariert habe? Ich werde morgen mal folgende Variante ausprobieren; void setPort (volatile char P, char bit)
__Son´s Bersi__ schrieb: > Die Originalidee habe ich aus einem Fachbuch, welches als Makro > geschrieben war. Mir geht es jetzt aber um eine Funktion mit gleichem > Inhalt! Tja, und jetzt weißt du, warum es ein Makro war. Mit einer Funktion geht das so nicht. __Son´s Bersi__ schrieb: >> Für Dich ist nicht relevant, was PORTB genau ist. Du kannst es wie eine >> globale Variable nutzen. Du hast schon einen grundsätzlichen Denkfehler > > Danke für die Info, aber Nichts "aber"! Fabians Erklärung paßt genau. > bei meinem Bsp wird eine 0 oder 1 zurück gegeben. Nein. Der Return-Typ von setPort ist void, also wird nichts zurückgegeben. > void setPort (char P, char bit) { > P |= (1<<bit); } > int main(void) { // mach was > if (setPort(PORTB, 0) { // mach was } } Da müßtest du eigentlich eine Fehlermeldung vom Compiler bekommen, da setPort nicht den passenden Rückgabetyp hat. Ist das wirklich der Code, den du genau so durch den Compiler hast laufen lassen? > Ich bin mir nicht sicher, ob der Fehler darin liegt, dass es sich bei > der "PORTB"-Übergabe, um einen reinen String handelt, ich ihn aber als > char-Wert deklariert habe? Was für ein String? In deinem Programm kommt nichts vor, das auch nur im entferntesten was mit Strings zu tun hätte. > Ich werde morgen mal folgende Variante ausprobieren; > void setPort (volatile char P, char bit) Das wird genau gar nichts bringen. Lies nochmal die Erklärung von Fabian und denke darüber nach.
Fabian O. schrieb: > __Son´s Bersi__ schrieb: >> Was ist "PORTB" und vor allem, wie kann es an eine Variable übergeben >> werden? > > Für Dich ist nicht relevant, was PORTB genau ist. Ja und nein. Ich kann seine Denkweise schon irgendwo auch verstehen. Seine Denkweise ist: ich übergebe den Port an die Funktion und die Funktion soll mir das Bit setzen. Und genau da kommt jetzt das ins Spiel, was Fabian angesprochen hat. Hier
1 | int main() |
2 | {
|
3 | setPort(PORTB, 0); |
4 | }
|
wird ja nicht der Port selber übergeben, sondern der momentane Wert der 'Variablen' PORTB. Die Lösung kommt jetzt daher, dass die ganzen Sache von den WinAVR bzw. Atmel Leuten so vorbereitet wurde, dass man auch von PORTB die Adresse nehmen kann. D.h. PORTB kann man sich tatsächlich, auch wenn es sich hier um Hardware handelt, wie eine Variable vorstellen (auch wenn es in Wirklichkeit keine ist). Und ab da kommen dann alle C-Dinge ins Spiel, die bereits angesprochen wurden und die sich um Argumentübergabe drehen. Man will an dieser Stelle beim Aufrufer eben nicht den momentanten Wert der 'Variablen' PORTB übergeben, sondern man will die Funktion in die Lage versetzen, die 'Variable' selbst zu verändern. In völliger Analogie zu
1 | void foo( unsigned char * a ) |
2 | {
|
3 | *a = 5; |
4 | }
|
5 | |
6 | int main() |
7 | {
|
8 | unsigned char wert = 2; |
9 | |
10 | foo( &wert ); |
11 | }
|
und PS: der für einen C-Programmierer relevante Datentyp für PORTB lautet "volatile unsigned char". Und Bersi. Ich glaub ich hab dir das schon mal gesagt: Dein µC-Fachbuch ist schön und gut (und auf jeden Fall besser als nichts). Aber du wirst da drinnen nur die Hälfte des für dich relevanten C-Sprachstandards finden. Ok, Argument Passing soltle eigentlich etwas ausführlicher beschrieben sein, weil es nun mal extrem wichtig ist, aber ich kenne auch derartige Sprach-Kurzeinführungen. Die sind oft nur Lückenbüsser, weil es sich auf dem Buchumschlag nun mal gut macht, wenn dort steht "Mit einer Einfführung in C". Aber die Sprache wird dort nicht angemessen beschrieben bzw. erklärt, weil man ja schnellstmöglich zum eigentlichen Thema des Buches übergehen will, der nun mal µC-Programmierung lautet. D.h. die Sprachbeschreibungen in solchen Büchern sind oft tatsächlich nur halbherzig und im Grunde sollte man so vergehen als ob sie nicht vorhanden wären und zum Studium eines derartigen Buches bereits Sprachkentnisse vorausgesetzt werden. Aus dem, was in diesen Büchern beschrieben ist, lernt man die Sprache meistens nicht ausreichend gut genug. Daraus folgt: Du wirst um ein dezidiertes C-Buch nicht herumkommen. Ein derartiges Buch hat auch nicht ohne Grund 200 Seiten. 200 Seiten, die du in deinem µC-Fachbuch aus naheliegenden Gründen nicht finden wirst, obwohl die Hälfte davon eigentlich auf jeden Fall notwendig wäre.
Karl Heinz Buchegger schrieb: > Und Bersi. > > Ich glaub ich hab dir das schon mal gesagt: Dein µC-Fachbuch ist schön > > und gut (und auf jeden Fall besser als nichts). Aber du wirst da drinnen > > nur die Hälfte des für dich relevanten C-Sprachstandards finden. Hallo Karl Heinz, deine Ausführungen "treffen den Nagel auf den Kopf"! Mir liegen 2 Fachbücher über AVR+C vor. Hier springe ich dauernd, weil viele Themen oberflächlich durchschritten werden, um zu konkreten Projekten(die mich nicht interessieren) zu kommen. Meine nächste Anschaffung wird auf dein Anraten ein Fachbuch für C sein. Hier entweder; (1) Die Programmiersprache C, ISBN 10 3540237852, 9,95€ (2) Programmieren in C, ISBN 3446154973, 29€ (3) C: Programmieren von Anfang an, ISBN 10 3499600749, 11,99€ Deine/Eure Tips werde ich zeitnah ausprobieren - DANKE!
so, es ist vollbracht und funktioniet einwandfrei; void setPort(volatile unsigned char *P, char bit) { *P |= ~(1<<bit); } int main(void) { setPort(&PORTB, 0); // etc. }
Ich bin für
> (2) Programmieren in C, ISBN 3446154973, 29€
Hallo, hier kommt noch ein Folgeproblem. Wie kann der "PORTB" als Variable über mehrere Funktionen weitergereicht werden? BSP: Obwohl setPort() und clrPort() einwandfrei funktionieren, reicht inpWeit() die Variablen nicht weiter;
1 | -----------------------------------------------
|
2 | void setPort(volatile unint8_t *P, uint8_t bit) |
3 | {
|
4 | *P |= (1<<bit); |
5 | }
|
6 | |
7 | void clrPort(volatile unint8_t *P, uint8_t bit) |
8 | {
|
9 | *P &= ~(1<<bit); |
10 | }
|
11 | |
12 | uint16_t impWeit(volatile unint8_t *P, uint8_t bit, uint16_t high, uint16_t low) //Impulsweitensteuerung |
13 | {
|
14 | setPort(*P,bit); //setzt Ausgang high |
15 | warte_ms(high); //Warteschleife |
16 | setPort(*P,bit); //setzt Ausgang low |
17 | warte_ms(low); //Warteschleife |
18 | }
|
19 | |
20 | int16_t main(void) |
21 | {
|
22 | while(1) |
23 | {
|
24 | impWeit(&PORTB, 1, 10, 20); |
25 | }
|
26 | return 0; |
27 | }
|
------------------------------------------------
__Son´s Bersi__ schrieb: > BSP: Obwohl setPort() und clrPort() einwandfrei funktionieren, reicht > inpWeit() die Variablen nicht weiter; Orientier dich an den Datentypen > setPort(*P,bit); //setzt Ausgang high Was will die Funktion haben? Sie will void setPort(volatile unint8_t *P, uint8_t bit) einen Pointer haben: volatile unint8_t *P Was hast du? Was ist der Datentyp deines P in der Funktion hier? uint16_t impWeit(volatile unint8_t *P, uint8_t bit, uint16_t high, uint16_t low) P ist ein volatile unint8_t *P, ist also auch ein Pointer. Was willst du weitergeben? Die Adresse, die im Pointer gespeichert ist, oder den Wert der sich unter dieser Adresse im Speicher verbirgt? (Also: die Adresse von PORTB, oder den momentanten Wert, der am PORTB anliegt?) Du willst die Adresse weitergeben. Denn 1) bringt dir der Wert nichts 2) will die Funktion ja die Adresse haben. ( 2) ist eine direkte Folge von 1). 2) könnte natürlich auch durch einen falschen Funktionsaufbau zustande kommen. Daher muss man an dieser Stelle auch überlegen, ob es überhaupt richtig ist, dass die Funktion einen Pointer nimmt oder ob nicht dieses Detail falsch implementiert ist. Aber in deinem Fall folgt 2) direkt aus 1) und ist daher als 'Forderung' korrekt.) Daher die Frage: Wozu der * in setPort(*P,bit); der * würde den Pointer dereferenzieren und dir den Wert an der Adresse von P liefern (also das was am PORTB anliegt). Das willst du aber gar nicht! Du willst ja die Adresse von PORTB weitergeben. Deshalb nimmt ja auch die Funktion eine Pointer und keinen uint8_t Ergo setPort( P, bit ); denn P enthält ja bereits diese Adresse! nicht einfach nur in Funktionen wahllos irgendwelche * und & einstreuen. BIssi nachdenken, wie die Dinge zusammenhängen. Es ist alles völlig logisch! Bei Pointern muss man immer unterscheiden zwischen * will ich mit dem Pointer selber, als mit der in ihm gespeicherten Adresse arbeiten * oder meine ich den Wert, der von dieser Adresse referenziert wird. Du kannst dir das ganze Pointer/Adressen Ding wie eine Bibliothek vorstellen. Die Bücher in den Regalen, das sind deine Werte im Speicher. Pointer sind einfach nur die Karteikarten, auf denen steht, wo (Gang/Regal/Platz) ein Buch zu finden ist. Worum dreht es sich bei einer Operation: Ist das eine Operation mit der Karteikarte (die Kartekarte an einen anderen Leser weitergeben) oder ist es eine Operation mit dem Buch selber (welches 'gefunden' wird, indem man die Ortsangabe auf der Karteikarte auswertet). In deinem Beispiel gibt eine Funktion die Karteikarte selber an die nächste Funktion weiter. Und erst die letzte in der Kette schaut auf die Karte (macht den *) um das Buch ausfindig zu machen, in welchem sie etwas eintragen soll.
Karl Heinz Buchegger schrieb: > Ergo > setPort( P, bit ); > denn P enthält ja bereits diese Adresse! Funktioniert! Karl Heinz Buchegger schrieb: > Orientier dich an den Datentypen Zeigt mir, dass ich mich sehr viel intensiver mit dem Thema Datentyp/Pointer auseinander setzen muss!
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.