Abbruch einer Funktion

#include <mcp_can.h>                                //Bibliotehk für CAN_BUS SPI UND DISPLAY
#include <mcp_can_dfs.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <TimerOne.h>

const byte interruptPin = 13; //Extern InterruptPin
#define OLED_RESET 7
Adafruit_SSD1306 display(OLED_RESET);

#define NUMFLAKES 10
#define XPOS 0
#define YPOS 1
#define DELTAY 2
#define LOGO16_GLCD_HEIGHT 16 
#define LOGO16_GLCD_WIDTH  16 


#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

unsigned char flagRecv = 0;					            //flag can bus data rec
unsigned char flagopen = 0;					            //flag vavle open
long unsigned int rxID1 = 0x00000050;		        //rxID
long unsigned int txID1 = 0x14fa0003;		        //txID

unsigned char len = 0;
unsigned char buf[8];
unsigned char stmp1[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned char stmp2[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};



const int SPI_CS_PIN = 10;
float X=0,Y=0;
float P=0,T=0;
int ING=13;
//int T_Ref[23]={ 0,480,540,595,644,688,725,756,782,804,
               // 822,837,849,858,867,873,879,883,887,890,
               // 893,895,900};
  int T_Ref[23]={0,541,609,671,726,775,817,852,882,906,
           926,943,957,968,977,984,991,996,1000,1004,
           1007,1009,1100};									    //tem calculate
MCP_CAN CAN(SPI_CS_PIN);                        //Set CS pin for canbus

void setup()   {  
  pinMode(ING,INPUT);										        //Extern Pin 13
  //Serial.begin(9600);
  while (CAN_OK != CAN.begin(CAN_1000KBPS))     // init can bus : baudrate = 500k//1000kbps
  {}     
  CAN.init_Mask(0,1,0xffff00ff); 							  //Mask defi
  CAN.init_Filt(0,1,0x14fa0003); 							  //filter defi
  attachInterrupt(0,MCP2515_ISR, FALLING); 			// start interrupt
  pinMode(9, OUTPUT);										        //pwm out put 
  Timer1.initialize(100); 									    //pwm frequence
  Timer1.pwm(9, 0); 										        //sollwert of null set
  pinMode(interruptPin, INPUT);								  //Extern interrupt set
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);		//init
  delay(2000);
  display.clearDisplay();

}

void MCP2515_ISR()											        //canbus date receiver interrupt
{   
    flagRecv = 1;											          //flag set to 1
}

void vavle_open() {											        //vavle_open programm
  Timer1.pwm(9, 819);   
  for(volatile int i=0;i<1000;i++)							//4A for 4s hold
    delayMicroseconds(4000);
  for(volatile int i=819;i>150;i--)							//4A to 0.6A rampdowm
    { 
      Timer1.pwm(9, i);
      delayMicroseconds(5000);								  //2s for rampdowm
    }
  }

 void vavle_close() {										        //vavle_close
  Timer1.pwm(9,0);											        //sollwert of null set
 }
 
void loop() 
{
    if(flagRecv)											          //can bus receiver data handle
    {
        flagRecv = 0;                        
        CAN.readMsgBuf(&len, stmp2);
    }
    stmp1[0]=digitalRead(ING);								  //Extern interrupt **not use hier
    if(stmp2[0]==1&& flagopen==0)							  //vavle open signal come
    vavle_open();
    else if(stmp2[0]==0&&flagopen==1)						//vavle close signal come
    vavle_close();
    flagopen=stmp2[0];										      //vavle signal flag set
    delay(10);
    P_MESS();												            //pressure measure
    T_MESS();												            //temp measure
    display_zeigen(P,T);									      //P and T display
    CAN.sendMsgBuf(txID1,0,8,stmp2);						//P and T data transmit
    //missing watchdog for H2 concentration
	//missing safe shutdown program 
	
}
  
void P_MESS(void)											//Program for pressure measure
{
  unsigned int A=0;
	for(byte i=0;i<20;i++)
	{
		A=A+analogRead(A0);
   delay(1);
	}
	X=(float)A/20.0; 
	X=constrain(X,102,922);
  P=map(X,102,922,0,700);
  P=constrain(P,0,700);
}  

