Jump to content
Intermodellbau 2024: Unser Stand in Halle 3 ist fertig für Besucher - schaut mal 'rein. ×
Schiffsmodell.net

Graupner Hott dritter Knüppel


Guest tt99

Recommended Posts

  • Replies 62
  • Created
  • Last Reply

Top Posters In This Topic

  • Ralph Cornell

    8

  • Achim_LSG

    7

  • MiSt

    2

  • Frankenmatrose

    1

Guest LostInSpace

Ja,

Code war bei meinem letzten Posting schon vorhanden. Ich bin nur noch nicht zum testen kommen. Ich will vermeiden, das noch Macken im Code sind und ich immer wieder neue Listings posten muss. Das würde den Thread nur unnötig zumüllen. Ich habe ja hier im Forum keine Möglichkeit, Postings im Nachhinein zu ändern.

 

Heute Abend, spätestens morgen folgt das Programm.

Link to comment
Guest LostInSpace

Hallo,

 

hier nun das Update. Der Code ist jetzt etwas einfacher und kosmetisch etwas abgeändert. Wichtig ist die neue loop() Implementierung. Man kann nun für jeden Kanal eine eigene Funktion hinterlegen.

/*
 * DSC-Schueler
 * erzeugen eines PPM Signals für Graupner DSC
 * Hardware ist Arduino UNO, keine speziellen LIBs
 * !!! Dies ist Demonstrationscode, nicht direkt für den produktiven Einsatz !!!
 * (c) l2hf.de 2016
 * r0.2.4
 */
#define TX_CHANNELS   8  // Anzahl Kanaele total
#define PPM_CENTER 1150  // Kanal-Mitte. Nicht 1500
#define PPM_RANGE   400  // Bereich von Center bis Min oder Max
#define PAUSE_LEN   300  // 300us. Muss > 285us sein, sonst DSC Problem
#define FRAME_LEN 22000  // Laenge eines komplette Frames. Also zB 22000=22ms

volatile uint16_t txChannel[ TX_CHANNELS + 1];
uint8_t  poti[ TX_CHANNELS] = { 0, 0, 0, 0, A0, A1, A0};  // Index der analogen Eingaenge
volatile uint16_t global_counter = 0; // wird 1x pro Frame um 1 erhoeht

// Hilfsvariablen
volatile uint8_t  channel_cnt = 0; // Zaehler ueber Ausgabekanaele 0 - ( TX_CHANNELS - 1)
static uint8_t channel_read = 1;

ISR( TIMER1_OVF_vect)
{
 if( channel_cnt == TX_CHANNELS)
 {
  ICR1 = (( txChannel[ TX_CHANNELS] + PAUSE_LEN) * 2) ;
  channel_cnt = 0;
  ++global_counter;
  txChannel[ TX_CHANNELS] = FRAME_LEN - ( TX_CHANNELS * PAUSE_LEN);
 }
 else
  ICR1 = ( txChannel[ channel_cnt++] + PAUSE_LEN) * 2;
} // ISR TIMER1_OVF_vect

ISR( TIMER1_COMPA_vect)
{
 if( channel_cnt == TX_CHANNELS)
  OCR1A = txChannel[ TX_CHANNELS] * 2; 
 else 
 {
  OCR1A = txChannel[ channel_cnt] * 2;
  txChannel[ TX_CHANNELS] -= txChannel[ channel_cnt];
 } 
} // ISR TIMER1_COMPA_vect

void setup() 
{
 cli();  // alle Interrupts aus
  
 for( int i = 0; i < TX_CHANNELS; ++i) // alle Kanaele auf CENTER setzen
  txChannel[ i] = PPM_CENTER;
 
 pinMode( 9, OUTPUT);  // Ausgabe des PPM Signals OC1A = PB1 -> UNO Pin9
 
 // hier evtl eigene Eingaenge aktivieren
 // zB. pinMode( 10, INPUT);

 // init 16bit Timer1 des UNO bei 16Mhz Takt
 TCCR1A = (1<<COM1A1) | (1<<WGM11); //  Mode 14
 TCCR1B = (1<<WGM12) | (1<<WGM13) | (1<<CS11); // Teiler/8
 TCCR1C = 0;
 
 OCR1A = txChannel[ 0] * 2;
 ICR1 = (txChannel[ 0] + PAUSE_LEN) * 2;
 txChannel[ TX_CHANNELS] = FRAME_LEN - (TX_CHANNELS * PAUSE_LEN); 
 TIMSK1 = (1<<OCIE1A) | (1<<TOIE1);

 sei();   // die Show kann beginnen -> IRQs an!
} // setup

