Serial Communication Radiosoftware (mAirlist)

Hallo,
Ich klink mich hier mal ein, mein Thema passt denke ich bestens dazu. Ich möchte per serieller Kommunikation eine Radiosoftware (mAirlist) steuern, und von dieser Software Kommandos an den Arduino geben zum ansteuern von Statusleds.

Die LED Steuerung funktioniert soweit, nur Unterstützt die Radiosoftware per serieller Kommunikation nur Textbefehle wie z.B. ON AIR Der Programmierer gab mir den Tip :
"Jeder Befehl muss mit (ASCII 13) abgeschlossen sein."

So habe ich es bisher versucht, allerdings kommt bei Tastendruck nichts an der seriellen Konsole an(Der LEDPart funktioniert:

// Pin 13 has an LED connected on most Arduino boards.
// give it a name:
int led = 13;
int tasterpin = 8;
int tasterstatus;


void setup()
{  
  Serial.begin(9600);
    // initialize the digital pin as an output.
  pinMode(led, OUTPUT); 
}

void loop() 
{
  if (Serial.available()) // auf Daten am serielle-Port warten
  {
    byte comand = Serial.read(); // Daten Byte in die Variable comand schreiben
      if (comand == 48) // comand auswerten ASCII 0
      digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)


      if (comand == 49) // comand auswerten ASCII 1
      digitalWrite(led, LOW);   // turn the LED off 
      {
tasterstatus = digitalRead(tasterpin);
if(tasterstatus == HIGH)
  Serial.print("ON AIR""");

}
  }
}

Wo liegt mein Fehler?

@Beliar:
Auch wenn es ein ähnliches Problem ist, wäre es besser, wenn Du dafür einen eigenen Thread aufmachen würdest. Sonst ist es unmöglich auseinander zu halten ob eine Antwort in diesem Thread nun zu Deiner Frage oder zu der ursprünglichen gehört.
Zu Deinem Problem. Soll jetzt der Arduino Kommandos an die Software schicken, oder die Software Kommandos an den Arduino?
Dein Programm hat leider keine gute Struktur, denn Du vermischt senden und empfangen von Daten. Der Taster wird nur abgefragt, wenn vorher Daten seriell empfangen wurden, denn sämtliche Befehle stehen innerhalb des "if (Serial.available())" Blocks.
Aber selbst wenn das klappen würde, sendest Du kein , da Du nur "Serial.print()" verwendest. "Serial.println()" sendet einen Zeilenumbruch nach der Ausgabe automatisch. Alternativ kannst Du den Zeilenumbruch auch in den String mit einbauen : "ON AIR\n" (Das \n ist ein Sonderzeichen für den Zeilenwechsel).
Mario.

Erstmal danke fürs umherschubsen. Mein Ardu soll beides machen. Befehle an die Software senden, und die Software einen Status als rückmeldung an den Ardu.

Das mit der Quittung an den Arduino klappt ja soweit. Nur das senden an die softwatre noch nicht.
Wenn ich das jetzt richtig verstehe, dann muss die Statusabfrage getrennt von der Kommandogabe im Script stehen? Wie müsste denn dann das Script umgeschrieben werden, das empfang und senden getrennt voneinander laufen?

Eins noch, wäre der automatische Zeilenumbruch das gleiche Signal wie ein ? Oder wie sende ich mit ON AIR dann noch einen mit Tastendruck? Weil das Programm braucht eben die Ausgeschriebenen Befehle mit nem <CR< dahinter. Warum auch immer er das so Programmiert hat...

Gruss

Sodale, nun sind wir schon einen Schritt weiter. Dank des Programmieres von mAirlist weiss ich nun das es ein /r sein muss. Damit klappt es im Grundlegenden auch schon mit folgendem Programm(Schalter vor Serial gestellt):

// Pin 13 has an LED connected on most Arduino boards.
// give it a name:
int led = 13;
int tasterpin1 = 8;
int tasterstatus;


void setup()
{  
  Serial.begin(9600);
    // initialize the digital pin as an output.
  pinMode(led, OUTPUT); 
}

void loop() 
    {
      {
tasterstatus = digitalRead(tasterpin1);
if(tasterstatus == HIGH)
  Serial.print("ON AIR\r");
 delay(1000);  
}
      {
tasterstatus = digitalRead(tasterpin1);
if(tasterstatus == HIGH)
  Serial.print("OFF AIR\r");
 delay(250);  
}

  if (Serial.available()) // auf Daten am serielle-Port warten
  {
    byte comand = Serial.read(); // Daten Byte in die Variable comand schreiben
      if (comand == 48) // comand auswerten ASCII 0
      digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)


      if (comand == 49) // comand auswerten ASCII 1
      digitalWrite(led, LOW);   // turn the LED off 

  }
}

