Hallo HaWe,
sorry das ich mich jetzt erst melde aber bei dem schönen Wetter konnte mich am WE nichts vor den Bildschirm locken.

Zu Deinen Fragen:

Meine "struct pid" sollte nur ein Auszug aus Deiner "struct PIDstruct" sein. Worauf es mir ankommt ist, dass du diese um zwei Felder erweiterst:
einmal um ein Element pthread_t und
zweitens, um ein Element worüber du deine Motoren identifizieren kannst.

Dadurch kannst du deinen Code wesentlich verkürzen, schau mal deine
Code:
safecall void StopPIDcontrol (char port) {

  if (port==OUT_A) {

    if (PID_A.runstate!=0) { // stop PID task if already running
      stop task_PID_A;
      PlayTone(TONE_C7,100);
      Off(OUT_A);
      Wait(50);
      PID_A.cont=false;
      PID_A.runstate=0;
      Wait(1);
      return;
    }

  }
  else
  if (port==OUT_B) {

    if (PID_B.runstate!=0) { // stop PID task if already running
      stop task_PID_B;
      PlayTone(TONE_C7,100);
      Off(OUT_B);
      Wait(50);
      PID_B.cont=false;
      PID_B.runstate=0;
      Wait(1);
      return;
    }

  }
  else
  if (port==OUT_C) {

    if (PID_C.runstate!=0) { // stop PID task if already running
      stop task_PID_C;
      PlayTone(TONE_C7,100);
      Off(OUT_C);
      Wait(50);
      PID_C.cont=false;
      PID_C.runstate=0;
      Wait(1);
      return;
    }

  }


}
an.

Da steht dreimal quasi das Gleiche.
Wenn du jetzt deine Struktur erweiterst und statt dem Port einen Zeiger auf die Variable übergibst, läßt sich der Code um 2/3 kürzen.
Code:
struct PIDstruct {
  /* Erweiterung */
  pthread_t tid;
  unsigned short motor_id;

                 // custom target values
  long  target;                  // set target
  int   tarpwm;                  // motor target speed
                 // custom regulation parameters
  float P;                       // P: basic propotional to error
  float I;                       // I: integral: avoid perish
  float D;                       // D: derivative: avoid oscillating
  float precis;                  // error precision to target
  int   regtime;                 // PID loop time
  float damp;                    // damp the integral memory
  char  cont;                    // target: continue or hit once
                 // internal control variables
  char  runstate;                // monitors runstate
  int   outp;                    // PID control output value
  int   maxout;                  // max output (max motor pwr)
  long  read;                    // current sensor reading
  float err;                     // current error
  float integr;                  // integral of errors
  float speed;                   // current speed


} ;

void StopPIDcontrol (struct PIDstruct *pid) {

  if (pid->tid) { // stop PID task if already running
    pid_stop(pid, 1); // siehe botties zweites Beispiel
    Off(pid->motor_id);
    pid->cont=false;
    pid->runstate=0;
    return;
  }

}
Wenn du jetzt eine Variable PID_A definierst, würde der Aufruf so aussehen:
Code:
struct PIDstruct PID_A;

void eine_stop_funktion(void) {
  StopPIDcontrol( &PID_A );
}
Du wählst somit nicht mehr über eine port/switch Kombination deinen PID Controler aus, sondern beim Aufruf der Funktionen über den Zeiger auf die Variable, welche alle Daten für einen Controler enthält.
D.h. bei allen Funktionen ersetzt du "char port" durch "struct PIDstruct* pid" und dereferenzierst die Elemente der Struktur nicht mehr über den "." Operator sondern über den "->" Operator.

Auch bei der Erezugung der Threads können wir jetzt den Zeiger auf die Variable als Parameter in die Thread-Funktion hineingeben, denn die Signatur dieser Funktion lautet:
Code:
void *(*function)(void *arg);
Zwar ist arg vom Typ "void *" nur da wir immer nur Zeiger vom Typ "struct PIDcontrol *" hineingeben können wir am Anfang der Routine diesen Zeiger sicher auf den richtigen Typ casten:
Code:
void *pid_calc(void *arg) {
  float aspeed, damp, PWMpwr, readold, errorold, tprop;
  long  readstart, cmax, cmin;                         // for monitoring
  long  starttime, runtime, clock, dtime;              // timer
  char  regloop;

  /* das ist ein ziemlich sicherer cast */
  struct PIDcontrol *pid = (struct PIDcontrol *) arg;

  pid->runstate = 0x10;                               // reg state: RAMPUP
  pid->read      = (MotorRotationCount(pid->motor_id));        // get current encoder reading
  pid->err        = pid->target - pid->read;          // error to target

  readstart      = pid->read;

/* ... */

}
so brauchst du auch diese Routine nur einmal, denn bei der Thread Erzeugung übergibst du den Zeiger auf die Variable z.B.:
Code:
pthread_create(&PID_A.tid, 0, pid_calc, &PID_A);
ich hoffe das es jetzt klarer ist, warum ich Zeiger verwenden würde?


Noch ein Wort zu den Variablen für die einzelnen PID Controler, du definierst die so:
Code:
struct PIDcontrol PID_A;
struct PIDcontrol PID_B;
struct PIDcontrol PID_C;
bei sowas sehe ich sofort eine Aufzählung und wenn ich dann auch noch Operationen über diese machen muss, wie z.B. ein warten auf das Beenden eines Threads, dann ordne ich sowas in einem Array an:
Code:
enum motoren {
  MOT_SCHULTER = 0,
  MOT_ELLE,
  MOT_HAND,
  MOT_MAX
};

struct PIDcontrol pids [MOT_MAX];

/* Verwendung */

void ein_stop(void) {
   StopPIDcontrol( &pids[MOT_SCHULTER );
}

void mehrere_stops(void) {
  int idx;

  for(idx = MOT_SCHULTER; idx < MOT_MAX; idx++)
    StopPIDcontrol( &pids[idx] );
}
find ich bequemer, ist aber Geschmackssache.

Gruss

botty