void loop() 
{
 uint16_t v; 
 if( ((channel_cnt + 1) % TX_CHANNELS) == channel_read)
 {   // wir lesen jeden Kanal nur 1x pro Kanal/Frame
  switch( channel_read) // lese aktiv gesendeter Kanal + 1
  {
   case 4 : // Analog einlesen (0-1023), bei Map Bereich reduzieren, weil Knueppel
   case 5 :
            v = analogRead( poti[ channel_read]); 
            txChannel[ channel_read] = map( v, 200, 823, PPM_CENTER - PPM_RANGE, PPM_CENTER + PPM_RANGE); 
            break;
   // bei Bedarf eigene Leseroutine
// case 3 : meineLeseRoutine();
//          break;   
   case 6 :  // normales Poti       
            v = analogRead( poti[ channel_read]); 
            txChannel[ channel_read] = map( v, 0, 1023, PPM_CENTER - PPM_RANGE, PPM_CENTER + PPM_RANGE); 
            break;
  } // switch
  channel_read = ++channel_read % TX_CHANNELS; // 0 - (TX_CHANNELS - 1)
 }
} // loop

Viel Spaß!

Link to comment

Hallo,

 

Vorab vielen Dank für den Code und deine Bemühungen.

 

Bei dem Code habe ich allerdings das selbe Problem wie mit dem anderen: Ich weis nicht, was ich ändern muss, um einen Schalter und zwei Potimeter zu übergeben.

 

Muss ich dann einfach noch case 7+8 hinzufügen: 

int buttonPin = 2;


void setup() 
{
 pinMode (buttonPin, INPUT_PULLUP);
}


void loop():
{
// case 7 : meineLeseRoutine();
//          break;   
   case 8 :  // normales Poti       
            v = digitalRead( buttonPin[ channel_read]); 
            txChannel[ channel_read] = map( v, 0, 1023, PPM_CENTER - PPM_RANGE, PPM_CENTER + PPM_RANGE); 
            break;
}

Oder gehe ich das in der void loop () falsch an???

 

 

Bei der Joysticksteuerung habe ich auch noch eine Frage:

 

Wenn ich den Code, den ich angefügt habe in einem einzelnen Programm Starte, so funktioniert er. Wenn ich ihn allerdings in den PPM_Code einfüge, so funktioniert es nicht. Kann das sein, dass durch die if Abfragen das Programm zu langsam wird und daher das Timing nicht mehr stimmt, oder ist es etwas anderes???

 

Daher wäre ich über Hilfe bei dem zwei Fragen sehr dankbar.

 

Viele Grüße

int potpin = A0;
int buttonPin = 2;   // Mit einem Widerstand zwischen Masse und Pin 2 funktioniert es einwandfrei

int val;
int x, y = 90;                         // y = 90 -> ist Servomitte

void setup() {
  Serial.begin(9600);

  pinMode(buttonPin, INPUT_PULLUP);
}

 
void loop() {
  val = analogRead(potpin);             // Potimeter auslesen

  x = (val - 516) / 100 * (-1);         // x ist zwischen -3 und 3

  if (x != 0){
    y = y + x;
  }
  if (y <= 0){
    y = 0;
  }
  if (y >= 180){
    y = 180;
  }

  
  if (digitalRead(buttonPin) == LOW) {
    y = 90;;
  }
   
  
  Serial.print("X: ");
  Serial.print(x);
  Serial.print(" | Y: ");
  Serial.print(y);
  Serial.print(" | Button: ");
  Serial.println(digitalRead(buttonPin));
    
  //delay(10);                            // Verzögerung zur Veranschauung der Werte
}


Link to comment
Guest LostInSpace

Hm,

 

