Serielle Übertragung -Interrupt geht nicht mehr

Hallo,
ich habe wieder mal ein Problem, wöran es liegt habe ich schon mal erkannt, die beste Lösung suche ich noch.
Ich steuere eine Pumpe über Phasenanschnitt, das funktioniert soweit auch gut. Ich habe eine 0-Durchgangserkennung und zünde einen Triac mit variabler Verzögerung. Die 0-Durchgangserkennung läuft über ein Interrupt.
Über ein HC05 Bluetoothmodul sollen die Werte auf ein Tablet übertragen werden und ich kann Werte für die Zündverzögerung vorgeben. Auch das funktioniert.
Zusammen aber nicht. Werte vom Tablet empfangen geht, das Senden der Werte über die serielle Schnittstelle bringt aber alles durcheinander und die die Phasenanschnittsteuerung geht nicht mehr.
Ich hatte eine ähnliche Schaltung schon mal, da wurde es aber über einenPWM Ausgang angesteuert. Das ging problemlos.

Welche Möglichkeiten habe ich, außer Datenmenge reduzieren und Bautrade erhöhen? Geht das durch geschicktes Auslagern des Sendens?

Welcher Zusammenhang macht die Probleme? Würde es gerne verstehen. läuft das Interrupt nicht mehr richtig und wenn ja warum?

Hoffe das war verständlich

Hier der Code. Die Regelung gibt es noch nicht. serielle Übertragung ist aus, dann geht es.

#define WINDOW_SAMPLE_WIDTH 3

//Sollwerte
float solltemp = 93;
float solldruck = 9;
float sollgewicht = 34;
float zielgewicht = 32;

// Nulldurchgang
int nulldurchgang = 0;
int verzoegerung = 0;
int last_CH1_state = 0;

//Druck und Druckregelung
int raw[WINDOW_SAMPLE_WIDTH], addPosition = 0;
double atm;
float p = 0.0;            // Druck

int Schalter = 0;   //Bezug starten, über bluetooth

//allg Variablen
char blueToothValue;
unsigned long zeit_jetzt;
unsigned long wartezeit = 100;     //für Zeitschleife von 1500 ms anstatt delay,


void setup() {

  Serial.begin(9600);
  pinMode(A5, OUTPUT);
  digitalWrite(A5, HIGH);


  PCICR |= (1 << PCIE0);    // PCMSK0 scan ein
  PCMSK0 |= (1 << PCINT0);  //D8 als trigger für interrupt bei state change. Optokopplereingang
  pinMode(3, OUTPUT);       //D3 als Output für Triacpulse
  verzoegerung = 0;
}

void loop() {

  //Druck einlesen
  raw[addPosition] = analogRead(A3);
  addPosition++;
  if (addPosition >= WINDOW_SAMPLE_WIDTH) addPosition = 0;
  for (int i = 0; i < WINDOW_SAMPLE_WIDTH; i++) {
    atm += raw[i];
  }
  atm = atm / WINDOW_SAMPLE_WIDTH;

  p =  (float)atm / 1023.0 * 5.0 * 5.1455 - 2.5787;

  //*************************Bezug abschalten
  if  (Schalter == 1) digitalWrite(A5, LOW);  //  if ((s < Zielgewicht) && (Schalter == 1)) digitalWrite(A5, LOW);
  else digitalWrite(A5, HIGH);


  if (verzoegerung > 7400) verzoegerung = 7400;
  if (verzoegerung < 0) verzoegerung = 0;



  if (nulldurchgang)
  {
    delayMicroseconds(verzoegerung); //Verzögerung für Phasenanschnitt
    digitalWrite(3, HIGH);
    delayMicroseconds(100);
    digitalWrite(3, LOW);
    nulldurchgang = 0;
  }
  // Start Modifikation der Variablen  per Bluetooth
  //zeit_jetzt = millis();
  //  while(millis() < (zeit_jetzt + wartezeit))

  if (Serial.available()) {
    blueToothValue = Serial.read();
  }

  switch (blueToothValue) {
    case 'U':
      verzoegerung = verzoegerung + 200;
      break;

    case 'W':
      verzoegerung = verzoegerung - 200;
      break;

    case 'R':
      Schalter = 1;
      break;

    case 'r':
      Schalter = 0;
      break;
    
  }

//  zeit_jetzt = millis();
//  while (millis() < (zeit_jetzt + wartezeit)){
 //   Serial.print( "*b" );  
 // Serial.println( verzoegerung);
 // Serial.print( "*" );
  }