void T_MESS(void)											//program for temp measure
{
  unsigned int B=0;
  for(byte i=0;i<20;i++)
  {
    B=B+analogRead(A2);
   delay(1);
  }
  Y=(float)B/20.0; 
  for(byte i=0;i<22;i++)
  {
    if(T_Ref[0+i]<Y&&Y<=T_Ref[1+i])
      T=-15+(5*i);
      else
      T=T;
   }
}

void display_zeigen(unsigned int DRU, int TMP)				//program for data display_zeigen
{
	display.clearDisplay();
	display.setTextColor(WHITE);
  display.setCursor(5,10);
	display.setTextSize(2.7);
	display.print("P: ");display.print(DRU,DEC);display.println(" Bar");
  display.setCursor(5,40);
  display.print("T: ");display.print(TMP,DEC);display.println(" ^C");
	display.display();
	display.clearDisplay();
}

Hallo liebe Gemeinde,

im Rahmen meiner BA befassei ch mich seit kurzem mit Arduino Programmierung und komme bei folgendem Thema leider nicht weiter:

das ist ein Programm für die Anstreuerung einer Ventile. Wenn bug[0]==1 soll die Strom auf 4A gesetzt werden und 4 Sekunden halten. Danach soll er inerhalb von ca. 3 Sekunden auf 0,6A fallen. Ich will mein Programm zu abändern, dass man die Ventile jederzeit schließen kann.

Vielen Dank im Voraus.

weg mit den delays.
und eine Finite State Machine programmieren.

Mach eine nicht blockierenden Ablauf.

Fang mit dem Beispiel "Blink Without Delay" zum Grundverständnis an.
Wenn du danach noch weitere Fragen hast, gerne.

weg mit den delays.

Und weg mit den for Schleifen. (Das meinte noiasca mit der FiniteStateMachine)

(deleted)

Ich beginne bei so etwas immer mit einem groben Bild.

Der TO beschreibt 3 Status mit folgenden Übergängen

20200827_182811m.jpg

Daraus macht man dan mit zweimal BlinkWithoutDelay in etwa so etwas:

bei mir sinds halt zwei Buttons:

/*
   https://forum.arduino.cc/index.php?topic=702407.0

   Finite state machine
   IDLE     Warten auf Startereignis
   HALTEN   Vollgas Ausgabe 255
   ABFALLEN Langsames Abschwächen bis 0

 */
enum class State {IDLE, HALTEN, ABFALLEN} state;  //Status für die FSM

const byte startPin = A0;    // Button gegen GND
const byte stopPin = A1;     // Button gegen GND
const byte pwmPin = 3;       // eine LED zum simulieren des Ausgangs

uint32_t previousMillis;
const uint8_t maxStep = 255;
uint8_t step = maxStep;

void doFSM()
{
  switch (state)
  {
    case State::IDLE :
      checkStart();

      break;
    case State::HALTEN :
      checkStop();  // prüfen auf abbruch
      if (millis() - previousMillis > 4000)  // prüfen auf Zeitablauf
      {
        Serial.println(F("weiter auf ABFALLEN"));
        state = State::ABFALLEN;
        previousMillis = millis();
        step = maxStep;
      }
      break;
    case State::ABFALLEN :
      // do
      checkStop();                                        // prüfen auf Abbruch
      if (millis() - previousMillis > (3000 / maxStep))   // ist was zu tun, Wir teilen den Intervall durch unsere Step, also etwa all 3000/25
      {
        Serial.print(".");                                // damit wir sehen dass sich was tut
        step--;
        analogWrite(pwmPin, step);                        // pwm dimmen
        previousMillis = millis();
      }
      // prüfen auf fertig
      if (step < 2)
      {
        Serial.println(F("\nweiter auf IDLE"));
        analogWrite(pwmPin, 0);
        state = State::IDLE;
      }
      break;
  }
}

void checkStart()
{
  if (digitalRead(startPin) == LOW)
  {
    Serial.println(F("\nstart pressed"));
    state = State::HALTEN;
    analogWrite(pwmPin, maxStep);
    previousMillis = millis();
  }
}

