Temperatursteuerung

Hallo Arduino Freunde,

für meine Masterarbeit möchte ich ein Magnetspulenventil (für eine Stickstoffzufuhr), Heizpatronen und die Geschwindigkeit eines Schrittmotors über eine Arduino Programmierung steuern/regeln. Ich habe hierfür einen Code geschrieben und komme leider bereits seit Wochen nur sehr langsam voran und bin mittlerweile an einem Punkt, bei dem ich nicht weiter komme. :frowning:

Über ein Keypad möchte ich folgende 4 Parameter einstellen:
A = Geschwindigkeit für den Schrittmotor (speed)
B = Solltemperatur für die Heizpatronen/ PDI Reglung (setpoint)
C = Temperatur bei dem das Ventil geöffnet werden soll (Valve open)
D = Temperatur bei dem das Ventil schließen soll (Valve closed)

Ich kann die Geschwindigkeit (A) problemlos einstellen. Doch folgende Probleme konnte ich nicht lösen:

Die Temperatur, die auf dem Display angezeigt wird, (über Thermistor aufgenommen) aktualisiert sich nur dann, wenn ich auf die Tasten des Keypads drücke. Dabei ist es wichtig,dass die Temperatur am besten im Sekundentakt aufgenommen und angezeigt wird, damit die Heizpatronen und das Ventil gesteuert werden können.

Das Öffnen und Schließen des Ventils funktioniert ebenfalls nur, wenn ich über das Keypad die Temperatur zum Öffnen und Schließen eingebe;und nicht automatisch, wenn die Temperatur zum Schließen oder Öffnen bereits erreicht wird.

Für das Ventil verwende ich ein MOSFET mit einer externen Spannungsquelle.

Für die Heizpatronen möchte ich ein Relais verwenden. Ich habe zu Testzwecken zunächst die Heizpatronen durch eine LED ersetzt, um zu überprüfen, ob die Schaltung überhaupt funktioniert.

Ich wäre sehr dankbar für jede Hilfe! (BTW: Ich bin ein absoluter Beginner, habe trotzdem alles versucht)

Beste Grüße
Miles

Hier ist der Code:

Miles Code.ino (11.3 KB)

  Hier ist der erste Teil des Codes:


////////////////////////////////////////////////////////////////////////
//Installation des Displays

#include <Wire.h>
#include <LCD.h>
// Einbinden der LiquidCrystal Bibliothek für das I2C Modul des Displays.
#include <LiquidCrystal_I2C.h>

// Es gibt min. 2 Adressen welche ein Display verwenden kann: 0x3F oder 0x27.
// Setzt die PINs des I2C Moduls für die Kommunikation mit dem Display.
// Adresse: 0x27
// EN: 2
// RW; 1
// RS: 0
// D4: 4
// D5: 5
// D6: 6
// D7: 7
// BL: 3
// BLPOL: POSITIVE


LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);     


unsigned long previousmillis4 = 0;
long interval4 = 1000;

////////////////////////////////////////////////////////////////////
// Installation des Tastenfelds

#include <Keypad.h>

const byte ROWS = 4;    //four rows
const byte COLS = 4;    //four columns

//define the cymbols on the buttons of the keypads
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {39, 41, 43, 45}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {47, 49, 51, 53}; //connect to the column pinouts of the keypad
long zahl, zahla=0, zahlb=0, zahlc=0, zahld=0;
bool a=0, b=0, c=0, d=0;

//initialize an instance of class NewKeypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

////////////////////////////////////////////////////////////////////
//Serielle Daten empfangen, senden und verarbeiten -> Definition von Variablen

double Setpoint = 4;                  //Sollwert für Heizpatronen
int DS18B20_int = 0;                  // für Übertragung der Solltemperatur   
float DS18B20_01;
float DS18B20_01alt = 1000;
int Setpoint_Trans = 4;
unsigned long previousmillis3 = 0;
long interval3 = 1000;


////////////////////////////////////////////////////////////////////
//Schrittmotor Antriebswelle

#define ENA1 2     //Konfiguration der PINS 2,8,9,3,4&5 für Schrittmotor
#define STP1 8
#define DIR1 9
#define MS11 3
#define MS21 4
#define MS31 5

unsigned long previousmillis1 = 0;          //Definition von Variablen
long interval1 = 0;
int stepState1 = LOW;

