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.
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);
}
}
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.
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.