Start sequencer : different bricks working on their own not working together...

Hi everyone,

Having debugged the fact that my H-bridge does work (in another thread), I'm coming back with bugs that are very hard for me to find...

I took some already written code (by myself so of low quality in itself...) that was working on it's own and compiled a couple of sketches with some other features to end up with... a non working, very weird acting code...

So before I post the code, here are -among others- the problems that I'm at difficulty to solve :

  • The code -sort of- works if I don't use the 3seconds "debounce" mode (test3s()) that I implemented (you have to press the start button during 3s to start it) but it doesn't work with it.

  • I have a mode selection switch that I've wired so it gives +5V on 2 arduino DI that are pulled down through a 15K resistor. If I make a very simple test sketch, the switch works perfectly everytime but when I implement it in the code (function pollswitch()), it doesn't really act on anything and I always have the same mode.

  • I'm controlling a H-bridge on pin 45 through PWM analogwrite. BUT if I put anything else than 255 on this analogwrite (during 5-6seconds phase), it won't light up the LED strip I'm controlling (for simulation) whereas if I make a simple fade sketch with it, it reacts perfectly. I've searched everywhere for a line that would put it back to 0 or such but didn't find it. Also, why would it work with 255 but nothing else?

Here's the first part of the code :

#include <Servo.h> 
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <PID_v1.h>
#include <TimerOne.h>

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Sets the LCD I2C address

Servo servo1;            // Engagement servo declaration   
Servo motor1;            // Starter motor declaration

// PIN affectation
const int start = 14;     //Start button
//const int Emerg = 18;     //Emergency stop button
const int PPump = 45;     //Preheat pump PWM motor driver
const int servo = 42;     //PWM output for starter motor engagement servo
const int motor = 43;     //PWM output for starter motor speed (controls the ESC)
const int modeventil = 3;    //Mode Ventilation switch (HIGH=ON)    15K PULLDOWN INSTALLED
const int modestart = 4;    //Mode Start switch (HIGH=ON)           15K PULLDOWN INSTALLED
const int spark = 34;       //Spark module relay   (LOW=ON)
const int drain = 35;       // Drain Valves relay  (LOW=ON)
const int led = 19;        //status led
const int LED1=22;         //LED1 = STATUS (blinking)
const int LED2=23;         //LED2 = Spark
const int LED3=24;         //LED3 = Servo + Starter Motor
const int LED4=25;         //LED4 = PreHeatPump (PPump)
const int LEDstart=20;     //LED bouton start blinking

double Setpoint, Input, Output;

const long t1 = 0;    //phase 1 duration in ms
const long t2 = 5000;    //phase 2 duration in ms
const long t3 = 6000;    //phase 3 duration in ms
const long t4 = 25000;    //phase 4 duration in ms
const long t5 = 30000;    //phase 5 duration in ms

const long tv = 40;  //ventilation in s

const int v1=5;       //STAND-BY Starter motor Speed (0RPM)
const int v2=50;      //MID starter motor speed (3000RPM)
const int v3=90;      //MAX starter motor speed  (~18000RPM)

int rampstepup=100;        //timestep between two incrementations of Starter motor speed
int rampstepdown=100;      //timestep between two decrementations of PreheatPumpMotor speed
int vtemp=0;             //speed variable to increment the starter motor speed with a ramp
int rampx=0;             //time variable to increment the starter motor speed with a ramp

unsigned long sequencestart = 0;        //Time variables
unsigned long previousMillis=0;
unsigned long currentMillis=0;
unsigned long test3s=0;
int blinkperiod = 200;                  //LED blink period (200ms=5Hz)

boolean sequence_auth=false;       //start authorization flag
boolean sequence_running=false;    //sequence running flag
boolean modeswpos=HIGH;            //mode switch reading : Ventilation=HIGH ; Start=LOW
int state=0;                       //State indicator (will be used to display which phase it is in on the LCD
int pin=0;
boolean ledState=LOW;

int read_state = 1;   //for RS232 Serial communication with FADEC
int readindex = 0;    //for RS232 Serial communication with FADEC
byte trame[48];       //for RS232 Serial communication with FADEC
int i;                //for RS232 Serial communication with FADEC
int egt=0;            //Exhaust gas temperature reading from FADEC
long int RPMN2=0;

unsigned long degt; //time value to "debounce" egt overheat

PID Preheat(&Input, &Output, &Setpoint,2,5,1, DIRECT);



