Problem mit Interrupt

Mehr
01 Mär 2020 11:05 #640 von Jo
Jo erstellte das Thema Problem mit Interrupt
Hallo allerseits
Habe ein hartnäckiges Problem mit einem Interrupt. Folgender Code läuft auf einer ESP8266
NodeMCU:
#include <ESP8266WiFi.h>
#include <PubSubClient.h>

// Wifi Connection
const char* ssid = "xxx";
const char* password = "xxx";

// MQTT Server address
const int mqtt_port = 1983;
const char* mqtt_server = "192.168.178.xx";
//Topics
const char* gate_topic = "Garage/Gate";

const int interruptGate = D7;//D7

WiFiClient espClient;
PubSubClient client(espClient);

void setup() {
  Serial.begin(9600);
  setup_wifi();
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);
  //Gate In/Out
  pinMode(interruptGate, INPUT_PULLUP);
  //digitalWrite(interruptGate, HIGH);
  attachInterrupt(digitalPinToInterrupt(interruptGate), handleInterruptGate, CHANGE);
}

void setup_wifi() {
  delay(2);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void callback(char* topic, byte* payload, unsigned int length) {
  //Car In
  if (strcmp(topic, gate_topic) == 0) {
   Serial.print("Message arrived\ntopic = ");
   Serial.print(topic);
   Serial.print(" - ");
    String spayload = "";
    for (int i = 0; i < length; i++) {
      spayload = spayload + (char)payload[i];
    }
    Serial.print("payload = " + spayload + "\n");
  }
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("Combi_Switch")) {
      Serial.println("connected");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

ICACHE_RAM_ATTR void handleInterruptGate() {
  static unsigned long last_interrupt_time = 0;
  unsigned long interrupt_time = millis();
  if (interrupt_time - last_interrupt_time > 20)
  {
    int dr = digitalRead(interruptGate); <--- Das funktioniert nicht zuverlässig!
    if(dr == LOW) {
      client.publish(gate_topic, "true", true);
    } else {
      client.publish(gate_topic, "false", true);
    }
    last_interrupt_time = interrupt_time;
  }
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
}

Der Interrupt an sich läuft zuverlässig auf "CHANGE", doch bei der Abfrage des momentanen Zustandes vom Eingang
"interruptGate" (in der ISR-Routine) erhält die Variable dr nicht immer den richtigen Wert.
Alle Hardwareteile sind geprüft und nicht defekt. Habe das auch mit externen Pullup-Widerständen getestet, von
10K runter auf 680R - keine Besserung.
Mit der Debounce-Time habe ich auch variiert, der Wert 20 reicht völlig,
Habe viele Varianten getestet, doch nichts war wirklich zuverlässig.
Was stimmt hier nicht?

Freundliche Grüße
Jo

Bitte Anmelden oder Registrieren um der Konversation beizutreten.

Mehr
09 Apr 2020 06:54 #663 von der_gerd
Problem mit Interrupt
Du hast sehr zeitaufwändigen Code in deiner ISR. Im allgemeinen sollte eine ISR möglichst schnell wieder verlassen werden. Verlagere doch mal die Kommunikationsanweisungen in die loop(). Dazu brauchst du ein globales Flag oder einen Semaphor.
Und überhaupt ergibt es praktisch wenig Sinn, den eingelesenen Wert nur in der ISR zu behalten. ;-)
Prinzip (in der Arduino Syntax bin ich momentan nicht sehr sicher):
Mit Flag (ist leichter)
global:
bool intrOccured = false; // globales Flag
char* boolstr[] = {"false","true"}; //Zugabe meinerseits ;-)
int dr;

ICACHE_RAM_ATTR void handleInterruptGate() {
// dein debounce
dr = digitalRead(interruptGate);
intrOccured = true;
//...
}

loop(){
// der MQTT Kram
if (intrOccured) {
intrOccured = false;
client.publish(gate_topic, boolstr[dr], true); // Mehr Datenstruktur -> weniger Ablaufstrutur ;-)
}
}
Entschuldige bitte die fehlenden Einrückungen, hab's mal eben reingehackt.
Wenn's vielleicht nicht hilft, so kannst du damit zumindest deinen Tastendruck weiterverarbeiten.
Ist es nicht so, dass die ISR mit ICACHE_RAM_ATTR in's rare RAM geladen wird? Dann ist es eh besser, sie klein zu halten.RAM ist für die Daten da, nicht für Programm. Die ISR im RAM laufen halt schneller ab, was sie auch sollten.
Viel Erfolg

Bitte Anmelden oder Registrieren um der Konversation beizutreten.

Powered by Kunena Forum