DCC Servodecoder Stellgeschwindigkeit einstellen

Hallo Zusammen

Ich habe ein kleines Problem mit meinem Arduino Nano DCC Servodecoder.
Der Decoder aufbau habe ich im Netz gefunden und funtioniert soweit alles super
nur wie bekomme ich die Stellgeschwindikeit eingestellt.
Die Stellwinkel bekomme ich eingestellt aber leider nicht die Stellgeschwindigkeit.
Ich hoffe mir kann jemand helfen.

Gruß Stefan

Hallo,
Das du ein Neuling bist, sieht jeder, das musst du nicht betonen.
Schreibe lieber in den Titel, welches Problem du hast, dann kann dir besser geholfen werden.

Und setze deinen Sketch bitte in Code-Tags, dann ist dieser von allen besser lesbar.

Verwende dazu die Schaltfläche </> oben links im Editorfenster.
Das kannst du auch noch nachträglich machen.
Auch den Titel anpassen.

Hallo Dieter
Danke für die info mit dem Code.
Mein problem ist das ich die Servo Stellgeschwindigkeit nicht einstellen kann vom Servo.
Den Stellwinken von links nach rechts klappt mit MS1 und MS2 aber nicht die Geschwindigkeit die es Braucht von MS1 nach MS2

#define ADDRESS  2

#define PIN_RAIL    2
#define PIN_OUT1    8
#define PIN_OUT2    9
#define PIN_OUT3    10
#define PIN_OUT4    11

#define N_PREAMBLE 10
#define N_BITS      8
unsigned short address;

unsigned char outmap[8] { PIN_OUT1, PIN_OUT1, PIN_OUT2, PIN_OUT2, PIN_OUT3, PIN_OUT3, PIN_OUT4, PIN_OUT4 };

// QUEUE //////////////////////////////////////////////////////////////////////
#define QUEUE_SIZE  0x100

class queue {
public:
  queue() { write_i = 1; read_i = 0; }
  void init() { write_i = 1; read_i = 0; }
  void put(bool val, unsigned long dur);
  bool get(bool *val, unsigned long *dur);
private:
  volatile bool value[QUEUE_SIZE];
  volatile unsigned long duration[QUEUE_SIZE];
  volatile unsigned char write_i;
  volatile unsigned char read_i;
};

void queue::put(bool val, unsigned long dur)
{
  if ((unsigned char)(write_i + 1) == read_i)
      read_i++;
  value[write_i] = val;
  duration[write_i++] = dur;
}

bool queue::get(bool *val, unsigned long *dur)
{
  if ((unsigned char)(read_i + 1) == write_i)
    return false;
  *val = value[++read_i];
  *dur = duration[read_i];
  return true;
}

queue bitQueue;

// BIT PROCESSING /////////////////////////////////////////////////////////////
/*
Zur Erkennung der eingehenden Daten wird ein Line-Interrupt
bei jeder positiven Flanke ausgelöst.
Nun wird ein Timer gestartet und nach dessen
Ablauf ein Timer-Interrupt ausgelöst.
Wenn zu diesem Zeitpunkt der Pegel auf ca. 5V liegt,
wird eine "1" erkannt, sonst eine "0".
*/
#define WIDTH_DETECT  (1.0/37950)  // 79 µs 3
// DCC0=200
#define TOL_DCC0_MIN  190
#define TOL_DCC0_MAX  19800
// DCC1=116
#define TOL_DCC1_MIN  104
#define TOL_DCC1_MAX  128

unsigned long time;
unsigned long timeNow;
bool currentBit;

void beginBit()
{
  timeNow = micros();
  bitQueue.put(currentBit, timeNow - time);
  time = timeNow;
  FlexiTimer2::start();
}

void detectBit()
{
  FlexiTimer2::stop();
  currentBit = !digitalRead(PIN_RAIL);
}

bool getBit(bool *val)
{
  unsigned long dur;
  while (!bitQueue.get(val, &dur))
    ;
  if (*val)
    return ((dur > TOL_DCC1_MIN) && (dur < TOL_DCC1_MAX));
  else
    return ((dur > TOL_DCC0_MIN) && (dur < TOL_DCC0_MAX));
  return false;
}

// Byte processing ////////////////////////////////////////////////////////////
bool getByte(unsigned char *val)
{
  bool b;
  unsigned char ret;
  for (int i = N_BITS; i > 0; i--) {
    if (!getBit(&b)) {
      return false;
    }
    ret <<= 1;
    ret |= b ? 0x01 : 0x00;
  }
  *val = ret;
  return true;
}

// MAIN ///////////////////////////////////////////////////////////////////////
void setup() {
  address = ADDRESS;
  pinMode(PIN_RAIL, INPUT);
  pinMode(PIN_OUT1, OUTPUT);
  pinMode(PIN_OUT2, OUTPUT);
  pinMode(PIN_OUT3, OUTPUT);
  pinMode(PIN_OUT4, OUTPUT);
  digitalWrite(PIN_OUT1, LOW);
  digitalWrite(PIN_OUT2, LOW);
  digitalWrite(PIN_OUT3, LOW);
  digitalWrite(PIN_OUT4, LOW);
  bitQueue.init();
  time = micros();
  attachInterrupt(0, beginBit, RISING);  // 0 = Pin2
  FlexiTimer2::set(3, WIDTH_DETECT, detectBit);
  FlexiTimer2::stop();
  Serial.begin(115200);
}