ich glaube, das da noch einiges an Grundlagenwissen fehlt.

 

Hier das Beispiel, um einen Schalter/Taster zu implementieren

// Im Kopf der Datei
#define buttonPin 2

// in setup()
pinMode (buttonPin, INPUT_PULLUP);

// Funktion leseSchalter( void)
uint16_t leseSchalter( void)
{
 if( digitalRead( buttonPin) == LOW)   // Schalter/Taster auf Masse?
  return 0;
 else
  return 1023 
}


// in loop()
// case 7 steht für Kanal 8
case 7 : v = leseSchalter();
         txChannel[ channel_read] = map( v, 0, 1023, PPM_CENTER - PPM_RANGE, PPM_CENTER + PPM_RANGE); 
         break;



Die Umsetzung für die Inkrementalsteuerung mache ich morgen.

 

 

Link to comment
Guest LostInSpace

Kleiner Nachtrag zum Stichwort Arduino Timer.

 

Die Arduino Umgebung ist für kleine Projekte natürlich unheimlich praktisch, hat aber auch einige nervende Fallstricke! Mein Programm benutzt für die PPM Ausgabe den 16Bit Timer1 des Atmega328. Dadurch ist das Ausgangssignal sehr stabil. Theoretisch könnte man in der loop() umfangreiche mathematische Betrachtungen machen, ohne dass das Ausgangssignal davon betroffen wird. Soweit, so gut. Leider gibt es in den Arduino Libs Funktionen, die auch den Timer1 benutzen. Dazu müsste auch die delay Funktion gehören. Wird nun ein delay aufgerufen, werden die Einstellungen für den Timer1 überschrieben und die PPM Ausgabe funktioniert nicht mehr. Man muss also beim Einsatz von Lib-Funktionen genau darauf achten, ob diese den Timer1 benutzen.

Link to comment

Das ist generell ein guter Hinweis zu Arduino - leider gehen viele Libs davon aus, dass der Controller ihnen ganz alleine gehört ...

 

... ist manchmal an der Grenze zur Spielerei, manchmal aber auch beeindruckend gut ...

 

... aber das Programm von LostInSpace ist ein sehr (!) schönes Beispiel dafür, wie man etwas ganz prima und straightforward "von Hand" machen kann.

 

Was ich mir für die weniger Versierten hier wünschen würde sind Blockkommentare, die die Funktion und Arbeitsweise der beiden Interrupt-Service-Routinen (ISR) zusammenfassen (nämlich Erzeugen der beiden Pulsflanken gemäß des Wunschtimings) bzw. die Arbeitsweise von loop(), wo abhängig vom Pulszähler der ISR jeweils zugehörige vorbereitende Tätigkeiten stattfinden. Plus ein Satz zur "Kommunikation" - der Pulszähler - zwischen ISRs und loop(), und schon versteht auch ein nichtversierter Gelegenheitsprogrammierer und "Normalerweise_Irgendeine_Lib_Benutzer", was dieses knackige Programm wie tut.

Link to comment
Guest LostInSpace

Ja, das Elend mit den Kommentaren. :mrgreen:

 

Zur Inkrementalsteuerung:

Soll die nur für einen Kanal sein oder für mehrere? Wenn für mehrere, dann einen Taster zum zurücksetzen aller Kanäle, oder für jeden Kanal einen eigenen Taster zum zurücksetzen?

Edited by LostInSpace
Link to comment

Ich habe einen Joystick. Also hat der eine x und eine y Achse. Zudem hat er einen Schalter. Mit dem sollten dann beide Kanäle neutralisiert werden. Für den Schalter als Kanal habe ich dann noch einen anderen Taster.

 

Noch etwas:

 

Ich bekomme es nicht hin den Schalter mit einzubinden. Ich habe jetzt versucht es so zu machen, wie du es gesagt hast, jedoch funktioniert es nicht.

/*
 * DSC-Schueler
 * erzeugen eines PPM Signals für Graupner DSC
 * Hardware ist Arduino UNO, keine speziellen LIBs
 * !!! Dies ist Demonstrationscode, nicht direkt für den produktiven Einsatz !!!
 * (c) l2hf.de 2016
 * r0.2.4
 */
 