Nun habe ich aber das Problem das es selbst bei kurzer Tasterbetätigung den Befehl etliche male Sendet. Da grad ON AIR und OFF AIR über eine Taste geschaltet wird würde ich immer zw. ON und OFF wechseln bei einer betätigung.
Nun habe ich deshalb die Delays eingefügt, allerdings verzögert darurch auch die LED, und ich halte es so nicht für die beste Lösung. Zumal je nach Delaylänge es immernoch dazu kommen könnte das man sofort wieder OFF schaltet.

Gibt es hierzu eine galantere Lösung?

Grüssle

Ja gibt es. Schau Dir mal die Beispiele "Debounce" und "BlinkWithoutDelay" aus der IDE an.

Beim "Debounce" geht es darum, das der Schalter prellt, also beim Schalten mehrmals HIGH und LOW liefert. Das ist ein mechanisches Problem und kann entweder Schaltungstechnisch gelöst werden, z.B. durch einen einfachen Kondensator oder gleich richtig mit einem FlipFlop. Hier gibt es eine sehr gute Einführung in das Thema: Entprellung – Mikrocontroller.net
Ein Entprellen per Software geht auch, hat aber immer den Nachteil das Dein Programm komplexer wird und Du gewisse Wartezeiten einbauen mußt.

Das BlinkWithoutDelay ist ein Beispiel das zeigt, wie man Programme schreibt die für bestimmte Aufgaben warten, bzw. die Ausführung bestimmter Aufgaben verzögern, ohne das blockierende delay() zu verwenden. Der Trick dabei ist, das man den Ablauf von loop() nicht mit einem delay() blockiert, sondern sich zu einem Zeitpunkt X den aktuellen Wert von millis() merkt ( unsigned long start = millis() ). Nun fragt man bei jedem Durchlauf von loop() an der gleichen Stelle ab, ob der aktuelle Wert von millis() minus dem gemerkten Wert schon größer als das gewünschte Interval in Millisekunden ist ( if(millis() - start > 1000) ... ). Wenn nicht, führt man die zu verzögernde Aktion noch nicht aus, kann im Rest von loop() aber trotzdem noch andere Dinge machen. Wichtig ist, das auch keine anderen Programmteile mit delay() den Ablauf blockieren. Je schneller loop() ausgeführt wird, desto genauer ist das Warten.

Mario.

Danke erstmal....

Wioe müsste es denn bei meinem bisherigem Code geändert werden mit debounce? Wenn ich das richtig sehe wird im Beispiel mein Taster ja zum Umschalter. Das soll ja so nicht sein. Er soll ja nur jeweils einen Impuls senden. Und beim 2. betätigen einen anderen....

Ginge das auch nach dem Beispiel wie es hier

beschrieben ist? Denn das sieht auf den ersten Blick einfacher aus.

Alle anderen Taster werden nur eine Funktion haben, nur dieser eine soll beim 1. drücken einschalten (ON AIR) und beim 2. drücken dann ausschalten(OFF AIR).

Rein von der Theorie funktioniert das nun ja auch schon, nur eben nicht entprellt.

Das von Dir verlinkte PDF zitiert den meisten Teil aus dem von mir verlinkten Tutorial des microcontroller.net Forums.
Auch hat die Funktion des Tasters (Umschalter, Ein-/Aus-Schalter, etc.) erstmal nichts mit dem entprellen zu tun.
Beim Entprellen geht es ja erstmal darum überhaupt das Drücken und ggf. wieder Loslassen des Tasters eindeutig zu erkennen. Was das Programm dann mit der Information das der Taster X gedrückt wurde anfängt, ist erstmal egal. Fakt ist aber, das ohne Entprellen meistens mehrere Tasten-Ereignisse erkannt werden, obwohl es nur eins gab und das wird immer zu Problemen führen. Das kannst Du ja an Deinem Beispiel ganz gut beobachten wie oft das "ON AIR" und "OFF AIR" gesendet wird, obwohl Du nur einmal den Taster drückst.

Wenn ich das richtig sehe wird im Beispiel mein Taster ja zum Umschalter. Das soll ja so nicht sein.

Doch, genau das ist er. Der Taster schaltet zwischen den beiden Zuständen "ON AIR" und "OFF AIR" um.