void loop() {
  bool b;
// Preamble
  for (int i = N_PREAMBLE; i > 0; i--)
    if (!getBit(&b) || !b)
      i = N_PREAMBLE;
  while (b) // restliche Startbits und packet start bit
    if (!getBit(&b))
      return;

// Low Address Byte
  unsigned char adr;
  union {
    unsigned short ad;
    unsigned char a[2];
  } ladr;
  ladr.ad = 0;
  if (!getByte(&adr))
    return;
  ladr.a[0] = adr;
  if ((ladr.a[0] & 0xc0) != 0x80)  // accessory?
    return;
  ladr.a[0] &= 0x3f;

// Start Bit
  if (!getBit(&b) || b)
    return;

// High Address - Data Byte
  unsigned char val = 0;
  if (!getByte(&val))
    return;
  if (!(val & 0x80))    // basic?
    return;
  ladr.ad |= (~val & 0x70) << 2;
  if (ladr.ad != address)
    return;
    
// Start Bit
  if (!getBit(&b) || b)
    return;

// Error Detection Data Byte
  unsigned char chk = 0;
  if (!getByte(&chk))
    return;
  if ((adr ^ val) != chk)
    return;
  bool set1 = (val & 0x08) != 0;
  unsigned char iadr = val & 0x07; 

// Packet End Bit
  if (!getBit(&b) || !b)
    return;

// Output Servo
#define MS20  20000
#define MS1    1000
#define MS2    2000

  if (set1) {
    int timePos;
    if (iadr & 0x01) // grün
      timePos = MS2;
    else             // rot
      timePos = MS1;
    detachInterrupt(0);
    for (int i = 0; i < 12; i++) {  // 240 ms
      digitalWrite(outmap[iadr], HIGH);
      delayMicroseconds(timePos);
      digitalWrite(outmap[iadr], LOW);
      delayMicroseconds(MS20 - timePos);
    }
    attachInterrupt(0, beginBit, RISING);
  }
}

Gruß Stefan

Hallo Stefan,
das Einstellen der Stellgeschwindigkeit ist in diesem Sketch nicht vorgesehen.

Wo hast Du den denn her? Für einen DCC-Decoder auf Arduino Basis gibt es wesentlich bessere Lösungen.

Hallo Franz-Peter

hier hab ich den gefunden

http://www.manfredstudier.de/Modellbahn/Decoder/Servo/servo.html

Gruß Stefan

Der Autor will offensichtlich gern alles selbst machen, und setzt keine Libraries ein. Ich halte das für keine gute Idee - warum das Rad neu erfinden, wenn es fertige bessere Lösungen gibt?

Für die Decodierung des DCC-Signals gibt es z.B. die NmraDcc Library. Da sind auch Beispiele für den Einsatz dabei, auch Servo-Decoder.

Auf der Basis habe ich auch einen frei konfigurierbaren Decoder geschrieben, der kann auch Servos langsam ansteuern. Ausserdem kannst Du die Endlagen per CV einstellen, und musst das nicht im Code fest eintragen.

Aber es gibt sicher auch noch mehr, die das können. Vielleicht etwas komplexer als deine Lösung, aber auch wesentlich flexibler.
Ich würde auch das DCC-Signal für den Arduino nicht direkt vom Gleis abgreifen. Gerade bei DCC hat dieses Dignal keinen festen Gnd-Bezugspegel ( Wenn Du Märklin einsetzt ist das anders, da mag es gehen ). Deshalb sollte der Signaleingang über einen Optokoppler getrennt sein.

Super danke werde mich da mal durch fuchsen.

Bei dem Optokoppler hab ich jetzt verschiedene Wiederstandswerte gesehen von 1K bis 3Kohm am DCC eingang.

ich habe 19 Volt schienenspannung was sollte man am besten nehmen?

Gruß Stefan

stefan79:
Super danke werde mich da mal durch fuchsen.

Bei dem Optokoppler hab ich jetzt verschiedene Wiederstandswerte gesehen von 1K bis 3Kohm am DCC eingang.

ich habe 19 Volt schienenspannung was sollte man am besten nehmen?

Je nach Optokoppler kannst du den Strom selbst berechnen und danach den Widerstand bestimmen.

Hallo Stefan,

stefan79:
ich habe 19 Volt schienenspannung was sollte man am besten nehmen?

Nennstrom beim 6N137 sind 7,5mA ( für den Wert sind die Schaltzeiten im Datenblatt angegeben), Maximalstrom sind 50mA. Der Widerstand ist also rel. unkritisch. 1-3kOhm passt da schon. 1,5kOhm ist auf jeden Fall ein guter Wert.

Hallo Franz-Peter

Danke für die Info.

Hab gestern versucht eine schaltung auf zu bauen aber irgend wie klappte es nicht so richtig :confused:

Ich muss es heute noch mal versuchen .

Gruß Stefan

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.