void setup() {      

  digitalWrite(spark,HIGH);    //Switching off Spark relay
  digitalWrite(drain,HIGH);    //Switching off drain relay
  lcd.begin(20,4);   // initialize the lcd for 20 chars 4 lines,  on backlight

  servo1.attach(servo);
  motor1.attach(motor);
  Serial.begin(19200);    //Initializing serial communication with PC (via USB)
  Serial2.begin(2400);    //Initializing the serial communication with the FADEC

  Input=egt;
  Setpoint=250;
  Preheat.SetMode(AUTOMATIC);
  Preheat.SetOutputLimits(64, 240);    //setting limits to PID outputs

  pinMode(motor, OUTPUT);
  pinMode(start, INPUT); 
  // pinMode(Emerg, INPUT);  
  pinMode(PPump, OUTPUT);
  pinMode(servo, OUTPUT);
  pinMode(modeventil, INPUT);
  pinMode(modestart, INPUT);
  pinMode(spark, OUTPUT);
  pinMode(drain,OUTPUT);
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(LED4, OUTPUT);
  digitalWrite(LED1,LOW);      //Lighting the LEDS 1s @ startup (test)
  digitalWrite(LED2,LOW);      //Lighting the LEDS 1s @ startup (test)
  digitalWrite(LED3,LOW);      //Lighting the LEDS 1s @ startup (test)
  digitalWrite(LED4,LOW);      //Lighting the LEDS 1s @ startup (test)
  delay(1000);
  digitalWrite(LED1,HIGH);
  digitalWrite(LED2,HIGH);
  digitalWrite(LED3,HIGH);
  digitalWrite(LED4,HIGH);

  motor1.write(v1);    //Starter Motor ESC STAND-BY

  rampstepup=((t4-t3-1000)/(v3-v2));    //calculating the time step for each +1 speed step #STARTER MOTOR RAMP

  //SPLASH SCREEN
  lcd.backlight();
  delay(250);
  lcd.noBacklight();
  delay(250);
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print("Turbotech Industries");
  lcd.setCursor(4,3);
  lcd.print("Turbine T1");
  delay(1000);  
  lcd.clear();
  lcd.setCursor(0,2);
  lcd.print("     READY?        ");
  delay(1000);
  lcd.clear();
  lcd.setCursor(0,2); 
  lcd.print("    GO!     ");
  delay(1000);
  lcd.clear();

}

void loop() 
{
  currentMillis=millis();
  read_fadec ();
  pollswitch ();
  safety3s ();
 // launchpad ();
  tmonitoring();

}

//Polling the switch so that you can't change the sequence while running
void pollswitch ()
{
  if (sequence_auth==false && sequence_running==false /* && state!=10 && state!=11 && state!=2 */)
  {
    if(digitalRead(modestart)==HIGH)
    {
      modeswpos=HIGH;
      state=1;
    }
    else
    {
      if(digitalRead(modeventil)==HIGH)
      {
        modeswpos=LOW;
      }
    }
  }

}


//Temperature monitoring to stop everything in case of an overtemperature 
void tmonitoring ()
{
  if ((egt > 850) && degt==0)
  {
    degt = currentMillis;
  }

  if (degt!=0 && millis()-degt>500)
  {
    if(egt>850){
      overheatstop();
    }
    else if(egt<650){
      degt=0;
    }
  }
}


//Requires to press 3seconds the start button (and keep it pressed) before any action is taken.
void safety3s ()
{
  if (sequence_auth==false && sequence_running==false && digitalRead(start)==HIGH)
  {
    state=2;
    digitalWrite(LED1,LOW);  //Lighting LED1 while waiting the 3seconds
    ledState=LOW;


    if ((currentMillis-test3s)>3000 && digitalRead(start)==HIGH)
    {
      sequence_auth=true;
      launchpad();
      if(sequence_running==false);
      {      
        sequencestart=currentMillis;
      }
    }
  }
  else{
    test3s=millis();    //if test3s = currentMillis, it can never reach the 3seconds...

    if(digitalRead(start)==HIGH)  //Blinking LED1 during Start button pressed and sequence running
    {
      if((currentMillis - previousMillis) > blinkperiod) {
        previousMillis = currentMillis;   
        if (ledState == LOW)
          ledState = HIGH;
        else
          ledState = LOW;
        digitalWrite(LED1, ledState);
      }
    }
  }
  if(digitalRead(start)==LOW && state!=10 && state!=11)
  {
    sequence_auth=false;
    digitalWrite(LED1,HIGH);
    digitalWrite(LED2,HIGH);
    digitalWrite(LED3,HIGH);
    digitalWrite(LED4,HIGH);
    motor1.write(0);
    servo1.write(0);
    analogWrite(PPump,0);
    digitalWrite(spark,HIGH);
    digitalWrite(drain,HIGH);
    sequencestart=currentMillis;
    state=1;
  }
}

And part 2 :

//SEQUENCE CHOICE AND LAUNCH
void launchpad()
{
  switch (modeswpos)
  {
  case LOW:
    startsequence();
    break;
  case HIGH:
    ventilation();
    break;
  }
}