Die Frage welche Lösung nun für Dein Projekt sinnvoll ist, mußt Du selbst entscheiden. Die Softwarelösung ist "billiger", weil man weniger Schaltungsaufwand hat. Software-Debounce macht aber immer das Programm komplexer. Entprellen per Hardware macht das Programm übersichtlicher, weil man dich darauf verlassen kann, das ein Flanken-Wechsel auch genau einmal drücken ist.

Also nun komme ich absolut nicht weiter...

Ich habe unzählige male versucht meinen obigen Code um folgenden Code zu erweitern, aber es funktioniert nicht.

/* 
 Debounce
 
 Each time the input pin goes from LOW to HIGH (e.g. because of a push-button
 press), the output pin is toggled from LOW to HIGH or HIGH to LOW.  There's
 a minimum delay between toggles to debounce the circuit (i.e. to ignore
 noise).  
 
 The circuit:
 * LED attached from pin 13 to ground
 * pushbutton attached from pin 2 to +5V
 * 10K resistor attached from pin 2 to ground
 
 * Note: On most Arduino boards, there is already an LED on the board
 connected to pin 13, so you don't need any extra components for this example.
 
 
 created 21 November 2006
 by David A. Mellis
 modified 30 Aug 2011
 by Limor Fried
 
This example code is in the public domain.
 
 http://www.arduino.cc/en/Tutorial/Debounce
 */

// constants won't change. They're used here to 
// set pin numbers:
const int buttonPin = 2;     // the number of the pushbutton pin
const int ledPin =  13;      // the number of the LED pin

// Variables will change:
int ledState = HIGH;         // the current state of the output pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button 
  // (i.e. the input went from LOW to HIGH),  and you've waited 
  // long enough since the last press to ignore any noise:  

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  } 
  
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    buttonState = reading;
  }
  
  // set the LED using the state of the button:
  digitalWrite(ledPin, buttonState);

  // save the reading.  Next time through the loop,
  // it'll be the lastButtonState:
  lastButtonState = reading;
}

Hier benötige ich fortgeschrittene Hilfe. Wie baue ich das Bounce anstelle von Delay in meinen Code ein?

Ok, viel gegoogelt, viel umherprobiert, aber nicht wirklich mit Bounce weiter gekommen.

Nun habe ich aber folgendes probiert:

const int LED = 13;    // the pin for the LED
const int BUTTON = 7;  // the input pin where the
                    // pushbutton is connected
int val = 0;    // val will be used to store the state
               // of the input pin
int old_val = 0; // this variable stores the previous
               // value of "val"
int state = 0;   // 0 = LED off and 1 = LED on


void setup() {
  pinMode(LED, OUTPUT);   // tell Arduino LED is an output
  pinMode(BUTTON, INPUT); // and BUTTON is an input
 Serial.begin(9600);
}


void loop(){
 val = digitalRead(BUTTON); // read input value and store it
                        // yum, fresh


 // check if there was a transition
 if ((val == HIGH) && (old_val == LOW)){
   state = 1 - state;
   delay(10);
 }


 old_val = val; // val is now old, let's store it


 if (state == 1) {
  // digitalWrite(LED, HIGH); // turn LED ON
    Serial.print("ON AIR\r");
 } else {
  // digitalWrite(LED, LOW);
   Serial.print("OFF AIR\r");
 }

  if (Serial.available()) // auf Daten am serielle-Port warten
  {
    byte comand = Serial.read(); // Daten Byte in die Variable comand schreiben
      if (comand == 48) // comand auswerten ASCII 0
      digitalWrite(LED, HIGH);   // turn the LED on (HIGH is the voltage level)


      if (comand == 49) // comand auswerten ASCII 1
      digitalWrite(LED, LOW);   // turn the LED off 

  }
}

Das funktioniert soweit ja ganz gut, allerdings werden meine Serial.print("ON AIR\r"); und Serial.print("OFF AIR\r"); nun jeweils endlos gesendet. Lässt sich das ändern das der befehl nur einmal gesendet wird?
Weil mit Bounce komme ich absolut nicht weiter.

Einmal drücken Serial.print("ON AIR\r"); nächstes mal drücken Serial.print("OFF AIR\r");

Lässt sich das ändern das der befehl nur einmal gesendet wird?

Natürlich :wink:

Achte auf die geschweiften Klammern und du wirst erkennen, die Stelle wo du deine Serial.print(ON / OFF) einbauen willst ist da wo das delay(10) sitzt.

(übrigens, delay(10) zum Entprellen ist voll in Ordnung, finde ich. Mach di da mal keine Sorgen )

Vielen Dank! Das sollte ich hinbekommen.... :wink: