Programm-Ablauf-Tip gesucht

Es geht mal wieder um meine Sprengersteuerung.

Ich schalte meine Sprenger über einen Homematic-Sender zeitversetzt mit der TimeAlarmLib

Jetzt bietet der Sender eine LED Statusmeldung (Seite10) ob Senden erfolgreich war. :wink:

Diese möchte ich abfangen & auswerten. :o

Gelbe LED(Status), grüne LED (senden ok), rote LED (senden fehlerhaft).

Wenn ein Sendesignal rausgeht leuchten erst mal alle 3 LED.

Schaltet die gelbe Status LED nach einigen sec aus kann in den folgenden ca. 2s die grüne und rote LED ausgelesen werden. Also Status auslesen nach Flankenwechsel H->L der gelben LED.

Das Test-Auswerten über die MCP23008 Porterweiterung per I2C klappt prima… Jubel! 8)

#include <Wire.h>
#include "Adafruit_MCP23008.h"

#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library
#include <SPI.h>



#define TFT_CS     10
#define TFT_RST    9  // you can also connect this to the Arduino reset
                      // in which case, set this #define pin to 0!
#define TFT_DC     8
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS,  TFT_DC, TFT_RST);

// Option 2: use any pins but a little slower!
#define TFT_SCLK 13   // set these to be whatever pins you like!
#define TFT_MOSI 11   // set these to be whatever pins you like!





// Basic pin reading and pullup test for the MCP23008 I/O expander
// public domain!

// Connect pin #1 of the expander to Analog 5 (i2c clock)
// Connect pin #2 of the expander to Analog 4 (i2c data)
// Connect pins #3, 4 and 5 of the expander to ground (address selection)
// Connect pin #6 and 18 of the expander to 5V (power and reset disable)
// Connect pin #9 of the expander to ground (common ground)

// Input #0 is on pin 10 so connect a button or switch from there to ground

Adafruit_MCP23008 mcp;

bool S_state;
bool G_state;
bool R_state;
bool S_laststate;





  
void setup() {  
  mcp.begin();      // use default address 0

  mcp.pinMode(0, INPUT);
  mcp.pullUp(0, HIGH);  // turn on a 100K pullup internally
  mcp.pinMode(1, INPUT);
  mcp.pullUp(1, HIGH);  // turn on a 100K pullup internally
  mcp.pinMode(2, INPUT);
  mcp.pullUp(2, HIGH);  // turn on a 100K pullup internally

  pinMode(13, OUTPUT);  // use the p13 LED as debugging


   
  tft.initR(INITR_BLACKTAB);   // initialize a ST7735S chip, black tab

  tft.fillScreen(ST7735_BLACK);     //Display löschen
  
  tft.setRotation(-1);              //Displayrichtung einstellen

  tft.setTextColor(ST7735_WHITE);
  tft.setTextSize(1);
  tft.println("Erkennen Sendestatus");
  delay(2500);
  tft.fillScreen(ST7735_BLACK);     //Display löschen
    

  S_state = HIGH;
  S_laststate = HIGH;
}



void loop() {
  // The LED will 'echo' the button
  digitalWrite(13, mcp.digitalRead(0));

  //Display löschen
  tft.setTextWrap(false);
  tft.fillScreen(ST7735_BLACK);


  S_state = mcp.digitalRead(0);             //gelbe Status LED
  G_state = mcp.digitalRead(1);             //grüne LED Fehler
  R_state = mcp.digitalRead(2);             //rote LED OK
  
  if(S_laststate == HIGH && S_state == LOW)                   //Bei Flankenwechsel gelbe LED H->L wird Sendestatus vob grüner & roter LED abgefragt
  {
    tft.setCursor(0, 0);
    tft.setTextColor(ST7735_YELLOW);
    tft.setTextSize(1);
    tft.println("Eing. 0 = Flanke H -> L");
    delay(700);
    if(G_state == HIGH && R_state == LOW)                     //Abfrage grüne LED nach abschalten gelbe LED Senden OK
    {
      tft.setCursor(0, 12);
      tft.setTextColor(ST7735_GREEN);
      tft.setTextSize(1);
      tft.println("Senden OK");
      delay(1000);
    }
    if(R_state == HIGH && G_state == LOW)                     //Abfrage rote LED nach abschalten gelbe LED Sendefehler
    {
      tft.setCursor(0, 24);
      tft.setTextColor(ST7735_RED);
      tft.setTextSize(1);
      tft.println("Sendefehler");
      delay(1000);
    }
  }
  //letzten zustand merken 
  S_laststate = S_state;
}

Es wird auf 4 Kanälen zeitversetzt gesendet. Die LED-Statusanzeige ist aber die gleiche.

Nun weiß ich nicht so recht wie ich diese Auswertung genau zum jeweilig gesendetem Kanal starten & auswerten soll.

