PPM Signal erzeugen

Hallo Ich bin noch dabei eine DIY RC Fernbedienung zu bauen.
Ich habe schon geschafft ein selbstgebauten Sender und Empfänger herzustellen.
Diese funktionieren simpel, PPM in den Sender rein und es kommt ein PPM Signal am Empfänger raus.

Nun zur eigentlichen Aufgabe in dieser Topic:
Ein PPM Signal zu erzeugen, dazu habe ich ein funktionierendes Beispiel weiter unten im Text.
Das ganze muss aber noch erweitert werden um:

  1. Anlaoge Potis sollen eingelesen werden und 6 Kanäle belegen
  2. Ein Taster soll bei Tastendruck ein kanal 7 bzw 8 auf 2000 setzten und beim nächsten drücken wieder auf 1000
  3. Ein OLED 128X64 soll mir die aktuellen werte Anzeigen

Das Klingt nach einer RIESEN Aufgabe aber ich hoffe ich hab es bald fertig.
Danke

//this programm will put out a PPM signal

//////////////////////CONFIGURATION///////////////////////////////
#define chanel_number 8  //set the number of chanels
#define default_servo_value 1500  //set the default servo value
#define PPM_FrLen 22500  //set the PPM frame length in microseconds (1ms = 1000µs)
#define PPM_PulseLen 300  //set the pulse length
#define onState 1  //set polarity of the pulses: 1 is positive, 0 is negative
#define sigPin 8  //set PPM signal output pin on the arduino
//////////////////////////////////////////////////////////////////


/*this array holds the servo values for the ppm signal
 change theese values in your code (usually servo values move between 1000 and 2000)*/
int ppm[chanel_number];

void setup(){  
  //initiallize default ppm values
  for(int i=0; i<chanel_number; i++){
    ppm[i]= default_servo_value;
  }

  pinMode(sigPin, OUTPUT);
  digitalWrite(sigPin, !onState);  //set the PPM signal pin to the default state (off)
  
  cli();
  TCCR1A = 0; // set entire TCCR1 register to 0
  TCCR1B = 0;
  
  OCR1A = 100;  // compare match register, change this
  TCCR1B |= (1 << WGM12);  // turn on CTC mode
  TCCR1B |= (1 << CS11);  // 8 prescaler: 0,5 microseconds at 16mhz
  TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
  sei();
}

void loop(){
  //put main code here
  static int val = 1;

  //TEST SIGNAL von 1000-1700
  ppm[0] = 1000;
  ppm[1] = 1100;
  ppm[2] = 1200;
  ppm[3] = 1300;
  ppm[4] = 1400;
  ppm[5] = 1500;
  ppm[6] = 1600;
  ppm[7] = 1700;
  
  delay(10);
}

ISR(TIMER1_COMPA_vect){  //leave this alone
  static boolean state = true;
  
  TCNT1 = 0;
  
  if(state) {  //start pulse
    digitalWrite(sigPin, onState);
    OCR1A = PPM_PulseLen * 2;
    state = false;
  }
  else{  //end pulse and calculate when to start the next pulse
    static byte cur_chan_numb;
    static unsigned int calc_rest;
  
    digitalWrite(sigPin, !onState);
    state = true;

    if(cur_chan_numb >= chanel_number){
      cur_chan_numb = 0;
      calc_rest = calc_rest + PPM_PulseLen;// 
      OCR1A = (PPM_FrLen - calc_rest) * 2;
      calc_rest = 0;
    }
    else{
      OCR1A = (ppm[cur_chan_numb] - PPM_PulseLen) * 2;
      calc_rest = calc_rest + ppm[cur_chan_numb];
      cur_chan_numb++;
    }     
  }
}

und was ist nun die Frage?

Die Frage ist:

Könnt ihr mir helfen das Ziel zu erreichen?
Habt ihr ein paar nette Ideen oder villt etwas ähnliches gefunden?

Ich habe schon 1. Abzuarbeiten hier könnt ihr euch das mal ansehen und Kritik üben.
Der Sender zeigt auf jedenfall die Position der Potis an.

//////////////////////CONFIGURATION///////////////////////////////
#define chanel_number 8  //set the number of chanels
#define default_servo_value 1500  //set the default servo value
#define PPM_FrLen 22500  //set the PPM frame length in microseconds (1ms = 1000µs)
#define PPM_PulseLen 300  //set the pulse length
#define onState 1  //set polarity of the pulses: 1 is positive, 0 is negative
#define sigPin 8  //set PPM signal output pin on the arduino
int ppm[chanel_number];

void setup() {
  //initiallize default ppm values
  for (int i = 0; i < chanel_number; i++) {
    ppm[i] = default_servo_value;
  }

  pinMode(sigPin, OUTPUT);
  digitalWrite(sigPin, !onState); 

  cli();
  TCCR1A = 0; // set entire TCCR1 register to 0
  TCCR1B = 0;

  OCR1A = 100;  // compare match register, change this
  TCCR1B |= (1 << WGM12);  // turn on CTC mode
  TCCR1B |= (1 << CS11);  // 8 prescaler: 0,5 microseconds at 16mhz
  TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
  sei();
}

