PPM Impulsdauer -> Auswertung (pulseIn, interrupt,...)

Guten Abend zusammen,

auf dem Dachboden lag nach eine Fernsteuerung 2Kanal 2.4Ghz, welche nun umfunktioniert werden soll, als Funksender für kleine Daten.
Bisher habe ich mit dem DSO112A herausgefunden, dass die Impulsdauer von ~0,95ms bis ~2.10ms variiert. Das ganze wiederholt sich alle ~20ms (50Hz).

Nun wollte ich mit dem Arduino die Impulsdauer auswerten, ohne grosse Auswirkungen auf die Zykluszeit.
Versuch 1: mit pulseIn() (Problem wenn kein Signal anliegt sehr hohe Wartezeit in pulseIn())

const uint8_t signal_PPM = 2; //Interrupt faehiger Pin (UNO)
const uint8_t status_LED = 13;
const uint16_t low_PPM = 1200;
const uint16_t high_PPM = 1800;
uint16_t dauer_PPM, max_us;

void setup()
{
  Serial.begin(19200);
  while (!Serial) {}
  pinMode(signal_PPM, INPUT);
  pinMode(status_LED, LED_BUILTIN);
}
void loop()
{
  uint32_t start_us = micros();
  noInterrupts();
  dauer_PPM = pulseIn(signal_PPM, HIGH); //timeout moeglich
  interrupts();

  if (dauer_PPM >= high_PPM)
  {
    digitalWrite(status_LED, HIGH);
  }
  else
  {
    digitalWrite(status_LED, LOW);
  }
  uint32_t ende_us = micros();
  uint16_t dauer_loop = ende_us - start_us;
  if (dauer_loop > max_us)
  {
    max_us = dauer_loop;
  }
  Serial.print("PPM = "); //test ohne F()
  Serial.print(dauer_PPM);
  Serial.print("\tmax_us = ");
  Serial.println(max_us);
}
//AUSGABE: PPM = 1322	max_us = 1988

Frage zwischendurch: Macht die Zykluszeiterfassung mit micros() ueberhaupt Sinn? Wird waehrend eines Interrupts der micros-Zaehler hochgezaehlt? :slight_smile:
Versuch 2: attacheInterrupt(...,...,CHANGE)

const uint8_t signal_PPM = 2; //Interrupt faehiger Pin (UNO)
const uint8_t status_LED = 13;
const uint16_t low_PPM = 1200;
const uint16_t high_PPM = 1800;
volatile uint32_t PPM_start = 0;
volatile uint32_t PPM_stopp = 0;
uint16_t dauer_PPM, max_us;

void get_PPM()
{
  if (digitalRead(signal_PPM)) //Beidseitige Verzoegerung (unrelevant?)
  {
    PPM_start = micros();
  }
  else
  {
    PPM_stopp = micros();
  }
}

void setup()
{
  Serial.begin(19200);
  while (!Serial) {}
  pinMode(signal_PPM, INPUT);
  pinMode(status_LED, LED_BUILTIN);
  attachInterrupt(digitalPinToInterrupt(signal_PPM), get_PPM, CHANGE);
}
void loop()
{
  uint32_t start_us = micros();
  if (PPM_start < PPM_stopp)
  {
    dauer_PPM = PPM_stopp - PPM_start;
  }
  if (dauer_PPM >= high_PPM)
  {
    digitalWrite(status_LED, HIGH);
  }
  else
  {
    digitalWrite(status_LED, LOW);
  }
  uint32_t ende_us = micros();
  uint16_t dauer_loop = ende_us - start_us;
  if (dauer_loop > max_us)
  {
    max_us = dauer_loop;
  }
  Serial.print("PPM = "); //test ohne F()
  Serial.print(dauer_PPM);
  Serial.print("\tmax_us = ");
  Serial.println(max_us);
}
//AUSGABE: PPM = 1321	max_us = 24

Versuch 3: attacheInterrupt(...) verschieben
(Problem dauer_PPM instabil)

const uint8_t signal_PPM = 2; //Interrupt faehiger Pin (UNO)
const uint8_t status_LED = 13;
const uint16_t low_PPM = 1200;
const uint16_t high_PPM = 1800;
volatile uint32_t PPM_start = 0;
volatile uint32_t PPM_stopp = 0;
uint16_t max_us;
uint32_t dauer_PPM;

void get_start()
{
  PPM_start = micros();
  detachInterrupt(digitalPinToInterrupt(signal_PPM));
  attachInterrupt(digitalPinToInterrupt(signal_PPM), get_stopp, FALLING);
}
void get_stopp()
{
  PPM_stopp = micros();
  detachInterrupt(digitalPinToInterrupt(signal_PPM));
  attachInterrupt(digitalPinToInterrupt(signal_PPM), get_start, RISING);
}
void setup()
{
  Serial.begin(19200);
  while (!Serial) {}
  pinMode(signal_PPM, INPUT);
  pinMode(status_LED, LED_BUILTIN);
  attachInterrupt(digitalPinToInterrupt(signal_PPM), get_start, RISING);
}
void loop()
{
  uint32_t start_us = micros();
  dauer_PPM = PPM_stopp - PPM_start;
  if (dauer_PPM >= high_PPM)
  {
    digitalWrite(status_LED, HIGH);
  }
  else
  {
    digitalWrite(status_LED, LOW);
  }
  uint32_t ende_us = micros();
  uint16_t dauer_loop = ende_us - start_us;
  if (dauer_loop > max_us)
  {
    max_us = dauer_loop;
  }
  Serial.print("PPM = "); //test ohne F()
  Serial.print(dauer_PPM);
  Serial.print("\tmax_us = ");
  Serial.println(max_us);
}
//AUSGABE: PPM = 1321	max_us = 20
FEHLERFALL: PPM = 4294948472	max_us = 20

Versuch 2 scheint fuer mich am "besten" zu sein. Wie ist Euere Erfahrung?
Vielen Dank
Grillgemuese :slight_smile:

Für das Einlesen von ppm-Signalen gibt es eine (halb-)fertige, aber brauchbare Lib.

Such mal nach arduino rc library

Man kann auch bei der Analyse des Codes einer Lib viel lernen. Du musst sie ja nicht blind übernehmen.

Gruß Tommy

Tommy56:
Man kann auch bei der Analyse des Codes einer Lib viel lernen. Du musst sie ja nicht blind übernehmen.

Ein wahres Wort gelassen ausgesprochen +1 und ganz Deiner Meinung (zumindest hier :wink: )

postmaster-ino:
ganz Deiner Meinung (zumindest hier :wink: )

Wenn wir immer der gleichen Meinung wären, wäre das doch langweilig :wink:

Gruß Tommy