//START SEQUENCE
void startsequence()
{
  //PHASE 2 : 0-5(t2)seconds
  if (digitalRead(start)==HIGH && (millis()-sequencestart)<t2)
  {
    sequence_running=true;
    servo1.write(95);          //Commanding servo to engage Starter motor
    motor1.write(v2);          //running the starter motor @ 3000RPM
    digitalWrite(LED2,LOW);    //LED2 (STARTER MOTOR) ON
    digitalWrite(drain,LOW);   //Drain relay ON, drains OPEN.
    state=3;
    if((currentMillis-sequencestart)>3000)
    {
      digitalWrite(spark,LOW);
      digitalWrite(LED2,LOW);    //LED3 (Spark indicator) ON
    }
    else
    {
      digitalWrite(spark,HIGH);
      digitalWrite(LED3,HIGH);    //LED3 (Spark indicator) OFF
    }
  }

  else        //PHASE 3 : 5-6seconds (IGNITOR ON)
  {
    if (digitalRead(start)==HIGH && (millis()-sequencestart)<t3)
    {
      sequence_running=true;
      digitalWrite(spark,LOW);      //spark module ON
      digitalWrite(drain,HIGH);      //Drain relay OFF / drains closed
      servo1.write(95);
      motor1.write(v2);
      digitalWrite(LED3,LOW);      //LED3 (Spark indicator) ON
      analogWrite(PPump,127);
      digitalWrite(LED4,LOW);    //LED4 (PreheatPump) ON
      digitalWrite(LED2,LOW);    //LED2 (STARTER MOTOR) ON
      state=4;
    }

    else  //PHASE 4 : 6-25seconds
    {         
      if (digitalRead(start)==HIGH && (millis()-sequencestart)<t4)
      {
        digitalWrite(spark,LOW);      //SPARK module ON
        digitalWrite(LED3,LOW);       //LED3 (Spark indicator) ON
        digitalWrite(drain,HIGH);     //Drain relay OFF / drains closed
        servo1.write(95);
        digitalWrite(LED2,LOW);    //LED2 (STARTER MOTOR) ON
        state=5;

        //RAMP2
        if((millis()-rampx)>rampstepup && vtemp<v3 && (millis()-sequencestart<(t4)))
        {
          vtemp=vtemp+1;
          motor1.write(vtemp);
          rampx=millis();
        }      
        else
        {
          motor1.write(vtemp);
        }
        //RAMP2

        Input=egt;
        lcd.setCursor(0,0);
        lcd.print("EGT = ");
        lcd.print(egt);
        Preheat.Compute();
        analogWrite(PPump,Output);
        int xxx=255-Output;          //LEDs being negative sunk, PWM has to be inverted.
        analogWrite(LED4,xxx);
        lcd.setCursor(0,1);
        lcd.print("PWM Preheat = ");
        lcd.print(Output);
        rampstepdown=((t5-t4)/(Output));
      }

      else  //PHASE 5 25-30seconds
      {
        if (digitalRead(start)==HIGH && (millis()-sequencestart)<t5)
        {
          motor1.write(5);
          digitalWrite(LED2,LOW);
          digitalWrite(spark,HIGH);
          digitalWrite(LED3,HIGH);
          state=6;
          servo1.write(0);

          //RAMPING PPump down
          if((millis()-rampx)>rampstepdown && vtemp>=0 && (millis()-sequencestart<(t5)))
          {
            vtemp=vtemp-1;
            analogWrite(PPump,vtemp);
            int xxx=255-vtemp;          //LEDs being negative sunk, PWM has to be inverted.
            analogWrite(LED4,xxx);
            rampx=millis();
          }      
          else
          {
            analogWrite(PPump,vtemp);
          }


        }
        else
        {
          if (sequence_running==true && sequence_auth == true)
          {
            while(digitalRead(start)==HIGH)
            {
              state=7;      //Waiting for operator to release start button
  
            }
            sequence_auth=false;
            sequence_running=false;
            motor1.write(5);
            servo1.write(0);
            analogWrite(PPump,0);
            digitalWrite(spark,HIGH);
            digitalWrite(LED2,HIGH);
          }
        }   

      }
    } 
  }

}





//VENTILATION
void ventilation()
{
  //PHASE 1 : continuous
  if (sequence_auth==true && digitalRead(start)==HIGH)

  {
    sequence_running=true;
    servo1.write(95);
    motor1.write(50);        //Ventilating the engine @3000RPM
    digitalWrite(drain,LOW);  //Draining excess fuel
    state=8;
  }

  else
  {
    {
      state=9;
      sequence_running=false;
      motor1.write(5);
      servo1.write(0);
      analogWrite(PPump,0);
      digitalWrite(spark,HIGH);
      digitalWrite(drain,HIGH);
    }
  }

}



void overheatstop()