void loop() {
  
  /* Ab hier geht es los:
  Aufgabe 1 Potis einlesen und zuordnen
  Aufgabe 2 Schalter einlesen und speichern
  Aufgabe 3 Display hinzufügen
  */
  
  int Kanal1 = map(analogRead(A0), 0, 1023, 1000, 2000);
  int Kanal2 = map(analogRead(A1), 0, 1023, 1000, 2000);
  int Kanal3 = map(analogRead(A2), 0, 1023, 1000, 2000);
  int Kanal4 = map(analogRead(A3), 0, 1023, 1000, 2000);
  int Kanal5 = map(analogRead(A4), 0, 1023, 1000, 2000);
  int Kanal6 = map(analogRead(A5), 0, 1023, 1000, 2000);
  int Kanal7 = 1300; //TEST
  int Kanal8 = 1800; //TEST
  
  ppm[0] = Kanal1;
  ppm[1] = Kanal2;
  ppm[2] = Kanal3;
  ppm[3] = Kanal4;
  ppm[4] = Kanal5;
  ppm[5] = Kanal6;
  ppm[6] = Kanal7;
  ppm[7] = Kanal8;

  delay(10);

}

ISR(TIMER1_COMPA_vect) { //leave this alone
  static boolean state = true;

  TCNT1 = 0;

  if (state) { //start pulse
    digitalWrite(sigPin, onState);
    OCR1A = PPM_PulseLen * 2;
    state = false;
  }
  else { //end pulse and calculate when to start the next pulse
    static byte cur_chan_numb;
    static unsigned int calc_rest;

    digitalWrite(sigPin, !onState);
    state = true;

    if (cur_chan_numb >= chanel_number) {
      cur_chan_numb = 0;
      calc_rest = calc_rest + PPM_PulseLen;//
      OCR1A = (PPM_FrLen - calc_rest) * 2;
      calc_rest = 0;
    }
    else {
      OCR1A = (ppm[cur_chan_numb] - PPM_PulseLen) * 2;
      calc_rest = calc_rest + ppm[cur_chan_numb];
      cur_chan_numb++;
    }
  }
}

Wo werden den die Positionen der Potis angezeigt?
Ich sehe noch keine Ausgabe am Sendesketch

Und das für Kanal 7 findest du in den Beispielen der IDE

na das schwierigste hast Du ja schon geschafft. Den Kram mit Kanal1 bis 6 kannst auch weglassen und direkt in das ppm Array schreiben. Macht zwar funktional keinen Unterschied, dafür wird der Code kürzer und meiner Meinung nach auch übersichtlicher.

We man mit einem Taster einen Wert toggeled steht tatsächlich in den Beispielen der IDE. Ich meine, für ein OLED gibt's auch ein Beispiel dort ... wenn nicht, finden sich zuhauf welche im Internet. Insgesamt ist das ganze Projekt nicht wirklich komplex. Mit ein wenig Recherche kriegst Du das sicher hin.

Hallo Danke ja das stimmt aber ich will noch ein paar funktionen wie Trimmen usw hinzufügen. Da muss ich doch noch die werte bearbeiten. Zu den Tasten toggle hab ich mich belesen und mal ein einfaches Programm geschrieben wie ich das einbauen würde. Ist das sinnvoll oder kann man das noch verbessern?

void setup() {

  
  pinMode(2, INPUT);
  Kanal7 = 1000;

}