///////////////////////////////////////////////
// Installation der Temperaturreglung für Heizpatronen

#include <OneWire.h>                      //Einbinden der Bibliotheken
#include <DallasTemperature.h>
#include <PID_v1.h>

#define ONE_WIRE_BUS 10      // Pin für Thermistor
// #define PIN_Relais 11              //Pin für Relais (Heizpatronen) Lieber pinMode
// #define PIN_MOSFET 12      //Pin für Mosfet (Ventil)  bringt nix! Lieber pinMode
#define Light 13
 
double Input;
double Output; //Definition der Variablen für PID-Regler
double Kp=5, Ki=2, Kd=3;    //Definition der Variablen für PID-Regler

PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);

//Installation der OneWire Instanz für die Kommunikation mit allen OneWire Bauelementen
OneWire oneWire(ONE_WIRE_BUS);


//Übergabe der OneWire Referenz für die Kommunikation mit dem Sensor
DallasTemperature sensors(&oneWire);

void temperaturregelung () {

//Temperaturaufnahme durch Thermistor (sensors= One_Wire_Bus Pin 10) = Ist-Temperatur
  sensors.requestTemperatures();             
 
  Input = sensors.getTempCByIndex(0);         // Input für PID Regler = Ist-Temperatur
 

//999 weil sonst der Wert 0 möglich ist, was zu Problemen bei der If-Abfrage führen würde
  DS18B20_int = (((sensors.getTempCByIndex(0))*10)+999);     

  while(sensors.getTempCByIndex(0) == -127){  //Falls Temperatursensor nicht verbunden ist, Heizpatrone nicht einschalten
 
  digitalWrite(Light,LOW);
    delay(500);
    digitalWrite(Light,HIGH);
    delay(500);
    sensors.requestTemperatures();
    Input = sensors.getTempCByIndex(0);
  }
 
  myPID.Compute();
  analogWrite(11, Output); // Pin 11 Relais
  Serial.println (sensors.getTempCByIndex(0));
  //Serial.println(Output);
}
//////////////////////////////////////////////////////////

void setup() {
  lcd.backlight();
Serial.begin(9600); // start serial port

pinMode(12,OUTPUT); // Pin für Mosfet (Ventil Schaltun)

/////////////////////////////////////////////
//Display

  lcd.begin(20,4); // initialisieren des Displays mit 20 Zeichen und 4 Zeilen
 
  lcd.setCursor ( 0, 0 );
  lcd.print("speed:");
 
  lcd.setCursor ( 0, 1 );
  lcd.print("setpoint:");
 
  lcd.setCursor ( 0, 2);
  lcd.print ("valve open:");   

  lcd.setCursor ( 0, 3 );
  lcd.print("valve closed:");

   lcd.setCursor ( 13, 1 );
  lcd.print("T:");
 

////////////////////////////////////////////////////////////////////
//Schrittmotor Antriebswelle

  pinMode(ENA1,OUTPUT);
  pinMode(STP1,OUTPUT);
  pinMode(DIR1,OUTPUT);
  pinMode(MS11,OUTPUT);
  pinMode(MS21,OUTPUT);
  pinMode(MS31,OUTPUT);
  digitalWrite(ENA1,HIGH);
  digitalWrite(MS11,HIGH);
  digitalWrite(MS21,HIGH);
  digitalWrite(MS31,HIGH);
  digitalWrite(DIR1,HIGH);

////////////////////////////////////////////////////////////////////
//Temperaturreglung

sensors.begin();           // Start up the library
sensors.setResolution(11);    //Auflösung 9- 12 Bits
 sensors.requestTemperatures(); // Temperaturmessung durchführen

Setpoint = 4; //Solltemperatur
//if (Setpoint > 50) { //Prüfen ob Solltemperatur zu hoch ist und ggf. Verringerung auf maximale Solltemperatur
// Serial.println("Solltemperatur zu hoch! maximale Solltemperatur von 50 wird nun verwendet");
 // Setpoint = 50;
//}

myPID.SetMode(AUTOMATIC); //PID-Regler starten
pinMode(Light,OUTPUT);
digitalWrite(Light,LOW);

}
////////////////////////////////////////////////////////////////////
//Serielle Daten empfangen, senden und verarbeiten