Kanal1 senden und dann erst mal warten bis gelbe H->L Flanke kommt? Bin ich ja in einer Schleife gefangen und behindere die anderen Abläufe! Dauerschleife wenn H->L nicht kommt? Hmmm…

Ich hoffe, ich habe mich einigermaßen verständlich ausgedrückt!? :smiley:

Ohne mich in deinen Ablauf detailliert eingearbeitet zu haben, mal eine Idee:

Ich würde ein Array von einem Struct anlegen, in dem für jeden Sendevorgang die relevanten Daten hinterlegt sind: ob sendet wurde, wann, welche Ausgänge etc.

Und dann Funktionen definieren, die in der loop() aufgerufen werden, z.B. checkTrans() (Übergabeparameter könnte der jeweilige Kanal sein).
dies Funktion prüft, ob es was zu prüfen gibt, wenn ja, wird geprüft und das Ergebnis im Array abgelegt, wenn nein, die Funktion sofort verlassen.
if (Senden == true && millis()-sendezeit>2000){
// prüfung
}else return;

Eine andere Funktion prüft dann zyklisch das Array auf Fehlereinträge und stößt eine Reaktion an: Anzeige, nochmal senden, etc.

Sorry - hatte ganz vergessen: Das ganze muss noch Stoni-verständlich sein. :grin:

Struct & Array: Na du traust mir Sachen zu... :grin:

Aber die

if (Senden == true && millis()-sendezeit>2000){
// prüfung
}else return;

Geschichte muß ich mir mal näher ansehen... THX!

Na ja, das mit dem Struct muss ja nicht sein, erleichtert die Sache aber.

Die Grundidee ist: Alle relevanten Daten sind global abgelegt.
Funtkionen werden zyklisch aufgerufen, entscheiden selbst, ob sie was tun müssen. Und werden so geschrieben, dass sie immer sehr schnell wieder verlassen´werden.

bevor man, um die Daten für die einzelnen Kanäle zu speichern, lauter einzelne Variable anlegt
Sendezeit1, Sendezeit2, Sendezeit3 etc
kann man die auch in ein Array packen:
Sendezeit[3]

Sowas kann man dann z.B. schön in Schleifen abarbeiten:

for (int i=0; i<3;i++){
  if (millis() - Sendezeit[i] > 2000{    
      check_LED_Status(i);
  }
}

So mal als Idee.

Bei vier Kanälen aber nur einer Statusinformation, verpackt in drei LED, hast Du ein Informationsdefizit. Schickst Du vier Datenpakete kurz nacheinender raus und erhälst eine Fehlermeldung, kannst Du diese nicht einem Kanal zuordnen. Daher sehe ich zwei Lösungsansätze:

  • Du schickst alle Datenpakete zusammen raus. Im Fehlerfall mußt Du alle Datenpakete erneut senden.
  • Du schickst Datenpaket 1 raus und wartest auf die Rückmeldung. Bei Erfolg geht es mit Datenpaket 2 weiter. Im Fehlerfall kannst Du das Datenpaket wiederholen oder mit Datenpaket 2 fortfahren, das Datenpaket 1 aber nach 4 wiederholen. Dazu benötigst Du einen Merker für fehlerhaftes Senden.
  1. geht nicht, da Sendezeiten der 4 Kanäle schon vorher durch die TimeAlarmsLib festgelegt wurde.

Ich muss also nach jedem Senden den Sendestatus abfragen und kann dann bei fehlerhaftem Senden über die TimeAlarmsLib ein erneutes Senden z.B. nach 15s aktivieren:

Alarm.timerOnce(15, OnceOnlySendenKanal1);

Muss ich aber auch von der Wiederholung begrenzen da er bei Dauerfehler sich totsendet… :smiley:

Ein Testsketch auf dem UNO mit einem Button als Sendeauslöser funzt schon. Muss ich aber noch in eine Funktion mit Rückmeldung verpacken.

#include <Wire.h>
#include "Adafruit_MCP23008.h"

#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library
#include <SPI.h>



#define TFT_CS     10
#define TFT_RST    9  // you can also connect this to the Arduino reset
                      // in which case, set this #define pin to 0!
#define TFT_DC     8
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS,  TFT_DC, TFT_RST);

#define BUTTON_NONE 0
#define BUTTON_DOWN 1
#define BUTTON_RIGHT 2
#define BUTTON_SELECT 3
#define BUTTON_UP 4
#define BUTTON_LEFT 5

// Option 2: use any pins but a little slower!
#define TFT_SCLK 13   // set these to be whatever pins you like!
#define TFT_MOSI 11   // set these to be whatever pins you like!





// Basic pin reading and pullup test for the MCP23008 I/O expander
// public domain!

