Impulse mit Arduino aufnehmen (Flankenerkennung)?

Guten Tag,

Also bekomme einen Impuls z.B 200ms auf 5V dann wieder auf 0V und von diesem möchte ich mit meinem Arduino die Zeit messen.

Mir gehts es aber jetzt nur darum, dass ich die positive und negative Flanke erkenne.

In meinem Loop stehen diese Simplen bedingungen. Das PINB, bei dem die Zustände der Eingangspins angezeigt werden, gebe ich mir über eine Interrupt-Funktion aus. Das Eingangssignal wird mit einem externen 10k Pulldown bearbeitet und wird klar vom Arduino erkannt. Lass mir mein PINB auf das PORTD spielen, und den Impuls (Rechtecksignal) auf eine LED ausgeben und das funktioniert prima.

Das Problem liegt darin, dass nicht alle Flanken erkannt werden, und ich habe keine Ahnung mehr wieso. Liegt auch nicht am Mikrocontroller, hab verschiedene Nano und Unos schon probiert.

Achja, der Counter dient nur zum Debugging aber den kann man erstmal vernässigen. Gleich wie die Serial.println. Millisekunden ist die aktuelle Zeit in Millisekunden seitdem der Arduino an ist.

Hier der Code, der erkennt ob eine positive oder negative Flanke anliegt:

  if(PINB != last_PINB){
    Serial.println("hi");
    if((PINB & (1 << Morse_Code))){
      POS = millisekunden;
      Serial.println("POS");
      counter++;
    }
    if(!(PINB & (1 << Morse_Code))){
      NEG = millisekunden;
      Serial.println("NEG");
      counter++;
    }
  }

Meistens erkennt er nur entweder eine positive Flanke, eine negative Flanke oder gar nichts. Obwohl die LED am PORTD das Eingagssignal nachläuft.

Mein last_PINB ist als unsigned char definiert und wird am Ende vom loop() mit = PINB gleichgesetzt.

Hab ich etwas übersehen? Komme so nicht drauf.

lg Sebastian

Moin,
wiefern erkennt er deine Flanke nicht? Geht er nicht in die Abfrage oder funktioniert das mit deinen Millisekunden nicht? (GGF Overflow?)
Wenn er nur nicht in die Abfrage geht ist es vermutlich ungünstige Zykluszeit, wenn du zwischen Abfrage? Speichern des "last_PINB" zu viel Script hast & dann währenddessen der Zustand ändert kann das der Controller natürlich nicht ahnen.
Andere frage: wieso holst du dir dein Pin über eine Interrupt Funktion und ließt ihn nicht einfach ein? Eventuell passiert durch diese Programmsprünge dein Problem?

Guten Tag, Danke für die Antwort. Also den PIN lese ich schon ganz normal ein ohne Interrupt. Hab meinen Timer mithilfen im Setup eingestellt, sodass er jede 1ms in eine Interruptfunktion geht, bei dem er die Variable millisekunden um 1 rauf zählt. Dort habe ich auch gleich ne Ausgabe reingemacht:

ISR(TIMER0_COMPA_vect) {
  millisekunden++;
  if (millisekunden - last_msg >= 1000) {
    sprintf(buffer, "t=[%lu] NEG = [%lu] POS = [%lu] Dit=[%lu] Dah=[%lu], PINB=[%d], last_PINB[%d]", millisekunden, NEG, POS, Dit, Dah, PINB, last_PINB );
    Serial.println(buffer);
    last_msg = millisekunden;
    Serial.println(code);
    Serial.println(counter);
  }
}

Also die Ausgabe erfolgt wie gewollt alle 1000ms, also der Millisekunden Timer funktioniert schon. Den Loop läuft er auch durch, weil dort wird auch meine LED welche das Input Signal praktisch kopiert angesteuert.

Er geht nicht in die Abfrage rein, kann sein das irgendwas mit dem last_PINB nicht funktioniert, aber sollte schon passen, zumindest ist die definiation und programmierung gleich wie all den Programmen zuvor.

