www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik fehler mit funktionen in c


Autor: pille1990 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich beschäftige mich im moment mit funktionen in c. nun wollte ich das 
auch mal ausprobieren und wenn ich dieses programm dann kompiliere, 
kommt immer folgender fehler:

C:\Users\Benedikt\Documents\default/../test2.c:15: undefined reference 
to `funktion'
make: *** [test2.elf] Error 1
Build failed with 1 errors and 0 warnings...

zeile 15 ist da wo die funktion mit dem namen "funktion" aufgerufen 
wird.


#include <avr/io.h>

void funktion();

int main(void)
{

while(1)
  {

  DDRD = 0xff;

  PORTD = 0xff;
  
  funktion();

  PORTD = 0x00;
  }
  
  void funktion()
  {
  PORTD &= ~(1 << PA0);
  }
  
}


was mache ich da falsch?
wo liegt hier der fehler?

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Unter Umständen wärs sinnvoll, die 'funktion' auch im richtigen 
Namensraum zu definieren...
#include <avr/io.h>

  void funktion()
  {
  PORTD &= ~(1 << PA0);
  }

int main(void)
{

while(1)
  {

  DDRD = 0xff;

  PORTD = 0xff;
  
  funktion();

  PORTD = 0x00;
  }
 
  
}

Autor: Roland Praml (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
#include <avr/io.h>

void funktion1(); // dies ist ein Prototyp, welcher später definiert wird
void funktion2()  // diese Fkt wird hier sofort definiert
{
  PORTD &= ~(1 << PA0);
}


int main(void)  // dies ist die Main-Fkt. In dieser können AFAIK keine weiteren definiert werden
{
while(1)
  {
  DDRD = 0xff;
  PORTD = 0xff;
  
  funktion1();
  funktion2();

  PORTD = 0x00;
  }
}

void funktion1() // hier wird die Funktion im zuvor angelegten Prototyp definiert
{
  PORTD &= ~(1 << PA0);
}
soweit klar?
Gruß
Roland

Autor: pille1990 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
danke für die hilfe...nach 2 stunden verzweifeltem probiern und im 
internet lesen habt ihr mir das sehr gut erklärt...danke!!!

Autor: Georg W. (gewe)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo pille1990,

wenn Du Prototyping machst, muss die entsprechende Funktion im gleichen 
Gültigkeitsbereich liegen, d.h. außerhalb von main().

Wenn Du funktion() vor main() einfügst, brauchts Du nicht einmal das 
Prototyping.

Außerdem würde ich void funktion(void) schreiben. Ahnliches gilt für int 
main(void). Hier fehlt der Rückgabewert oder Du schreibst void main 
(void).

Mit diesem Hinweisen kannst Du das Programm fehlerfrei übersetzen.

Wobei ich aber den Sinn des Programms nicht sehen kann.

PS: Falls Du den Port D immer als Ausgang nutzen möchtest, genügt es die 
Datenrichtungsbits einmal vor der Hauptschleife zu beschreiben.

PPS: Wie lange bleibt Port D 0xff bzw. 0x00?

cu
Georg

Autor: pille1990 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
das programm war einfach nur zum testen wie das mit den funktionen 
funktioniert....
jetzt habe ich aber ein sinnvolleres programm geschrieben...bei dem ich 
aber schon wieder ein problem habe.

ich will einen zähler realisieren, der die tastendrücke eines tasters 
zählt und diese dann auf einem port ausgibt.
dazu frage ich einfach den taster ab
#include <avr/io.h>

#define TASTER PC0
#define EINGANG PINC
#define AUSGANG PORTD

void press()
  {
  
  while(!EINGANG & (1 << TASTER));      //solange in der while schleife laufen, bis der taster gedrückt ist
  i++;
  AUSGANG = i;
  }

void release()
  {
  while(EINGANG & (1 << TASTER));    //solange in der while schleife laufen, bis der taster wieder losgelassen wird
  }

void main(void)
{
  DDRC = 0x00;
  DDRD = 0xff;

  
  
  while(1)
  {

  int i;
  i = 0;

  press();

  release();
  }
  
}

nun zum problem:
da ich ja die variable "i" in der main funktion deklariert habe, ist sie 
in der press funktion nicht verfügbar.
ich will aber nun, dass die variable auch in der press funktion 
verfügbar ist ohne dort die folgenden programmzeilen zu schreiben:
int i;
i = 0;

da gibt es doch für die funktionen diese parameter...aber irgendwie 
verstehe ich nicht wie man diese hier einsetzt.

noch eine frage:
warum bekomme ich vom compiler einen fehler wenn ich die funktion 
"press" und "release" nach der main funktion deklariere?

Autor: Matthias Nix (vbchaos)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
pille1990 wrote:
> nun zum problem:
> da ich ja die variable "i" in der main funktion deklariert habe, ist sie
> in der press funktion nicht verfügbar.
> ich will aber nun, dass die variable auch in der press funktion
> verfügbar ist ohne dort die folgenden programmzeilen zu schreiben:

Stichwort: Globale Variable. Dazu schreibst du das int i = 0; einfach 
außerhalb der Funktionen, sinnvollerweise über die erste Funktion und 
unter die includes. Dort findet man globale definitionen am einfachsten 
wieder. Irgendwo im AVR Tutorial werden globale Variablen sicherlich 
erklärt.
Edit (Der Ordnung halber): Mit Übergabewerten (Parametern) an Funktionen 
hat das nichts zu tun.

> noch eine frage:
> warum bekomme ich vom compiler einen fehler wenn ich die funktion
> "press" und "release" nach der main funktion deklariere?

Weil: Dein compiler geht das von oben nach unten durch. Wenn er in einer 
funktion, bei dir die main, einen aufruf sieht, den er noch nicht kennt 
(weil eben weiter unten definiert), macht er n warning, weil er den 
aufruf nicht kennt. Ausführen lässt sich das ganze trotzdem, weil der 
Compiler wahrscheinlich mehrere durchgänge macht (zwecks optimierung), 
daher auch nur eine Warning und kein Error. Er möchte dich quasi sanft 
darauf hinweisen, dass dein Programmierstil da noch Nachbesserung 
vertragen könnte :) Daher also: Wenn du aufrufe machst auf funktionen, 
die später erst definiert werden, macht man oben (unter includes, über 
die erste funktion) einen Prototyp der noch kommenden funktionen. In 
deinem Fall: void press (void);

Autor: Georg W. (gewe)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo pille1990,

übersetzen lässt sich:
#include <avr/io.h>

..

void press(int i)
  {
  
  while(!EINGANG & (1 << TASTER));      //solange in der while schleife laufen, bis der taster gedrückt ist
  i++;
  AUSGANG = i;
  }

...

void main(void)
{
  DDRC = 0x00;
  DDRD = 0xff;
  
  while(1)
  {

  int i;
  i = 0;

  press(i);
  release();
  }
  
}


Funktioniern wird das aber auch nicht, da bei jedem Durchlauf der 
while-Schleife i auf 0 gesetze wird. D.h. für i gilt das selbe wie für 
DDRD,

#include <avr/io.h>

...

void main(void)
{
  int i;
  i = 0;

  DDRC = 0x00;
  DDRD = 0xff;
  
  while(1)
  {

  press(i);
  release();
  }
  
}


Du wirst aber Probleme bekommen weil der Ausgabeport 8 Bit "breit" ist, 
du aber einen 16 Bit Integer zuweist.

Um solche Knackpunkte zu vermeiden werden in der stdint.h die Datentypen 
mit der Bitbreite definiert:



typedef signed char  int8_t
typedef unsigned char  uint8_t
typedef signed int  int16_t
typedef unsigned int  uint16_t
typedef signed long int  int32_t
typedef unsigned long int  uint32_t
typedef signed long long int  int64_t
typedef unsigned long long int  uint64_t

Wenn Du i als uint8_t deklarierst, läufst Du hier nicht in ein 
Überlaufproblem hinein.

cu
Georg

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Achso, nochwas: 'void main()' ist in C99 nicht erlaubt.

C99 final draft:
5.1.2.2.1 Program startup 
The function called at program startup is named main. The implementation declares no
prototype for this function. It shall be defined with a return type of int and with no
parameters:
int main(void) { /* ... */ } ...

Autor: Georg W. (gewe)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Sven,

stimmt. Achse auf mein Haupt.

Das kommt davon, wenn man Tips nicht ausprobiert.

Beim Compilieren kommt ja auch eine entsprechende Warnung.

Somit sollte es dann heißen int main (void) und am Ende nach der while 
Schleife noch ein return (0) z.B.

cu
Georg

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Georg Werner wrote:
> @Sven,
>
> stimmt. Achse auf mein Haupt.
Aber ne schwere Achse, damit es richtig weh tut ;-)

> Somit sollte es dann heißen int main (void) und am Ende nach der while
> Schleife noch ein return (0) z.B.
Erstens ist das return am Ende überflüssig, da main, wenn es auf einem 
µC ohne OS läuft, nirgendwohin etwas zurückgeben kann. Zweitens steht 
das return hinter einer Endlosschleife und wird sowieso nie erreicht 
(weshalb manch ein Compiler dabei sogar eine Warnung ausspuckt, dass da 
Code steht, der nie erreicht wird). Drittens ist return keine 
Funktion, was ein Grund dafür ist, dass sein Argument nicht in 
Klammern eingeschlossen wird. OK, es funktioniert auch mit Klammern, 
aber die korrekte Schreibweise ist einfach "return ausdruck;"

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johannes M. wrote:

> Erstens ist das return am Ende überflüssig, da main, wenn es auf einem
> µC ohne OS läuft, nirgendwohin etwas zurückgeben kann. Zweitens steht
> das return hinter einer Endlosschleife und wird sowieso nie erreicht
> (weshalb manch ein Compiler dabei sogar eine Warnung ausspuckt, dass da
> Code steht, der nie erreicht wird). Drittens ist return keine
> Funktion, was ein Grund dafür ist, dass sein Argument nicht in
> Klammern eingeschlossen wird. OK, es funktioniert auch mit Klammern,
> aber die korrekte Schreibweise ist einfach "return ausdruck;"

und viertens ist main die grosse Ausnahme.
Auch wenn main einen Returntyp von int hat, ist es zulässig das return 
am Ende wegzulassen. Der Compiler muss sich selbst ein
 return 0;
dazudenken

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.