void DatenEinAus(){
  Setpoint_Trans = (Setpoint+999);
  Serial.println (Setpoint_Trans);      //über das Display würde 1003 ausgegeben werden
  int incoming = Serial.available();
  if (incoming > 0){                  //wenn über das Display ein Wert >0 ausgegeben wird, wird
    DS18B20_int = Serial.parseInt();

    DS18B20_01 = (((-999)/10.0));//999 weil sonst der Wert 0 möglich ist, was zu Problemen bei der If-Abfrage führen würde
    if (DS18B20_01 < 7 * DS18B20_01alt){ //Ab und zu tritt ein Faktor 10 Fehler auf. Daher hier der Filter
      DS18B20_01alt = DS18B20_01;
    }
  }
}
Hier ist der zweite Teil des Codes

void loop() {

////////////////////////////////////////////////////////////////////
// Timer starten
   unsigned long currentmillis = millis(); 

   
////////////////////////////////////////////////////////////////////
//Display
  if(currentmillis - previousmillis4 >= interval4) {   //previousmillis4 war 0. wenn der der timer über eine Sekunde ist...
        previousmillis4 = currentmillis;               //dann wird previousmillis4 auf 1 sek gesetzt
        lcd.setCursor ( 15, 1 );
        lcd.print("       ");
        lcd.setCursor ( 15, 1 );
        lcd.print(sensors.getTempCByIndex(0));          //und der Wert von DS18B20_01 über den lcd ausgegeben vermutlich T durch 10 // hier verändert von DS18B20_01 auf sensors.getTemp und so
  }

///////////////////////////////////////////////////////////////////
//Schrittmotor Antriebswelle
    if((currentmillis - previousmillis1 >= interval1) && (interval1 !=0))
    {     
      previousmillis1 = currentmillis; 
       if(stepState1 == LOW){                                                                               
        stepState1 = HIGH;
       }
      else{
        stepState1 = LOW;
     }
      digitalWrite(ENA1,LOW);
      digitalWrite(STP1, stepState1); 
     
    }
  if(interval1 == 0){
    digitalWrite(ENA1,HIGH);
  }
 
////////////////////////////////////////////////////////////////////
//Serielle Daten Empfangen und verarbeiten
 
  if(currentmillis - previousmillis3 >= interval3) {          // previousmillis3 war 0. interval3 war 1000. Nach 1 Sek gibt previousmillis3 die verstrichene Zeit (currentmillis) an
        previousmillis3 = currentmillis;
        DatenEinAus();                                        // nach 1 Sek geht Temperaturmessung los
       
  }
 
////////////////////////////////////////////////////////////////////
//Tastenfeld  -> Eingabe
 
  char key = keypad.getKey();
 
  if (key){
    switch(key) {
    case '*' :                            // Die gerade aktive Zahl löschen
      if(a) zahla=0;
      if(b) zahlb=0;
      if(c) zahlc=0;
      if(d) zahld=0;
      zahl=0;
      break;
    case '1' : zahl*=10; zahl+=1; break;  // Die Ziffern 1 bis 0 eingeben
   case '2' : zahl*=10; zahl+=2; break;
    case '3' : zahl*=10; zahl+=3; break;
    case '4' : zahl*=10; zahl+=4; break;
    case '5' : zahl*=10; zahl+=5; break;
    case '6' : zahl*=10; zahl+=6; break;
    case '7' : zahl*=10; zahl+=7; break;
    case '8' : zahl*=10; zahl+=8; break;
    case '9' : zahl*=10; zahl+=9; break;
    case '0' : zahl*=10; zahl+=0; break;
    case 'A' : a=1; b=0; c=0; d=0; zahl=0; break; // Zahl A aktivieren
    case 'B' : a=0; b=1; c=0; d=0; zahl=0; break; // Zahl B aktivieren
    case 'C' : a=0; b=0; c=1; d=0; zahl=0; break; // Zahl C aktivieren
    case 'D' : a=0; b=0; c=0; d=1; zahl=0; break; // Zahl D aktivieren
    case '#' :                                    // alle Zahlen ausgeben


//Schrittmotor Geschwindigkeit
      interval1 = (18.75/2*60)/zahla; //Umrechnung für U/min: 3200 Schritte pro Umdrehung bei 1/16 Step, 60000 ms pro Minute -->60000/3200 = 18,75 ms zwischen den Schritten, geteilt durch 2 weil mit jedem Schleifendurchlauf nur einmal an oder aus geschaltet wird, mal 60 wenn U/h.   

//Solltemperatur für Heizpatronen
      Setpoint = zahlb;



///////////////////////////////////////////////////////////////////////////////////////////////////
//Ventilsteuerung
 
//TemperaturSchwellwert für Öffnen des Ventils

if (sensors.getTempCByIndex(0)>= zahlc)
{
  digitalWrite(12,HIGH);   //Mosfet wird geschaltet und Ventil öffnet sich
  delay (1000);
}
else {
digitalWrite (12,LOW);
delay (1000);
}
//TemperaturSchwellwert für Schließen des Ventils
if (sensors.getTempCByIndex(0) <= zahld)
{
  digitalWrite(12,LOW);   //Mosfet wird nicht geschaltet und Ventil schließt sich
  delay (1000);
}

}

////////////////////////////////////////////////////////////////////////////////////////////////
// Tempearturreglung Heizpatrone

temperaturregelung ();
  int incoming = Serial.available(); 
  if (incoming > 0){ 
  Setpoint_Trans = Serial.parseInt();
 Setpoint = ((Setpoint_Trans)-999);
  //Serial.println(Setpoint);
  }
  delay(400);


 
//////////////////////////////////////
if(a){
      zahla=zahl;
   
      lcd.setCursor ( 6, 0 );
      lcd.print("    ");
      lcd.setCursor ( 6, 0 );
      lcd.print(zahla);
     
    }// Wenn ZahlA aktiv ist, dann zahl in ZahlA übernehmen
    if(b) {
      zahlb=zahl;
     
      lcd.setCursor ( 9, 1 );       
      lcd.print("       ");
      lcd.setCursor ( 9, 1 ); 
      lcd.print (zahlb);   
    }
   
    if(c) {
      zahlc=zahl;
     
      lcd.setCursor ( 11, 2 );
      lcd.print("       ");
      lcd.setCursor ( 11, 2 );
      lcd.print (zahlc);     
    }
    if(d) {
      zahld=zahl;
     
      lcd.setCursor ( 13, 3 );
      lcd.print("       ");
      lcd.setCursor ( 13, 3 );
      lcd.print (zahld);
    }


}
}