Hier ist noch mein ganzer Loop:

void loop() {
  if(!(PINB == last_PINB)){
    Serial.println("hi");
    if((PINB & (1 << Morse_Code))){
      POS = millisekunden;
      Serial.println("POS");
      counter++;
    }
    if(!(PINB & (1 << Morse_Code))){
      NEG = millisekunden;
      Serial.println("NEG");
      counter++;
    }
  }

  if(!(PINB & (1 << Morse_Code))){
    PORTD &= ~(1 << Check_LED);
  }else{
    PORTD |= (1 << Check_LED);
  }

  last_PINB = PINB;
  last_PORTD = PORTD;

}

Warum nutzt Du nicht die vorhandene Funktion millis()?

Gruß Tommy

Würde gehen, hatten nur damals mal in einem Test die Vorgabe uns einen eigenen Timer zu erstellen und dann hab ich den einfach weiter verwendet. Kann ja mal die Defination vom Setup schicken:

void setup() {
  DDRD |= (1 << Check_LED);
  DDRB = 0x00; 

  PORTB = 0xff; //Turn off Pull-Up resistor

  //Timer Setup see: Atmega328p Datasheet
  TCCR0A = (1 << WGM01);              
  TCCR0B |= (1 << CS01) | (1 << CS00); 
  OCR0A = 250;

  TIMSK0 |= (1 << OCIE0A);

  Dit = (1200 / WPM);
  Dah = (1200 / WPM) * 3;
  Serial.begin(9600);
}

lg

Funktioniert jedoch mit der millis() und ohne meinen eigenen Timer mit Interrupt auch nicht...

#include "Arduino.h"
#include <ctype.h>

//INPUTS
#define Morse_Code (PB4)

//OUTPUTS
#define Check_LED (PD7)

//TIMES
volatile unsigned long int millisekunden;
unsigned long int POS;
unsigned long int NEG;
unsigned long int Dit;
unsigned long int Dah;
int WPM = 6;
unsigned int counter;
#define T_BLINK (500)
#define T_PRELLEN (200)

//Variables for last Loop
unsigned char last_PINB;
unsigned char last_PORTD;
unsigned long int last_msg;

//Global Variables
char buffer[128];
//String code = "";

void setup() {
  DDRD |= (1 << Check_LED);
  DDRB = 0x00; 
  PORTB = 0xff; //Turn off Pull-Up resistor

  Dit = (1200 / WPM);
  Dah = (1200 / WPM) * 3;
  Serial.begin(9600);
}

void loop() {
  if(!(PINB == last_PINB)){
    Serial.println("hi");
    if((PINB & (1 << Morse_Code))){
      POS = millis();
      Serial.println("POS");
      counter++;
    }
    if(!(PINB & (1 << Morse_Code))){
      NEG = millis();
      Serial.println("NEG");
      counter++;
    }
  }

  if(!(PINB & (1 << Morse_Code))){
    PORTD &= ~(1 << Check_LED);
  }else{
    PORTD |= (1 << Check_LED);
  }

  last_PINB = PINB;
  last_PORTD = PORTD;
}

So habe nun das last_PINB direkt dort gespeichert, wo ich entscheide ob es eine negative oder positive Flanke ist und es funktioniert perfekt. Woren es zuvor gescheitert ist, weiß ich nicht. Wohl irgendein Overflow fehler oder so.

void loop() {
  if(last_PINB != PINB){
    Serial.println("hi");
    if((PINB & (1 << Morse_Code))){
      POS = millis();
      Serial.println("POS");
      counter++;
      last_PINB = PINB;
    }
    if(!(PINB & (1 << Morse_Code))){
      NEG = millis();
      Serial.println("NEG");
      counter++;
      last_PINB = PINB;
    }
  }

  if(!(PINB & (1 << Morse_Code))){
    PORTD &= ~(1 << Check_LED);
  }else if((PINB & (1 << Morse_Code))){
    PORTD |= (1 << Check_LED);
  }

  last_PORTD = PORTD;
}

Danke euch @Tommy56 @tjard-frischling