{
  lcd.setCursor(0,3);
  lcd.print("OVERHEAT!");
  sequence_auth=false;
  state=10;

  if (servo1.read()>45)
  {
    servo1.write(95);
    analogWrite(PPump,0);
    digitalWrite(spark,HIGH);
    digitalWrite(drain, LOW);  //Draining excess fuel    
    motor1.write(64);          //Ventilating @4000RPM
    delay(5000);
    state=1;
    sequence_running=false;
  }
  else
  {
    emergstop();
  }
}

void emergstop()
{
  sequence_auth=false;
  state=11;
  motor1.write(5);
  servo1.write(0);
  analogWrite(PPump,0);
  digitalWrite(spark,HIGH);
  lcd.clear();
  lcd.setCursor(0,3);
  lcd.print("EMERGENCY STOP!");
  delay(2000);
  state=1;
  sequence_running=false;

}

void read_fadec () //extracting temperature and speed informations from FADEC RS232 frames
{
  byte buffer;

  if (Serial2.available()>0)
  {
    buffer = Serial2.read();

    switch (read_state) {
    case 1:
      if (buffer == 252) {
        read_state = 2;
        // debut de trame, on se prepare a recevoir
        readindex = 0;
        break;
      }

    case 2:
      if (buffer == 253) {
        read_state = 3;
      }
      else {
        // mauvaise synchro, on reset 
        read_state = 2;
      }

      break;

    case 3:
      trame[readindex] = buffer;

      if (readindex >= 47) {
        // on a eu le dernier byte
        //for(int i=0;i<47;i++)
        //{
        //Serial.print("vitesse : ");
        //Serial.print(trame[37]); 
        //Serial.println("000 RPM");
        RPMN2 = word (trame[47],trame[46]);
        //Serial.print(RPMN2);
        //Serial.println("00 RPM");
        //Serial.print("Temperature : "); 
        //Serial.println(trame[43]*4);
        egt=100;//(trame[43]*4);
        //Serial.println(Output);
        //Serial.println();
        //}
        read_state = 1;
      }

      readindex ++;
      break;

    }
  }
}

Also another weird thing I can't explain myself :

During phase 4, I print some stuff to the LCD (EGT temperature and PWM value).

But they only appear when I release the start button (and when as a result, I'm not in that phase anymore...)
How can it be?

Thanks for the help!

Marc

If you have a long piece of code that won't fit, just post it as an attachment so it is all in one piece.

You have a lot of code and I am lazy.

If this was my project I would reduce most of the different functions to a stub, eg

void tmonitoring() {

}

and I would drop all the LCD stuff and just use the serial monitor for debugging. Then I could study the part that is causing problems without the risk of problems elsewhere.

I would also take all the action stuff (digitalWrite()s etc) out of the function startsequence() and put it in one or more separate functions so all that is left in the startsequence is the code for the logic of the sequence.

...R

Hi Robin,

I'm just wondering, where does it end... I've already divided the different functions of the code into functions that are called in the loop.
But where should I put all the digitalwrites and all? In the end I'm just gonna be calling one function after another, is there an advantage to that? (I'm still new to programming).

Thanks for the help,

Marc

marc426:
In the end I'm just gonna be calling one function after another, is there an advantage to that? (I'm still new to programming).

Strictly speaking it is the Arduino that will be doing all the calling and it doesn't care.

The advantage of lots of small functions is that it allows you to get different pieces working in isolation from others. And if the functions have meaningful names it makes the logic much clearer. My aim (not always achieved) is to write code that I will understand again in 6 months time after reading through it once.

This Thread illustrates what I am talking about.

...R

Thank you Robin for the thread link.

Strictly speaking it is the Arduino that will be doing all the calling and it doesn't care.

But there is some overhead associated with each function call. Having a function that does nothing but call an Arduino function does not improve the readability of your code. Nor does having too many functions:

void loop()
{
   byte val = myDigitalRead(somePin);
}

byte myDigitalRead(int somePin)
{
   return readTheDigitalPin(somePin);
}

byte readTheDigitalPin(int somePin)
{
   return forRealThisTime(somePin);
}

byte forRealThisTime(int somePin)
{
   return digitalRead(somePin);
}

PaulS:
Nor does having too many functions:

I assume that users will apply my suggestions with a little common sense and not deliberately try to contrive ridiculous situations.

...R

Thats rather a good post Robin, i missed it first time around.
It deserves a sticky or even if one is not available a mention in one of the existing stickies.

Boardburner2:
Thats rather a good post Robin, i missed it first time around.
It deserves a sticky or even if one is not available a mention in one of the existing stickies.

Thank you.
The sticky business is not my call.

...R

I assume that users will apply my suggestions with a little common sense and not deliberately try to contrive ridiculous situations.

I'd hope so, but how many times have we seen people post code where loop() calls exactly one other function?