ISR(PCINT0_vect) {

  if (PINB & B00000001) {
    if (last_CH1_state == 0) {
      nulldurchgang = 1;
    }
  }
  else if (last_CH1_state == 1) {
    nulldurchgang = 1;
    last_CH1_state = 0;
  }
}

Hallo,

deine delays und while wirken blockierend im Ablauf.

Die Ausgabe des Triggers in loop() macht das Timing ziemlich kaputt.

Was soll last_CH1_state?

Was willst Du da machen?

Das hier lässt sich abkürzen:

Tja so richtig werde ich nicht schlau draus, was Du da mit der Schleife willst.
Dann ist dein nulldurchgang ein int und verändert sich in einer ISR.
Dafür sollte der aber volatile sein.
Und da Du nur zwei Zustände kennst, mach ein bool daraus!

Und dann lager das was zusammengehört in einzelne Funktionen aus.

#define WINDOW_SAMPLE_WIDTH 3

//Sollwerte
float solltemp = 93;
float solldruck = 9;
float sollgewicht = 34;
float zielgewicht = 32;

// Nulldurchgang
volatile bool nulldurchgang = 0;
int verzoegerung = 0;
int last_CH1_state = 0;

//Druck und Druckregelung
int raw[WINDOW_SAMPLE_WIDTH], addPosition = 0;
double atm;
float p = 0.0;            // Druck

int Schalter = 0;   //Bezug starten, über bluetooth

//allg Variablen
char blueToothValue;
//unsigned long zeit_jetzt;
unsigned long wartezeit = 100;     //für Zeitschleife von 1500 ms anstatt delay,


void setup()
{
  Serial.begin(9600);
  pinMode(A5, OUTPUT);
  digitalWrite(A5, HIGH);
  PCICR |= (1 << PCIE0);    // PCMSK0 scan ein
  PCMSK0 |= (1 << PCINT0);  //D8 als trigger für interrupt bei state change. Optokopplereingang
  pinMode(3, OUTPUT);       //D3 als Output für Triacpulse
  verzoegerung = 0;
}

void loop()
{
  readBT();
  readPressure();
  //*************************Bezug abschalten
  digitalWrite(A5, !Schalter);
  if (nulldurchgang)
  {
    delayMicroseconds(verzoegerung); //Verzögerung für Phasenanschnitt
    digitalWrite(3, HIGH);
    delayMicroseconds(100);
    digitalWrite(3, LOW);
    nulldurchgang = false;
  }
}
void readPressure()
{
  //Druck einlesen
  raw[addPosition] = analogRead(A3);
  addPosition++;
  if (addPosition >= WINDOW_SAMPLE_WIDTH) addPosition = 0;
  for (int i = 0; i < WINDOW_SAMPLE_WIDTH; i++)
  {
    atm += raw[i];
  }
  atm = atm / WINDOW_SAMPLE_WIDTH;
  p =  (float)atm / 1023.0 * 5.0 * 5.1455 - 2.5787;
}
void readBT()
{
  if (Serial.available())
  {
    blueToothValue = Serial.read();
    switch (blueToothValue)
    {
      case 'U':
        verzoegerung = verzoegerung + 200;
        break;
      case 'W':
        verzoegerung = verzoegerung - 200;
        break;
      case 'R':
        Schalter = 1;
        break;
      case 'r':
        Schalter = 0;
        break;
    }
    if (verzoegerung > 7400) verzoegerung = 7400;
    if (verzoegerung < 0) verzoegerung = 0;
    Serial.print( "*b" );
    Serial.println(verzoegerung);
    Serial.print( "*" );
  }
}

ISR(PCINT0_vect)
{
  if (PINB & B00000001)
  {
    if (last_CH1_state == 0)
    {
      nulldurchgang = true;
    }
  }
  else if (last_CH1_state == 1)
  {
    nulldurchgang = true;
    last_CH1_state = 0;
  }
}

die delays sind microsecunden und die brauche ich, um die Zündverzögerung hin zu bekommen. Das funktioniert ja auch und stört nicht. Die while könnte ich durch if ersetzen.

Aber exakt so (nur mit einem pwm Ausgang und ohne die =-Durchgangserkennung mit Interrupt) funktioniert es ja wie es soll.

Was meinst du mit damit? Was soll ich anders machen?