Drücke mal in der IDE Strg+T
Evtl siehst Du dann Deinen Fehler .
Tip: alles was nach if (key) { kommt, wird NUR ausgeführt, wenn eine Taste gedrückt wird.

Hey vielen Dank für die Antwort.

Es scheint so (besser) zu klappen. Jetzt wird die Temperatur auch im Sekundentakt aufgezeichnet und wiedergegeben. Das Ventil lässt sich jetzt auch automatisch Öffnen und Schließen (Indem für C und D die Temperaturschwellwerte eingegeben werden).

Jetzt habe ich leider ein anderes Problem und hoffe, dass sich das leicht lösen lässt:

Das Keypad ist "wahrscheinlich" geblockt durch das Programm, und ich muss sehr oft auf die Tasten drücken und auf den richtigen Zeitpunkt hoffen, sodass das Keypad die Info aufnehmen kann.

Beispielsweise musste ich eben gefühlt 20 mal auf die Taste C klicken, bis ich diese Verändern konnte. Und ebenso musste ich mehrmals auf eine Zahl klicken, bis diese auf dem Display angezeigt wurde.

Könnt ihr mir vielleicht dabei auch helfen? Wäre euch weiterhin sehr dankbar!

Liebe Grüße
Miles

Hi

Vermeide delay();
Bei jedem delay(x) bleibt der Arduino x Millisekunden 'hängen'.
Die eigentliche Tasterabfrage braucht selber nahezu keine Zeit - ist also schwupps schon wieder vorbei - und wenn Du Da nicht gerade den Knopf gedrückt hast, ist's halt auch schon wieder zu spät.
Was passiert, wenn der Taster gedrückt gehalten wird - kA, so weit bin ich nicht im Sketch drin - außerdem ist's ja mittlerweile ein völlig Anderer.

Suche dazu die Nachtwächer-Erklärung hier im Forum.

Vermeide delay(), verwende statt Dessen ein millis()-Konstrukt und merke Dir die jeweilige Startzeit.

MfG