seltsamer Fehler nach Speichern: Programmname = reservierter Befehl

hallo, ein seltsamer Fehler nach Speichern: Programmname = reservierter Befehl

ich habe Sketch 1.5.6.r2 mit 2009. ich habe eine Testprogramm mit Tönen "Tone" genannt, und nach dem Speichern erhalte ich die Fehlermeldung:en

Arduino: 1.5.6-r2 (Windows XP), Board: "Arduino Duemilanove or Diecimila, ATmega168"

Build options changed, rebuilding all

Tone.cpp.o: In function setup': C:\Programme\Arduino/Tone.ino:133: undefined reference totone(unsigned char, unsigned int, unsigned long)' C:\Programme\Arduino/Tone.ino:140: undefined reference to `noTone(unsigned char)'

Dieser Report hätte mehr Informationen mit "Ausführliche Ausgabe während der Kompilierung" aktiviert in Datei > Einstellungen

speichere ich es unter anderem Namen - no prob. :astonished: seltsam, oder?

HaWe: seltsam, oder?

Ja, Du bist genau so genial wie die Arduino-Entwickler! Und nennst ein Programmmodul, das etwas mit Tönen zu tun hat, "Tone". Die Arduino-Entwickler und Du, ihr seid beide genial im Ausdenken von Namen!

Aber wenn so viel Genialität gleichzeitig aufeinanderprallt, gibt es nun mal Probleme.

haha, jurs, also hör mal …
ich kann doch jedes C-Programm (mit gpp C/C++, devcpp, oder was auch immer erstellt) unter jedem beliebigen Namen speichern!
Das wär ja noch schöner, wenn ich da keine reservierten Wörter aus der Programmiersprache selber verwenden dürfte.
Was hat das eine mit dem anderen zu tun?!

Kann ja wohl nicht dein Ernst sein!

HaWe:
ich kann doch jedes C-Programm (mitgpp C/C++, devcpp, was cu immer erstellt) unterjedem beliebigen Namen speichern!
Das wär ja noch schöner, wenn ich da keine reservierten Wörter verwenden dürfte.
Was hat das eine mit dem anderen zu tun?!

Das würde ich an Deiner Stelle mal nachprüfen, ob Du wirklich “jedes C-Programm (mitgpp C/C++, devcpp, was cu immer erstellt)” beispielsweise unter dem Namen Tone.cpp abspeichern kannst UND DANN in dieses Programm noch eine C+±Library inkludiert werden kann, bei der die Headerdatei Tone.h und die Librarydatei ebenfalls Tone.cpp heißt wie das Hauptprogramm.

Nur weil Du in Deinen “Sketch” die Zeile “#include <Tone.h>” nicht mit reinschreibst, heißt das ja nicht, dass diese Zeile nicht kompiliert werden soll. Sobald Du Deine tönenden Funktionen im Sketch verwendest, baut die Arduino-Software automatisch in den kompilierten Code ein “#include <Tone.h>” ein, auch wenn Du vergessen haben solltest, diese Include-Zeile reinzuschreiben.

Tatsächlich wird die namensgleiche C++ Librarydatei Tone.cpp dann wegen der Namensgleichheit nicht inkludiert, und sämtliche Funktionen aus dieser Librarydatei fehlen dann im Programm und sind nicht vorhanden.

Der wesentliche Unterschied zu “normalen” C+±Compilern ist: Normale C+±Compiler zeigen Warnings und Errors an. Die Arduino-Software unterschlägt sämtliche Warnings und zeigt nur die Errors. Und daher wird beim Fehlschlagen des Library-Imports kein Warning angzeigt, sondern erst der Error, dass eine von Dir verwendete Funktion nicht vorhanden ist.

ich habe keine Datei Tone.h , und ich #include sie ntl dann auch nicht - wie kommst du auf diese Idee?

Aber auch in C ist es möglich, ein programm "void" oder "printf" zu nennen, und auch einen headerfile mit identischem Namen, also z.B. ein printf.h zu haben (als header) und zusätzlich ein printf.c zu kompilieren (was den compilierbaren bzw. make/link-baren Code enthält). Es ist sogar üblich in C, .h Headerfiles mit den Befehls-Prototypen und gleichnamige .c files mit dem ausgeschriebenen Code identisch zu benennen. Also nochmal: Dateinamen und Keywords haben doch nichts mit einander zu tun!

Das kann was damit zu tun haben was die IDE im Hintergrund macht. Da wird sehr viel automatisch eingefügt und einiges herumkopiert und zusammengefügt von dem man nichts mitbekommt. Damit das alles einfacher wird, funktioniert das Ganze etwas anders als in Standard C/C++ IDEs.

HaWe: ich habe keine Datei Tone.h , und ich #include sie ntl dann auch nicht - wie kommst du auf diese Idee?

Stimmt, es gibt keine Tone.h, sondern nur eine Tone.cpp und die findest Du unter den Core-Files: C:\Arduino-Pfad\hardware\arduino\cores\arduino

HaWe: Aber auch in C ist es möglich, ein programm "void" oder "printf" zu nennen, und auch einen headerfile mit identischem Namen, also z.B. ein printf.h zu haben (als header) und zusätzlich ein printf.c zu kompilieren (was den compilierbaren bzw. make/link-baren Code enthält).

Du kannst ein Programm "printf.c" nennen, und in dieses Programm kannst Du dann nochmal eine Library mit einer anderen printf.c inkludieren? Merkwürdig!

HaWe: Nochmal: Dateinamen und Keywords haben doch nichts mit einander zu tun!

Nein, Dateinamen und Keywords haben nichts miteinander zu tun. Nur Dateinamen und Dateinamen.

also, damit dus glaubst zum Thema “gleichnamige .h headers und .c files” - das ist absoluter C-Standard.
Hier: gpp C/C++, CSLite 2009.

Das andere Thema “C-File hat zufällig den gleichen Namen wie ein C-command” hat damit erstmal aber gar nichts zu tun, aber das ist es ja, was in Sketch schiefläuft.
Immerhin steckt da ja auch ne Menge Java dahinter, da wundert mich dann eh nichts mehr ]:smiley:

/*
* \file ev3_timer.c
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * The Initial Developer of this code is John Hansen.
 * Portions created by John Hansen are Copyright (C) 2009-2013 John Hansen.
 * All Rights Reserved.
 *
 */

#include "ev3_timer.h"

static unsigned long long msTimers[NUM_MS_TIMERS];
static unsigned long long usTimers[NUM_US_TIMERS];
static unsigned long long csTimers[NUM_CS_TIMERS];

#define TIMER_INTERVAL 10000 // 10 ms
#define TIMER_10MS     1
#define TIMER_50MS     5
#define TIMER_100MS    10
#define TIMER_250MS    25
#define TIMER_500MS    50
#define TIMER_1SEC     100
#define MAX_CALLBACKS  4

static TimerCallback callBack10ms[MAX_CALLBACKS];
static TimerCallback callBack50ms[MAX_CALLBACKS];
static TimerCallback callBack100ms[MAX_CALLBACKS];
static TimerCallback callBack250ms[MAX_CALLBACKS];
static TimerCallback callBack500ms[MAX_CALLBACKS];
static TimerCallback callBack1s[MAX_CALLBACKS];

static int callBack10ms_count;
static int callBack50ms_count;
static int callBack100ms_count;
static int callBack250ms_count;
static int callBack500ms_count;
static int callBack1s_count;

unsigned long TimerWait(unsigned long Time)
{
  return TimerGetMS() + Time;
}

void TimerReady(unsigned long Timer)
{
  // wait until timer has elapsed
  // do not block other threads
  while (Timer > TimerGetMS())
  {
    usleep(1000);
  }
}

unsigned long Timer(byte Timer)
{
  // slow timer 10 ticks per second
  return FastTimer(Timer) / 10;
}

unsigned long FastTimer(byte Timer)
{
  // centisecond timer (100 ticks per second)
  if (Timer < NUM_CS_TIMERS)
    return TimerGetCS() - csTimers[Timer];
  return 0;
}

void ClearTimer(byte Timer)
{
  if (Timer < NUM_CS_TIMERS)
    csTimers[Timer] = TimerGetCS();
}

void SetTimer(byte Timer, unsigned long Value)
{
  if (Timer < NUM_CS_TIMERS)
    csTimers[Timer] = TimerGetCS() - Value;
}

unsigned long TimerMS(byte Timer)
{
  if (Timer < NUM_MS_TIMERS)
    return TimerGetMS() - msTimers[Timer];
  return 0;
}

void ClearTimerMS(byte Timer)
{
  if (Timer < NUM_MS_TIMERS)
    msTimers[Timer] = TimerGetMS();
}

void SetTimerMS(byte Timer, unsigned long Value)
{
  if (Timer < NUM_MS_TIMERS)
    msTimers[Timer] = TimerGetMS() - Value;
}

unsigned long TimerUS(byte Timer)
{
  if (Timer < NUM_US_TIMERS)
    return TimerGetUS() - usTimers[Timer];
  return 0;
}

void ClearTimerUS(byte Timer)
{
  if (Timer < NUM_US_TIMERS)
    usTimers[Timer] = TimerGetUS();
}

void SetTimerUS(byte Timer, unsigned long Value)
{
  if (Timer < NUM_US_TIMERS)
    usTimers[Timer] = TimerGetUS() - Value;
}

void _timerSigHandler(int sig)
{
  int index = 0;
  static unsigned long counter = 0;

  // Handle the 10ms ones first
  if (counter % TIMER_10MS == 0)
  {
    for (index = 0; index < callBack10ms_count; index++)
    {
      callBack10ms[index](sig);
    }
  }
  // Handle the 50ms ones
  if (counter % TIMER_50MS == 0)
  {
    for (index = 0; index < callBack50ms_count; index++)
    {
      callBack50ms[index](sig);
    }
  }

  // Handle the 100ms ones
  if (counter % TIMER_100MS == 0)
  {
    for (index = 0; index < callBack100ms_count; index++)
    {
      callBack100ms[index](sig);
    }
  }

  // Handle the 250ms ones
  if (counter % TIMER_250MS == 0)
  {
    for (index = 0; index < callBack250ms_count; index++)
    {
      callBack250ms[index](sig);
    }
  }

  // Handle the 500ms ones
  if (counter % TIMER_500MS == 0)
  {
    for (index = 0; index < callBack500ms_count; index++)
    {
      callBack500ms[index](sig);
    }
  }

  // Handle the 1s ones
  if (counter % TIMER_1SEC == 0)
  {
    for (index = 0; index < callBack1s_count; index++)
    {
      callBack1s[index](sig);
    }
  }
  counter++;
}

void _timerCallbackInit()
{
  struct sigaction sa;
  struct itimerval timer;
  memset(&sa, 0, sizeof(sa));
  sa.sa_handler = &_timerSigHandler;
  sigaction (SIGALRM, &sa, NULL);
  timer.it_value.tv_sec = 0;
  timer.it_value.tv_usec = TIMER_INTERVAL;
  timer.it_interval.tv_sec = 0;
  timer.it_interval.tv_usec = TIMER_INTERVAL;
  setitimer(ITIMER_REAL, &timer, NULL);

  // Reset all the counters
  callBack10ms_count  = 0;
  callBack50ms_count  = 0;
  callBack100ms_count = 0;
  callBack250ms_count = 0;
  callBack500ms_count = 0;
  callBack1s_count    = 0;

  // Ensure all pointers are NULL
  memset(callBack10ms,  0, sizeof(TimerCallback) * MAX_CALLBACKS);
  memset(callBack50ms,  0, sizeof(TimerCallback) * MAX_CALLBACKS);
  memset(callBack100ms, 0, sizeof(TimerCallback) * MAX_CALLBACKS);
  memset(callBack250ms, 0, sizeof(TimerCallback) * MAX_CALLBACKS);
  memset(callBack500ms, 0, sizeof(TimerCallback) * MAX_CALLBACKS);
  memset(callBack1s,    0, sizeof(TimerCallback) * MAX_CALLBACKS);
}

void SetTimerCallback(TimerInterval interval, TimerCallback callback)
{
  if (callback != NULL)
  {
    switch(interval)
    {
      case ti10ms:  callBack10ms[callBack10ms_count++] = callback; break;
      case ti50ms:  callBack50ms[callBack50ms_count++] = callback; break;
      case ti100ms: callBack100ms[callBack100ms_count++] = callback; break;
      case ti250ms: callBack250ms[callBack250ms_count++] = callback; break;
      case ti500ms: callBack500ms[callBack500ms_count++] = callback; break;
      case ti1sec:  callBack1s[callBack1s_count++] = callback; break;
    }
  }
}

void TimerInit()
{
  unsigned long long csTick, msTick, usTick;
  int i;
  usTick = TimerGetUS();
  msTick = usTick / 1000;
  csTick = msTick / 10;
  for (i=0; i < NUM_US_TIMERS; i++)
    usTimers[i] = usTick;
  for (i=0; i < NUM_MS_TIMERS; i++)
    msTimers[i] = msTick;
  for (i=0; i < NUM_CS_TIMERS; i++)
    csTimers[i] = csTick;
  // also initialize our callback timers
  _timerCallbackInit();
}

unsigned long long TimerGetUS()
{
  struct timeval tv;
  gettimeofday(&tv, 0);
  return (((unsigned long long)tv.tv_sec) * 1000000) + tv.tv_usec;
}

unsigned long long TimerGetMS()
{
  struct timeval tv;
  gettimeofday(&tv, 0);
  return (((unsigned long long)tv.tv_sec) * 1000) + (tv.tv_usec / 1000);
}

unsigned long long TimerGetCS()
{
  return TimerGetMS() / 10;
}
/** \file ev3_timer.h
 * \brief Functions and constants for controlling EV3 timers
 *
 * ev3_timer.h contains declarations for the EV3 C API timer functions.
 *
 * License:
 *
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * The Initial Developer of this code is John Hansen.
 * Portions created by John Hansen are Copyright (C) 2009-2013 John Hansen.
 * All Rights Reserved.
 *
 * ----------------------------------------------------------------------------
 *
 * \author John Hansen (bricxcc_at_comcast.net)
 * \date 2013-07-10
 * \version 1
 */
 
#ifdef __cplusplus
extern "C" {
#endif

#ifndef ev3_timer_h
#define ev3_timer_h

#include <unistd.h>
#include <sys/time.h>
#include <signal.h>
#include <string.h>
//#include <stdio.h>
//#include <stdlib.h>

#include "ev3_constants.h"

typedef enum {
  ti10ms,
  ti50ms,
  ti100ms,
  ti250ms,
  ti500ms,
  ti1sec
} TimerInterval;

typedef void (*TimerCallback)(int sig);


unsigned long TimerWait(unsigned long Time);
void TimerReady(unsigned long Timer);

unsigned long Timer(byte Timer);
unsigned long FastTimer(byte Timer);
void ClearTimer(byte Timer);
void SetTimer(byte Timer, unsigned long Value);

unsigned long TimerMS(byte Timer);
void ClearTimerMS(byte Timer);
void SetTimerMS(byte Timer, unsigned long Value);

unsigned long TimerUS(byte Timer);
void ClearTimerUS(byte Timer);
void SetTimerUS(byte Timer, unsigned long Value);

void TimerInit();

unsigned long long TimerGetUS();
unsigned long long TimerGetMS();
unsigned long long TimerGetCS();

void SetTimerCallback(TimerInterval interval, TimerCallback callback);

#endif // ev3_timer_h

#ifdef __cplusplus
}
#endif

hi,

Das andere Thema "C-File hat zufällig den gleichen Namen wie ein C-command" hat damit erstmal aber gar nichts zu tun, aber das ist es ja, was in Sketch schiefläuft.

eben das ist nicht richtig.

es gibt Deine Tone.ino es gibt die Tone.cpp, die wegen Deiner Tone.ino nicht geladen werden kann. und dann gibt es die funktion "void tone", die wegen der nicht-geladenen Tone.cpp nicht gefunden wird. da kommts dann zum fehler...

gruß stefan

ja, für Sketch muss das wohl so hinnehmen.
In richtigem ANSI C geht es aber trotzdem, eben weil Dateinamen nichts, aber auch gar nichts mit internen Befehlen zu tun haben.

Ich denke , es ist schlicht ein Bug in der IDE und makefile, den man beheben könnte - aber es gibt sicher auch wichtigeres :wink:

hi,

In richtigem ANSI C geht es aber trotzdem, eben weil Dateinamen nichts, aber auch gar nichts mit internen Befehlen zu tun haben.

auch Dein problem hat nichts mit internen befehlen zu tun... nur Deine fehlermeldung, aber die kommt, weil programm und library den gleichen namen haben...

gruß stefan

welche Library? Ich habe keine Library eingebunden und weiß auch von keiner!

aber selbst wenn e sie gÄbe müsste es standardmäßig problemlos gehen!

hi,

Du verwendest doch die funktion tone(), oder? diese funktion ist in der library Tone definiert, die damit automatisch eingebunden wird. die datei Tone.cpp liegt, wie jurs schon sagte, in C:\Arduino-Pfad\hardware\arduino\cores\arduino

bin kein c-profi, aber beim erstellen der entgültigen auführbaren datei gibt es zwischenschritte, bei der andere "zwischen"-dateien erstellt werden. von mir geraten: diese dateien heißen wie die original-dateien Deines programms bzw. der benutzten libraries. dabei wird's wohl zum konflikt kommen.

gruß stefan

ja, ok, verstehe jetzt - es liegt an einer gleichnamigen lib, die nur zufällig wie ein C-API-Befehl heißt. Woher soll ich wiisen,welche lib ide devs wann wo genannt und irgendwo versteckt haben? Aber selbst wenn ich's wüsste - gleichnamige .c und .h Namen dürften nach C-Konventionen aber gar kein Problem sein (wie gezeigt) Aber wie gesagt - kann ntl damit leben, halte es aber trotzdem für nen Bug.

Aber selbst wenn ich's wüsste - gleichnamige .c und .h Namen dürften nach C-Konventionen aber gar kein Problem sein (wie gezeigt)

Aber nicht wenn für ein .C file in ein .CPP file angelegt wird, das den gleichen Namen wie das .CPP file einer Biliothek hat und darum die Bibliothek nicht eingefügt wird. Grüße Uwe