#define TX_CHANNELS   8  // Anzahl Kanaele total
#define PPM_CENTER 1150  // Kanal-Mitte. Nicht 1500
#define PPM_RANGE   400  // Bereich von Center bis Min oder Max
#define PAUSE_LEN   300  // 300us. Muss > 285us sein, sonst DSC Problem
#define FRAME_LEN 22000  // Laenge eines komplette Frames. Also zB 22000=22ms
#define buttonPin 2
 
volatile uint16_t txChannel[ TX_CHANNELS + 1];
uint8_t  poti[ TX_CHANNELS] = { 0, 0, 0, 0, A0, A1, A0};  // Index der analogen Eingaenge
volatile uint16_t global_counter = 0; // wird 1x pro Frame um 1 erhoeht

// Funktion leseSchalter( void)
uint16_t leseSchalter( void)
{
 if( digitalRead( buttonPin) == LOW)   // Schalter/Taster auf Masse?
  return 0;
 else
  return 1023; 
}


// Hilfsvariablen
volatile uint8_t  channel_cnt = 0; // Zaehler ueber Ausgabekanaele 0 - ( TX_CHANNELS - 1)
static uint8_t channel_read = 1;
 
ISR( TIMER1_OVF_vect)
{
 if( channel_cnt == TX_CHANNELS)
 {
  ICR1 = (( txChannel[ TX_CHANNELS] + PAUSE_LEN) * 2) ;
  channel_cnt = 0;
  ++global_counter;
  txChannel[ TX_CHANNELS] = FRAME_LEN - ( TX_CHANNELS * PAUSE_LEN);
 }
 else
  ICR1 = ( txChannel[ channel_cnt++] + PAUSE_LEN) * 2;
} // ISR TIMER1_OVF_vect
 
ISR( TIMER1_COMPA_vect)
{
 if( channel_cnt == TX_CHANNELS)
  OCR1A = txChannel[ TX_CHANNELS] * 2; 
 else 
 {
  OCR1A = txChannel[ channel_cnt] * 2;
  txChannel[ TX_CHANNELS] -= txChannel[ channel_cnt];
 } 
} // ISR TIMER1_COMPA_vect
 
void setup() 
{
 cli();  // alle Interrupts aus
  
 for( int i = 0; i < TX_CHANNELS; ++i) // alle Kanaele auf CENTER setzen
  txChannel[ i] = PPM_CENTER;
 
 pinMode( 9, OUTPUT);  // Ausgabe des PPM Signals OC1A = PB1 -> UNO Pin9

 pinMode (buttonPin, INPUT_PULLUP);

 
 // hier evtl eigene Eingaenge aktivieren
 // zB. pinMode( 10, INPUT);
 
 // init 16bit Timer1 des UNO bei 16Mhz Takt
 TCCR1A = (1<<COM1A1) | (1<<WGM11); //  Mode 14
 TCCR1B = (1<<WGM12) | (1<<WGM13) | (1<<CS11); // Teiler/8
 TCCR1C = 0;
 
 OCR1A = txChannel[ 0] * 2;
 ICR1 = (txChannel[ 0] + PAUSE_LEN) * 2;
 txChannel[ TX_CHANNELS] = FRAME_LEN - (TX_CHANNELS * PAUSE_LEN); 
 TIMSK1 = (1<<OCIE1A) | (1<<TOIE1);
    
 sei();   // die Show kann beginnen -> IRQs an!
} // setup
 
void loop() 
{
 uint16_t v; 
 if( ((channel_cnt + 1) % TX_CHANNELS) == channel_read)
 {   // wir lesen jeden Kanal nur 1x pro Kanal/Frame
  switch( channel_read) // lese aktiv gesendeter Kanal + 1
  {
   case 4 : // Analog einlesen (0-1023), bei Map Bereich reduzieren, weil Knueppel
   case 5 :
            v = analogRead( poti[ channel_read]); 
            txChannel[ channel_read] = map( v, 200, 823, PPM_CENTER - PPM_RANGE, PPM_CENTER + PPM_RANGE); 
            break;
   // bei Bedarf eigene Leseroutine
// case 3 : meineLeseRoutine();
//          break;   
   case 6 :  // normales Poti       
            v = analogRead( poti[ channel_read]); 
            txChannel[ channel_read] = map( v, 0, 1023, PPM_CENTER - PPM_RANGE, PPM_CENTER + PPM_RANGE); 
            break;
   // in loop()
   // case 7 steht für Kanal 8
   case 7 : 
            v = leseSchalter();
            txChannel[ channel_read] = map( v, 0, 1023, PPM_CENTER - PPM_RANGE, PPM_CENTER + PPM_RANGE); 
            break;
         
  } // switch
  channel_read = ++channel_read % TX_CHANNELS; // 0 - (TX_CHANNELS - 1)
 }
} // loop
 
