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;
}
}
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...
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?
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.
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.
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