last_CH1_state ist ein Merker.
Es hängt noch eine kleine Schaltung dran, da wird die Sinuswelle der Netzspannung reduziert und gleichgerichtet. Ein Optokoppler liest das ein und immer wenn ein Tiefpunkt kommt wird die State-Änderung erkannt. Das macht der Interrupt unten im Code. Wenn das erkannt wird, wird über den fire-pin ein Triac verzögert gezündet. Die Schwingungsdauer bei unseren 50Hz sind 20ms, da jede Halbwelle kontrolliert wird sind es max. 10ms.

Ich dachte immer, dass bei einem Interrupt Ereignis der Code unterbrochen wird. Drum hätte ich jetzt eher vermutet, dass der Phasenanschnitt richtig weiter läuft und die serielle Kommunikation ein Problem hat, es ist aber genau anders rum...

Danke für die Hilfe, das werde ich heute Abend gleich mal probieren.

Wenn man denkt man hat es verstanden gehts erst richtig los.:slight_smile:

Dann gehört der auch volatile. Und eigentlich doch dann auch nur bool.

Alles lesen: volatile - Arduino-Referenz

Dafür sorgen daß der Trigger-Impuls exakt die gewünschte Zeit nach dem Interrupt ausgegeben wird, nicht irgendwann in loop().

Hast Du schon mal nach ähnlichen Projekten im Forum gesucht?

nicht nur da, im kompletten www.
einzeln funktioniert es ja, im Zusammenspiel nur nicht. Ich habe auch schon komplexere Dinge gebaut, die haben ach funktioniert. Aber so wie es aussieht war das dann meistens Glück.

und das mache ich, indem ich es auslagere, so wie bereits von my_xy_projekt beschrieben oder?

Du hast nichts verstanden :frowning:

Dann verrate mir doch wie, anstatt nur zu sagen wie es nicht geht. Das wär hilfreicher.
Konkrete Frage:
Wie sorge ich dafür, daß der Trigger- Impuls exakt die gewünschte Zeit nach dem Interrupt ausgegeben wird?

Für mein Verständnis sollte das bischen Loop einem im MHZ Bereich arbeitenden MC nicht an die Grenze bringen. Ich kann ja erst ausgeben, wenn ich meine Startbedingung abgefragt habe, sprich der Taster gedrückt ist.

Entweder in der ISR warten oder die Zeit des interrupts speichern und in loop() auswerten.

Hallo,

ich glaube ich weiß warum das verrückt spielt. Du liest die Serielle ein und speicherst den Empfang in globaler char blueToothValue. Wenn du nichts mehr empfängst, bleibt das alte char erhalten und das switch case wird immer wieder aufs neue ausgeführt und damit die Rechnungen usw. was dann Auswirkung auf steigende delay Zeiten hat. Dazu kommt noch das signed Overflows nicht definiert sind. Kann funktionieren muss aber nicht. Demzufolge noch alle Datentypen kontrollieren ob diese signed sein müssen. Auch dessen Wertebereich kontrollieren. Im Zweifelsfall immer den Größten. Optimieren kann man immer noch.

Du benötigst eine saubere Einlesefunktion die erst ihr okay zur Auswertung zurückgibt wenn neue Daten eingelesen wurden.

Dann hab ichs ja richtig gemacht :wink:

ich habe es mal so wie du es geschrieben hast umgesetzt. Das funktioniert, aber es gibt mir meine Werte an mein Bluetooth Gerät jetzt natürlich nur zurück, wenn es gerade auch einen Wert bekommt. Ich möchte die IST Werte aber gerne sehen und erst dann denn Sollwert ändern.
Wenn ich die Klammer vom

if (Serial.available())
  {

nur um die Einlese switch case Struktur mache hängt es wieder, dafür habe ich wieder Werte

Tausche readBT()

void readBT()
{
  static unsigned long lastuebertragung = 0;
  if (Serial.available())
  {
    blueToothValue = Serial.read();
    switch (blueToothValue)
    {
      case 'U':
        verzoegerung = verzoegerung + 200;
        break;
      case 'W':
        verzoegerung = verzoegerung - 200;
        break;
      case 'R':
        Schalter = 1;
        break;
      case 'r':
        Schalter = 0;
        break;
    }
    if (verzoegerung > 7400) verzoegerung = 7400;
    if (verzoegerung < 0) verzoegerung = 0;
  }
  if (millis() - lastuebertragung > wartezeit)
  {
    Serial.print( "*b" );
    Serial.println(verzoegerung);
    Serial.print( "*" );
    lastuebertragung = millis();
  }
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.