void loop() {


  Taster7Neu = digitalRead(2);

  if (Taster7Neu != Taster7Alt)
  {
    Taster7Alt = Taster7Neu;
    if (Taster7Neu != 0) 
    {
      Kanal7 = Kanal7 + 200;
      if (Kanal7 > 2000) 
      {
        Kanal7 = 1000;
      }
    }
  }

Hier mal noch der Aktuelle Stand der Arbeit.
Der Arduino benutzt schon 50% seiner Resourcen das macht mir etwas sorgen

//////////////////////CONFIGURATION  PPM///////////////////////////////
#define chanel_number 8  //set the number of chanels
#define default_servo_value 1500  //set the default servo value
#define PPM_FrLen 22500  //set the PPM frame length in microseconds (1ms = 1000µs)
#define PPM_PulseLen 300  //set the pulse length
#define onState 1  //set polarity of the pulses: 1 is positive, 0 is negative
#define sigPin 2  //set PPM signal output pin on the arduino
int ppm[chanel_number];

//////////////////////CONFIGURATION  DISPLAY///////////////////////////////
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET 4 // not used / nicht genutzt bei diesem Display
Adafruit_SSD1306 display(OLED_RESET);



void setup() {

//////////////////////SETUP  PPM///////////////////////////////  
  Serial.begin(9600);
  for (int i = 0; i < chanel_number; i++) {
  ppm[i] = default_servo_value;
  }

  pinMode(sigPin, OUTPUT);
  digitalWrite(sigPin, !onState);
  pinMode(3, INPUT);
  pinMode(4, INPUT); 

  cli();
  TCCR1A = 0; 
  TCCR1B = 0;

  OCR1A = 100;  
  TCCR1B |= (1 << WGM12);  
  TCCR1B |= (1 << CS11);  
  TIMSK1 |= (1 << OCIE1A);
  sei();
  
//////////////////////SETUP  DISPLAY///////////////////////////////

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  randomSeed(analogRead(0));
}

#define DRAW_DELAY 118
#define D_NUM 47

void loop() {

//////////////////////PROCESSING  PPM///////////////////////////////
  /* Ab hier geht es los:
  Aufgabe 1 Potis einlesen und zuordnen
  Aufgabe 2 Schalter einlesen und speichern
  Aufgabe 3 Display hinzufügen
  */
  
  int Kanal1 = map(analogRead(A0), 0, 1023, 1000, 2000);
  int Kanal2 = map(analogRead(A1), 0, 1023, 1000, 2000);
  int Kanal3 = map(analogRead(A2), 0, 1023, 1000, 2000);
  int Kanal4 = map(analogRead(A3), 0, 1023, 1000, 2000);
  int Kanal5 = map(analogRead(A6), 0, 1023, 1000, 2000);
  int Kanal6 = map(analogRead(A7), 0, 1023, 1000, 2000);
  int Kanal7 = map(digitalRead(3), 0, 1, 1000, 2000);
  int Kanal8 = map(digitalRead(4), 0, 1, 1000, 2000);
  
  ppm[0] = Kanal1;
  ppm[1] = Kanal2;
  ppm[2] = Kanal3;
  ppm[3] = Kanal4;
  ppm[4] = Kanal5;
  ppm[5] = Kanal6;
  ppm[6] = Kanal7;
  ppm[7] = Kanal8;

//////////////////////CONTROL/TEST AREA//////////////////////////////
  
  /*
  Serial.print("    Kanal 1: ");
  Serial.print(Kanal1);
  Serial.print("    Kanal 2: ");
  Serial.print(Kanal2);
  Serial.print("    Kanal 3: ");
  Serial.print(Kanal3);
  Serial.print("    Kanal 4: ");
  Serial.print(Kanal4);
  Serial.print("    Kanal 5: ");
  Serial.print(Kanal5);
  Serial.print("    Kanal 6: ");
  Serial.print(Kanal6);
  Serial.print("    Kanal 7: ");
  Serial.print(Kanal7);
  Serial.print("    Kanal 8: ");
  Serial.println(Kanal8);
  */

  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setTextSize(1);
  
  display.setCursor(1,1);
  display.println("123: ");
  display.setCursor(30,1);
  display.println(Kanal1);
  display.setCursor(65,1);
  display.println(Kanal2);
  display.setCursor(100,1);
  display.println(Kanal3);  

  display.setCursor(1,11);
  display.println("456: ");
  display.setCursor(30,11);
  display.println(Kanal4);
  display.setCursor(65,11);
  display.println(Kanal5);
  display.setCursor(100,11);
  display.println(Kanal6);

    display.setCursor(65,21);
  display.println(Kanal7);
  display.setCursor(100,21);
  display.println(Kanal8);

  display.display();
 
  delay(10);

}

//////////////////////OUTUPUT  PPM///////////////////////////////

ISR(TIMER1_COMPA_vect) { //leave this alone
  static boolean state = true;

  TCNT1 = 0;

  if (state) { //start pulse
    digitalWrite(sigPin, onState);
    OCR1A = PPM_PulseLen * 2;
    state = false;
  }
  else { //end pulse and calculate when to start the next pulse
    static byte cur_chan_numb;
    static unsigned int calc_rest;

    digitalWrite(sigPin, !onState);
    state = true;

    if (cur_chan_numb >= chanel_number) {
      cur_chan_numb = 0;
      calc_rest = calc_rest + PPM_PulseLen;//
      OCR1A = (PPM_FrLen - calc_rest) * 2;
      calc_rest = 0;
    }
    else {
      OCR1A = (ppm[cur_chan_numb] - PPM_PulseLen) * 2;
      calc_rest = calc_rest + ppm[cur_chan_numb];
      cur_chan_numb++;
    }
  }
}

Was denkst du, warum eine halbwegs brauchbare Fernsteuerung keinen 328 drin hat?

Also kann ich mir nur auf Grundlegende Funktionen beschränken.

Habt ihr ne Idee wie mal ich vernünftige Steuerknüppel preiswert komme? Das ist das einzige was ich da habe und was es auf Ebay gibt
https://www.ebay.de/itm/152624667412

Die sind für RC Zwecke ungeeignet.

Hier sind recht ordentliche drin, auch eine pwm Erzeugung: i6