Edited by tt99
Link to comment

Hallo,

 

Ich wollte mich nochmal melden. Ich habe noch mal lange mit einem Freund rumprobiert und es jetzt irgendwie hinbekommen. 

 

Jetzt kann ich mit einem Joystick steuern und diesen auch wieder zurücksetzen. Zudem kann ich jetzt noch einen weiteren Kanal über einen Schalter steuern. Daher nochmal einen großen Dank, an alle die mir geholfen haben, dabei besonders an LostInSpace, da ich es ohne seinen Code nicht geschafft hätte.

 

Ich habe jetzt den entsprechenden Code nochmal angefügt.

 

Viele Grüße

/*
 * DSC-Schueler
 * erzeugen eines PPM Signals fuer Graupner DSC
 * Hardware ist Arduino UNO, keine speziellen LIBs
 * !!! Dies ist Demonstrationscode, nicht direkt fuer den produktiven Einsatz !!!
 * (c) l2hf.de 2016
 * r0.2.4
 */
 
#define TX_CHANNELS   10 // Anzahl Kanaele total
#define PPM_CENTER 1150  // Kanal-Mitte. Nicht 1500
#define PPM_RANGE   400  // Bereich von Center bis Min oder Max
#define PAUSE_LEN   300  // 300us. Muss > 285us sein, sonst DSC Problem
#define FRAME_LEN 22000  // Laenge eines komplette Frames. Also zB 22000=22ms
#define buttonPin 2      // Zum zurücksetzten des Joysticks 
#define switchPin 3      // Taster
 
volatile uint16_t txChannel[ TX_CHANNELS + 1];
uint8_t  poti[ TX_CHANNELS] = { 0, 0, 0, 0, 0, A0, A1, A0};  // Index der analogen Eingaenge
volatile uint16_t global_counter = 0; // wird 1x pro Frame um 1 erhoeht

// Funktion leseSchalter( void)
uint16_t leseSchalter( void)
{
 if( digitalRead( switchPin) == HIGH)
  return 60;
 else
  return 1089; 
}


// Hilfsvariablen
volatile uint8_t  channel_cnt = 0; // Zaehler ueber Ausgabekanaele 0 - ( TX_CHANNELS - 1)
static uint8_t channel_read = 1;

int w, x = 510;                         // x = 510 -> ist Servomitte
int y, z = 510;                         // z = 510 -> ist Servomitte

 
ISR( TIMER1_OVF_vect)
{
 if( channel_cnt == TX_CHANNELS)
 {
  ICR1 = (( txChannel[ TX_CHANNELS] + PAUSE_LEN) * 2) ;
  channel_cnt = 0;
  ++global_counter;
  txChannel[ TX_CHANNELS] = FRAME_LEN - ( TX_CHANNELS * PAUSE_LEN);
 }
 else
  ICR1 = ( txChannel[ channel_cnt++] + PAUSE_LEN) * 2;
} // ISR TIMER1_OVF_vect
 
ISR( TIMER1_COMPA_vect)
{
 if( channel_cnt == TX_CHANNELS)
  OCR1A = txChannel[ TX_CHANNELS] * 2; 
 else 
 {
  OCR1A = txChannel[ channel_cnt] * 2;
  txChannel[ TX_CHANNELS] -= txChannel[ channel_cnt];
 } 
} // ISR TIMER1_COMPA_vect
 