// Connect pin #1 of the expander to Analog 5 (i2c clock)
// Connect pin #2 of the expander to Analog 4 (i2c data)
// Connect pins #3, 4 and 5 of the expander to ground (address selection)
// Connect pin #6 and 18 of the expander to 5V (power and reset disable)
// Connect pin #9 of the expander to ground (common ground)

// Input #0 is on pin 10 so connect a button or switch from there to ground

Adafruit_MCP23008 mcp;

bool S_state;
bool G_state;
bool R_state;
bool S_laststate;

bool ButtonSelectOn = false;
bool MillisButtonSelectOnGesetzt = false;

unsigned long AltMillis = 0;





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

  pinMode(13, OUTPUT);  // use the p13 LED as debugging

  pinMode(0, INPUT);           // set pin to input
  digitalWrite(0, HIGH);       // turn on pullup resistors
  pinMode(1, INPUT);           // set pin to input
  digitalWrite(1, HIGH);       // turn on pullup resistors
  pinMode(2, INPUT);           // set pin to input
  digitalWrite(2, HIGH);       // turn on pullup resistors
   
  tft.initR(INITR_BLACKTAB);   // initialize a ST7735S chip, black tab

  tft.fillScreen(ST7735_BLACK);     //Display löschen
  
  tft.setRotation(-1);              //Displayrichtung einstellen

  tft.setTextColor(ST7735_WHITE);
  tft.setTextSize(1);
  tft.println("Erkennen Sendestatus");
  delay(2500);
  tft.fillScreen(ST7735_BLACK);     //Display löschen
    

  S_state = HIGH;
  S_laststate = HIGH;
}








void loop() {

  uint8_t b = readButton();
  if (b == BUTTON_SELECT)
  {
    tft.setCursor(0, 36);
    tft.setTextColor(ST7735_RED);
    tft.setTextSize(1);
    tft.println("Enter");
    ButtonSelectOn = true;
    delay(300);
  }
  
  // The LED will 'echo' the button
  digitalWrite(13, digitalRead(0));

  //Display löschen
  tft.setTextWrap(false);
  tft.fillScreen(ST7735_BLACK);


  if (ButtonSelectOn == true)
  {
            if (MillisButtonSelectOnGesetzt == false)
            {
              AltMillis = millis();
              MillisButtonSelectOnGesetzt = true;
            }
            if (millis() - AltMillis <= 3000)
            {  
                      S_state = digitalRead(0);             //gelbe Status LED
                      G_state = digitalRead(1);             //grüne LED Fehler
                      R_state = digitalRead(2);             //rote LED OK
                      
                      if(S_laststate == HIGH && S_state == LOW)                        //Bei Flankenwechsel gelbe LED H->L wird Sendestatus vob grüner & roter LED abgefragt
                      {
                              tft.setCursor(0, 0);
                              tft.setTextColor(ST7735_YELLOW);
                              tft.setTextSize(1);
                              tft.println("Eing. 0 = Flanke H -> L");
                              delay(300);
                              if(G_state == HIGH && R_state == LOW)                     //Abfrage grüne LED nach abschalten gelbe LED Senden OK
                              {
                                tft.setCursor(0, 12);
                                tft.setTextColor(ST7735_GREEN);
                                tft.setTextSize(1);
                                tft.println("Senden OK");
                                delay(300);
                              }
                              if(R_state == HIGH && G_state == LOW)                     //Abfrage rote LED nach abschalten gelbe LED Sendefehler
                              {
                                tft.setCursor(0, 24);
                                tft.setTextColor(ST7735_RED);
                                tft.setTextSize(1);
                                tft.println("Sendefehler");
                                delay(300);
                              }
                      }
            }
            if (millis() - AltMillis > 3000)
            {
                  MillisButtonSelectOnGesetzt = false;
                  ButtonSelectOn = false;
            }
  }
  //letzten zustand merken 
  S_laststate = S_state;
  
}












uint8_t readButton(void) {
  float a = analogRead(3);
  
  a *= 5.0;
  a /= 1024.0;
  
  //Serial.print("Button read analog = ");
  //Serial.println(a);
  if (a < 0.2) return BUTTON_DOWN;
  if (a < 1.0) return BUTTON_RIGHT;
  if (a < 1.5) return BUTTON_SELECT;
  if (a < 2.0) return BUTTON_UP;
  if (a < 3.2) return BUTTON_LEFT;
  else return BUTTON_NONE;
}

Vorschlag:

uint8_t readButton(void) {
  int a = analogRead(3);
  if (a < 41) return BUTTON_DOWN;
  if (a < 205) return BUTTON_RIGHT;
  if (a < 307) return BUTTON_SELECT;
  if (a < 410) return BUTTON_UP;
  if (a < 655) return BUTTON_LEFT;
  else return BUTTON_NONE;
}