void checkStop()
{
  if (digitalRead(stopPin) == LOW)
  {
    Serial.println(F("\nstop pressed"));
    state = State::IDLE;
    analogWrite(pwmPin, 0);
  }
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.print(F("FSM Grundgerüst"));
  pinMode(startPin, INPUT_PULLUP);
  pinMode(stopPin, INPUT_PULLUP);
  pinMode(pwmPin, OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  doFSM();
}

20200827_182811m.jpg

@noiasca

Vielen Dank für die scnhelle Antwort. Wenn ich millis() benutze, kann ich Timer Funktion ja weglassen?

@Peter-CAD-HST
Danke für den Hinweis.

Ich will ja meine Strom für 4s halten und anschließend soll der innerhalb von ca. 3 Sekunden auf 0,6A fallen.Dafür hat @noiasca in seinem code step verwendet. Sorry, ich kann es leider nicht verstehen.

Statt deiner for Schleife benutzt noiasca (3000/maxstep = 11), verkleinert also alle 11 ms step um eins und gibt den step-Wert (255 - 1) als PWM-Wert aus. Ist so nach knapp 3s fertig.

das hat sich ergeben auf Grund der Anforderung, dass das nicht sofort "auf 0,6" abgeshaltet wird, sondern für mich klang das nach "langsam runterdimmen in 3 Sekunden". Der PWM hat 8bit, daher "dimme" ich in 3000 Millisekunden, eben die 255 Schritte runter.

4        ________
3                __
2                  __
1                    __
0 ______               ______

  .idle.  4sec   3sec  .idle.

wenn das nicht richtig ist. Solltest du deine Anforderung besser beschreiben.

edit: Michael hat es richtig erkannt. Da ich nicht weis, in welchen Stufen DU runterdimmen willst, gibts dafür halt einen Parameter wie granular das sein soll. Bei mir sind es die angesprochenen 3000/255 etwa 11 Millisekunden.
Du kannst dein Runterfahren auch anders machen. Wichtig ist, dass es nicht blockierend ist.

ich habe nicht behauptet, dass dein Lösungsvorschlag falsch sei. Mir geht es ausschließlich um step. Es ist im Sketch rot hinterlegt. Das kommt immer wieder in dem Code vor, z.B. step-- oder step<2.

Die rot Hinterlegung wird von irgendeiner Lib kommen. Das kann ich nicht negativ beeinflussen.

step-- … klar ich will von 255 auf 0 runterzählen. kannst auch step = step-1 schreiben.
step<2 … ich warte nicht auf 0 sondern höre schon bei 1 auf. Das ist ja nur die Abbruchbedingung. Kannst du ändern so wie es dir gefällt.

@noiasca vielen Dank für die Erklärung. Ich gebe es zu, dass die Problemstellelung nicht korrekt genug beschrieben worden. Ich versuche es ausführlicher zu beschreiben:

Das Programm ist für den Treiber von einem Wasserstofftank (WT) vorgesehen. Man kann unter anderem die Ventile vom WT mit CAN-Befehlen ansteuern. Wenn der CAN-Befehl 01 00 00 00 00 00 00 00 lautet, soll die Ventile geöffnet werden (es gibt keinen externen Schalter/Taster dafür). Damit die Verluste zu minimieren, soll der Strom beim geöffneten Zustand zuerst auf 4A springen und nach 4 Sekunden innerhalb von 3S auf 0,6A fallen. Der CAN-Befehl 00 00 00 00 00 00 00 00 schließt dann die Ventile I=0A.

Ich versuche es ausführlicher zu beschreiben

Deine Frage "Abbruch einer Funktion" hat nichts mit Wasserstofftanks oder CAN Bus zu tun.
Die hier diskutierte Antwort jedenfalls nicht. Da geht es nur darum, wie man nicht blockierenden Code schreiben kann. Also ohne delay und ohne blockierende for-Schleifen.

Wenn du das FadeOutWithoutDelay-Prinzip verstanden hast, kannst du es an deine Aufgabenstellung selbst anpassen.

Für Probleme mit dem CAN Bus machst du besser einen neuen Thread auf.
Bei Problemen mit Wasserstofftanks sind wir an Beschreibung und Lösung interessiert, aber sonst vermutlich eher das falsche Forum.