void setup() 
{
 cli();  // alle Interrupts aus
  
 for( int i = 0; i < TX_CHANNELS; ++i)  // alle Kanaele auf CENTER setzen
  txChannel[ i] = PPM_CENTER;
 
 pinMode( 9, OUTPUT);                   // Ausgabe des PPM Signals OC1A = PB1 -> UNO Pin9

 pinMode (buttonPin, INPUT_PULLUP);     // zum zurücksetzten

 pinMode (switchPin, INPUT_PULLUP);     // Schalter
 
 // init 16bit Timer1 des UNO bei 16Mhz Takt
 TCCR1A = (1<<COM1A1) | (1<<WGM11); //  Mode 14
 TCCR1B = (1<<WGM12) | (1<<WGM13) | (1<<CS11); // Teiler/8
 TCCR1C = 0;
 
 OCR1A = txChannel[ 0] * 2;
 ICR1 = (txChannel[ 0] + PAUSE_LEN) * 2;
 txChannel[ TX_CHANNELS] = FRAME_LEN - (TX_CHANNELS * PAUSE_LEN); 
 TIMSK1 = (1<<OCIE1A) | (1<<TOIE1);
    
 sei();   // die Show kann beginnen -> IRQs an!
} // setup
 
void loop() 
{
 uint16_t v; 
 if( ((channel_cnt + 1) % TX_CHANNELS) == channel_read)
 {   // wir lesen jeden Kanal nur 1x pro Kanal/Frame
  switch( channel_read) // lese aktiv gesendeter Kanal + 1
  {
   // case 6 steht fuer Kanal 7
   case 6 : // Analog einlesen (0-1023), bei Map Bereich reduzieren, weil Knueppel
            v = analogRead( poti[ channel_read]);
            
            w = ((v / 100) - 5);         // w ist zwischen -5 und 5
            if (w < -1 or w > 1)
              x = x + w;
                                   
            if (x <= 0)
              x = 0;
            
            if (x >= 1023)
              x = 1023;
            
            if (digitalRead(buttonPin) == LOW) 
              x = 510;
            
            txChannel[ channel_read] = map( x, -60, 960, PPM_CENTER - PPM_RANGE, PPM_CENTER + PPM_RANGE); 
            break;
   // case 7 steht fuer Kanal 8
   case 7 :
            v = analogRead( poti[ channel_read]); 
            
            y = ((v / 100) - 5);         // y ist zwischen -5 und 5
            if (y < -1 or y > 1)
              z = z + y;
              
            if (z <= 0)
              z = 0;
            
            if (z >= 1023)
              z = 1023;
            
            if (digitalRead(buttonPin) == LOW) 
              z = 510;;
            
            txChannel[ channel_read] = map( z, -60, 960, PPM_CENTER - PPM_RANGE, PPM_CENTER + PPM_RANGE); 
            break;
   // case 9 steht fuer Kanal 10
   case 9 : 
            v = leseSchalter();      
            
            txChannel[ channel_read] = map( v, 0, 1023, PPM_CENTER - PPM_RANGE, PPM_CENTER + PPM_RANGE); 
            break;
         
  } // switch
  channel_read = ++channel_read % TX_CHANNELS; // 0 - (TX_CHANNELS - 1)
 }
} // loop
Edited by tt99
Link to comment

Hallo,

 

Ich wollte nochmal ein Update geben. Ich habe jetzt alles soweit fertig und es funktioniert wirklich sehr gut. Ist sogar noch besser geworden als ich dachte.

 

Ich habe es jetzt mit einen Joystick und einem Taster umgesetzt.

 

Viele Grüße

 

post-14151-0-67600200-1480244995_thumb.jpg

post-14151-0-89384700-1480245009_thumb.jpg

post-14151-0-47413700-1480245023_thumb.jpg

post-14151-0-42026100-1480245044_thumb.jpg

post-14151-0-00093400-1480245058_thumb.jpg

Link to comment

Hi. Wenn ich das richtig sehen gehst du mit 230V über ein "Rasiererkabel" rein.

Vielleicht solltest du den Anschluss nochmal überdenken und eine Variante mit Erdung einbauen.

Der Metallkoffer und die Metallplatte sind ohne Erdung "ein bisschen" gefährlich.

 

Mein' ja nur...

Mario

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.