3

In my recent project, I have done everything means capture serial data and split it out in proper form.

Until now everything is fine. But when I add another portion of code which contains Interrupt. Now, whenever Interrupt come into the picture, my incoming serial data totally destroy. And when I remove that interrupt portion then everything is fine. But this interrupt is also given one my reading(RPM READING).

I tried out detachinterrupt function, it disables my interrupt then I can't get my RPM READING.

I also tried out interrupts() and noInterrupts() function. But I don't get any results. I think I'm not able to utilize my code with this function.

Here, below my whole code which is a little bit lengthy. But, it's necessary.

#include<LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 7, 6, 5, 4);

String data_TPS_Json = "";
String data_MAP_Json = "";
String data_LOAD_TM_Json = "";

String data_LOAD_RI_Json = "";
String data_RPM_Json = "";
String data_INJECTION_TIME_Json = "";

String response = "";
bool begin = false;

char in;
int len = 0;

float TPS_Json;
float MAP_Json;
float LOAD_TM_Json;

float LOAD_RI_Json;
float RPM_Json;
float INJECTION_TIME_Json;

//----------------------------For MAP calculation----------------------------//
float MAP_MIN = 0.85;
float MAP_MAX = 1.90;

int LOAD_MIN_MAP[] = {1, 2};
int LOAD_MAX_MAP[] = {3, 4};

float mMAP[2] = {};
float yMAP[2] = {};

int i, j, a;
float MAP, mFinalMAP, yFinalMAP;

//----------------------------For TPS calculation----------------------------//
float TPS_MIN = 0.00;
float TPS_MAX = 5.00;

int LOAD_MIN_TPS[] = {1, 3};
int LOAD_MAX_TPS[] = {2, 4};

float mTPS[2] = {};
float yTPS[2] = {};

int k, l, b;
float TPS, mFinalTPS, yFinalTPS;

//----------------------------For LOAD calculation---------------------------//
int LOAD_MIN = 2;
int LOAD_MAX = 100;

float injTime_MIN_LOAD[] = {6.20, 6.26};
float injTime_MAX_LOAD[] = {7.80, 8.06};

float mLOAD[2] = {};
float yLOAD[2] = {};

int m, n, c;
float LOAD, mFinalLOAD, yFinalLOAD;

//----------------------------For RPM calculation----------------------------//
const int kPinRPM = 3;        // RPM / Digital Pin 3
const int RPMInterrupt = 1;   // RPM's interrrupt pin
byte engineCylinders = 2;         // Engine cylinders = 4;
byte engineCycles = 4;            // Engine cycle = 2
int refreshInterval = 750;        // Milliseconds between sensor updates
unsigned long previousMillis = 0;
volatile int RPMpulses = 0,  RPM0 = 0;
int RPM, Final_RPM;

int RPM_MIN = 400;
int RPM_MAX = 6000;

float injTime_MIN_RPM[] = {6.20, 7.80};
float injTime_MAX_RPM[] = {6.26, 8.06};

float mRPM[2] = {};
float yRPM[2] = {};

int o, p, d;
float mFinalRPM, yFinalRPM;

//------------------------For GAS PRESSURE calculation-----------------------//
float minPosVolGas = 0.00;
float maxPosVolGas = 2.50;

float minInjPerPos = 0.35;
float maxInjPerPos = 0.00;

float minNagVolGas = 2.50;
float maxNagVolGas = 5.00;

float minInjPerNag = 0.00;
float maxInjPerNag = 0.25;

float GAS_Pressure, mGasPos, mGasNag, yGasPos, yGasNag;

//----------------------For INJECTION TIME calculation-----------------------//
float yInjTime, injTime, gasInjTime;
volatile uint32_t kInjTime = 0;

const int kPinInj = 8;

void setup() 
{
  Serial.begin(9600);
  lcd.begin(16, 2);

  pinMode(kPinRPM, INPUT_PULLUP); // Enable internal pullup
  attachInterrupt(RPMInterrupt, countRPM, FALLING); //Interrupt for RPM

  pinMode(kPinInj, OUTPUT);  
}

void loop() 
{
  //----------------------------MAP----------------------------//

  MAP = analogRead(A0) * (5.0 / 1023.0);

  for(a = 0; a < 2; a++)
  {
    mMAP[i] = (LOAD_MIN_MAP[a] - LOAD_MIN_MAP[a]) / (MAP_MAX - MAP_MIN);
    yMAP[j] = mMAP[i] * (MAP - MAP_MIN) + LOAD_MIN_MAP[a];
  }

  //----------------------------TPS----------------------------//

  TPS = analogRead(A1) * (5.0 / 1023.0);

  for(b = 0; b < 2; b++)
  {
    mTPS[k] = (LOAD_MAX_TPS[b] - LOAD_MIN_TPS[b]) / (TPS_MAX - TPS_MIN);
    yTPS[l] = mTPS[k] * (TPS - TPS_MIN) + LOAD_MIN_TPS[b];
  }

  //----------------TPS/MAP CALLIBRATION / LOAD----------------//

  mFinalTPS = (yMAP[1] - yMAP[0]) / (TPS_MAX - TPS_MIN);
  yFinalTPS = mFinalTPS * (TPS - TPS_MIN) + yMAP[0];

  mFinalMAP = (yTPS[1] - yTPS[0]) / (MAP_MAX - MAP_MIN);
  yFinalMAP = mFinalMAP * (MAP - MAP_MIN) + yTPS[0];

  LOAD = (yFinalTPS + yFinalMAP) / 2;

  //----------------------------LOAD---------------------------//

  for(c = 0; c < 2; c++)
  {
    mLOAD[m] = (injTime_MAX_LOAD[c] - injTime_MIN_LOAD[c]) / (LOAD_MAX - LOAD_MIN);
    yLOAD[n] = mLOAD[m] * (LOAD - LOAD_MIN) + injTime_MIN_LOAD[c];
  }

  //----------------------------RPM----------------------------//

  if(millis() - previousMillis > refreshInterval)
  {
    previousMillis = millis();
    RPM =  getRPM();
  }

  for(d = 0; d < 2; d++)
  {
    mRPM[o] = (injTime_MAX_RPM[d] - injTime_MIN_RPM[d]) / (RPM_MAX - RPM_MIN);
    yRPM[p] = mRPM[o] * (RPM - RPM_MIN) + injTime_MIN_RPM[d];
  }

  //-----------LOAD/RPM CALLIBRATION / INJECTION TIME----------//

  mFinalLOAD = (yRPM[1] - yRPM[0]) / (LOAD_MAX - LOAD_MIN);
  yFinalLOAD = mFinalLOAD * (LOAD - LOAD_MIN) + yRPM[0];

  mFinalRPM = (yLOAD[1] - yLOAD[0]) / (RPM_MAX - RPM_MIN);
  yFinalRPM = mFinalRPM * (RPM - RPM_MIN) + yLOAD[0];

  yInjTime = (yFinalLOAD + yFinalRPM) / 2;
  injTime = (yInjTime * 1000) / 1000;

  //------------------JSON SERIAL DATA---------------------//

  while(Serial.available() || !begin)
  {
      in = Serial.read();

      if (in == '{')
      {
        begin = true;
      }

      if(begin)
      {
        response += (in);
      }

      if(in == '}')
      {
        break;
      }

      delay(1);
  }

  len = response.length();

  if(len == 39)
  {
    data_TPS_Json = response.substring(8, 12);
    data_MAP_Json = response.substring(21, 25);
    data_LOAD_TM_Json = response.substring(35, 37);

    jsonMapTps();
  }

  if(len == 52)
  {
    data_LOAD_RI_Json = response.substring(9, 13);
    data_RPM_Json = response.substring(22, 26);
    data_INJECTION_TIME_Json = response.substring(46, 50);

    jsonRpmLoad();
  }  

  //------------------------GAS_PRESSURE-----------------------//

  GAS_Pressure =  analogRead(A2) * (5.0 / 1023.0);

  mGasPos = (maxInjPerPos - minInjPerPos) / (maxPosVolGas - minPosVolGas);
  yGasPos = mGasPos * (GAS_Pressure - minPosVolGas) + minInjPerPos;

  mGasNag = (maxInjPerNag - minInjPerNag) / (maxNagVolGas - minNagVolGas);
  yGasNag = mGasNag * (GAS_Pressure - minNagVolGas) + minInjPerNag;

  if(GAS_Pressure >= 0.00 && GAS_Pressure < 2.50)
  {
    gasInjTime = injTime + (injTime * yGasPos);
  }
  else if(GAS_Pressure >= 2.50 && GAS_Pressure <= 5.00)
  {
    gasInjTime = injTime - (injTime * yGasNag);
  }

  //--------------------Pulse Generation-----------------------//

  if((kInjTime > 0) && ((millis() - kInjTime) >= injTime))
  {
    kInjTime = 0;
    digitalWrite(kPinInj, 0);
  }                                  
}

void countRPM()
{
  RPMpulses++;

  digitalWrite(kPinInj, RPMpulses & 1); // Set or clear kPinInj
  if(RPMpulses & 1) 
  kInjTime = millis();  // Store alternate times
}

int getRPM()
{
  Final_RPM = ((RPMpulses * (60000UL / 2) * (engineCycles/engineCylinders)) / refreshInterval);
  RPM0 = RPMpulses &= 1;
  RPMpulses - RPM0;
  return Final_RPM;
}

void jsonMapTps()
{
    TPS_Json = data_TPS_Json.toFloat();
    MAP_Json = data_MAP_Json.toFloat();
    LOAD_TM_Json = data_LOAD_TM_Json.toFloat();

    lcd.setCursor(0, 0);
    lcd.print(TPS_Json);
    lcd.setCursor(8, 0);
    lcd.print(MAP_Json);
    lcd.setCursor(0, 1);
    lcd.print(LOAD_TM_Json);  
}

void jsonRpmLoad()
{
    LOAD_RI_Json = data_LOAD_RI_Json.toFloat();
    RPM_Json = data_RPM_Json.toFloat();
    INJECTION_TIME_Json = data_INJECTION_TIME_Json.toFloat();

    lcd.setCursor(0, 0);
    lcd.print(LOAD_RI_Json);
    lcd.setCursor(8, 0);
    lcd.print(RPM_Json);
    lcd.setCursor(0, 1);
    lcd.print(INJECTION_TIME_Json);  
}
5
  • Please add memory statistics. Commented May 26, 2017 at 10:46
  • 2
    You haven't specified what hardware you are using. You need to narrow down the fault. "My data gets destroyed" is not very helpful. What does you program read when you get an interrupt, how does this vary to normal? With that number of Strings in memory I agree with @MikaelPatel it is probably memory related. Commented May 26, 2017 at 11:44
  • @MikaelPatel means how many bytes consume by code?
    – Hasan
    Commented May 27, 2017 at 6:27
  • @CodeGorilla Hardware means Arduino Uno or Arduino Mega? Then I used here Arduino Mega. OK... So I have to give a full flow of what I want to do and what happens. Am I right?
    – Hasan
    Commented May 27, 2017 at 6:29
  • Your interrupt handler is short and simple. It should definitely not disturb your program. It does, however, increase memory usage (stack space), which could be the cause of your problems. You should definitely follow Jot's advice about making most variables local and getting rid of String objects. Commented Jun 20, 2017 at 10:18

2 Answers 2

1

You need to clean up the whole sketch. I will try to mention the most important things first.

For an Arduino Uno, this sketch uses 520 bytes RAM and 1528 bytes are free to use for stack and heap. That seems enough but with heap fragmentation it might be a problem, see: Adafruit about an increasing heap

The data_... Strings are only to display something. They can be replaced with normal strings. You could also make a single buffer of a char array for the "response".

The variables that are used in the interrupt routine and also outside the interupt routine should be made volatile.

When the variable begin is false, you still read data with Serial.read(). That can't be right. Could you rewrite that part ?

The variable kInjTime is used to store the millis() time and also to disable it by setting it to zero. That is not good programming since millis() can be zero. It is better to add an extra variable to turn that timing on and off.

The use of digitalPinToInterrupt() is advised when using attachInterrupt(). That makes it easier to see which pins are used.

The function digitalWrite() takes HIGH or LOW, not 0 or 1 and not a bit of a variable, only HIGH or LOW.

Try to use more local variables. You have too many variables as global, which makes it hard to read the sketch.

9
  • Oh...Thank you for this points that you mentioned. Let me explain every point.
    – Hasan
    Commented May 27, 2017 at 6:41
  • "data_" strings are displaying the value of data. Suppose serially data {"TPS":"0.40","MAP":"0.95","LOAD":"14"} comes. Then that "data_" strings hold 0.40, 0.95 & 14.
    – Hasan
    Commented May 27, 2017 at 6:49
  • Ok.. Means I have to initialize all that variable made volatile which I used in the Interrupt routine.
    – Hasan
    Commented May 27, 2017 at 6:52
  • Ok, that "Serial.read" portion is capture serial data. Ok, I can try to rewrite that portion.
    – Hasan
    Commented May 27, 2017 at 6:59
  • Ok, means I have to use another variable which holds 0 or 1?
    – Hasan
    Commented May 27, 2017 at 7:01
0

Finally got the solution. My method of capturing Serial string data is a little bit faulty. And also remove maximum strings and try to declare maximum local variables And use ArduinoJson library for parsing the data.

This is my modified code:

#include<LiquidCrystal.h>
#include <ArduinoJson.h>

LiquidCrystal lcd(12, 11, 7, 6, 5, 4);

String response = "";
bool begin = false, finished;

//----------------------------For MAP calculation----------------------------//
float MAP_MIN = 0.85;
float MAP_MAX = 1.90;

int LOAD_MIN_MAP[] = {1, 2};
int LOAD_MAX_MAP[] = {3, 4};

float mMAP[2] = {};
float yMAP[2] = {};

int i, j, a;
float MAP, mFinalMAP, yFinalMAP;

//----------------------------For TPS calculation----------------------------//
float TPS_MIN = 0.00;
float TPS_MAX = 5.00;

int LOAD_MIN_TPS[] = {1, 3};
int LOAD_MAX_TPS[] = {2, 4};

float mTPS[2] = {};
float yTPS[2] = {};

int k, l, b;
float TPS, mFinalTPS, yFinalTPS;

//----------------------------For LOAD calculation---------------------------//
int LOAD_MIN = 2;
int LOAD_MAX = 100;

float injTime_MIN_LOAD[] = {6.20, 6.26};
float injTime_MAX_LOAD[] = {7.80, 8.06};

float mLOAD[2] = {};
float yLOAD[2] = {};

int m, n, c;
float LOAD, mFinalLOAD, yFinalLOAD;

//----------------------------For RPM calculation----------------------------//
const int kPinRPM = 3;        // RPM / Digital Pin 3
const int RPMInterrupt = 1;   // RPM's interrrupt pin
byte engineCylinders = 2;         // Engine cylinders = 4;
byte engineCycles = 4;            // Engine cycle = 2
int refreshInterval = 750;        // Milliseconds between sensor updates
unsigned long previousMillis = 0;
volatile int RPMpulses = 0,  RPM0 = 0;
int RPM, Final_RPM;

int RPM_MIN = 400;
int RPM_MAX = 6000;

float injTime_MIN_RPM[] = {6.20, 7.80};
float injTime_MAX_RPM[] = {6.26, 8.06};

float mRPM[2] = {};
float yRPM[2] = {};

int o, p, d;
float mFinalRPM, yFinalRPM;

//------------------------For GAS PRESSURE calculation-----------------------//
float minPosVolGas = 0.00;
float maxPosVolGas = 2.50;

float minInjPerPos = 0.35;
float maxInjPerPos = 0.00;

float minNagVolGas = 2.50;
float maxNagVolGas = 5.00;

float minInjPerNag = 0.00;
float maxInjPerNag = 0.25;

float GAS_Pressure, mGasPos, mGasNag, yGasPos, yGasNag;

//----------------------For INJECTION TIME calculation-----------------------//
float yInjTime, injTime, gasInjTime;
volatile uint32_t kInjTime = 0;

const int kPinInj = 8;

void setup() 
{
  Serial.begin(9600);
  lcd.begin(16, 2);

  pinMode(kPinRPM, INPUT_PULLUP); // Enable internal pullup
  attachInterrupt(RPMInterrupt, countRPM, FALLING); //Interrupt for RPM

  pinMode(kPinInj, OUTPUT);  
}

void loop() 
{
  //----------------------------MAP----------------------------//

  MAP = analogRead(A0) * (5.0 / 1023.0);

  for(a = 0; a < 2; a++)
  {
    mMAP[i] = (LOAD_MIN_MAP[a] - LOAD_MIN_MAP[a]) / (MAP_MAX - MAP_MIN);
    yMAP[j] = mMAP[i] * (MAP - MAP_MIN) + LOAD_MIN_MAP[a];
  }

  //----------------------------TPS----------------------------//

  TPS = analogRead(A1) * (5.0 / 1023.0);

  for(b = 0; b < 2; b++)
  {
    mTPS[k] = (LOAD_MAX_TPS[b] - LOAD_MIN_TPS[b]) / (TPS_MAX - TPS_MIN);
    yTPS[l] = mTPS[k] * (TPS - TPS_MIN) + LOAD_MIN_TPS[b];
  }

  //----------------TPS/MAP CALLIBRATION / LOAD----------------//

  mFinalTPS = (yMAP[1] - yMAP[0]) / (TPS_MAX - TPS_MIN);
  yFinalTPS = mFinalTPS * (TPS - TPS_MIN) + yMAP[0];

  mFinalMAP = (yTPS[1] - yTPS[0]) / (MAP_MAX - MAP_MIN);
  yFinalMAP = mFinalMAP * (MAP - MAP_MIN) + yTPS[0];

  LOAD = (yFinalTPS + yFinalMAP) / 2;

  //----------------------------LOAD---------------------------//

  for(c = 0; c < 2; c++)
  {
    mLOAD[m] = (injTime_MAX_LOAD[c] - injTime_MIN_LOAD[c]) / (LOAD_MAX - LOAD_MIN);
    yLOAD[n] = mLOAD[m] * (LOAD - LOAD_MIN) + injTime_MIN_LOAD[c];
  }

  //----------------------------RPM----------------------------//

  if(millis() - previousMillis > refreshInterval)
  {
    previousMillis = millis();
    RPM =  getRPM();
  }

  for(d = 0; d < 2; d++)
  {
    mRPM[o] = (injTime_MAX_RPM[d] - injTime_MIN_RPM[d]) / (RPM_MAX - RPM_MIN);
    yRPM[p] = mRPM[o] * (RPM - RPM_MIN) + injTime_MIN_RPM[d];
  }

  //-----------LOAD/RPM CALLIBRATION / INJECTION TIME----------//

  mFinalLOAD = (yRPM[1] - yRPM[0]) / (LOAD_MAX - LOAD_MIN);
  yFinalLOAD = mFinalLOAD * (LOAD - LOAD_MIN) + yRPM[0];

  mFinalRPM = (yLOAD[1] - yLOAD[0]) / (RPM_MAX - RPM_MIN);
  yFinalRPM = mFinalRPM * (RPM - RPM_MIN) + yLOAD[0];

  yInjTime = (yFinalLOAD + yFinalRPM) / 2;
  injTime = (yInjTime * 1000) / 1000;

  //------------------JSON SERIAL DATA---------------------//

  StaticJsonBuffer<100> jsonBuffer;

  while (finished == false)
  {
    if (Serial.available())
    {
      const char in = Serial.read();
      if (in == '{')
      {
        response = "";  // Blank the string
        begin = true;
      }
      if (begin)
      {
        response += (in); // Only write if within the {}
      }
      if (in == '}')
      { 
        begin = false;   // Prevent any chars between } and { leaking through.
        break;
      }
    }
    delay(1);
  }

  JsonObject& root = jsonBuffer.parseObject(response);

  const char* ActionOne = root["ActionOne"];
  const char* ActionTwo = root["ActionTwo"];

  //--------------------TPS/MAP/LOAD-----------------------//

  if(root.containsKey("ActionOne"))
  {
    float TPS = root["TPS"];
    float MAP = root["MAP"];
    int LOAD = root["LOAD"];

    lcd.setCursor(0, 0);
    lcd.print(TPS);

    lcd.setCursor(8, 0);
    lcd.print(MAP);

    lcd.setCursor(0, 1);
    lcd.print(LOAD);  
  }

 //--------------LOAD/RPM/INJECTION_TIME-------------------//

  if(root.containsKey("ActionTwo"))
  {
    float LOAD = root["LOAD"];
    int RPM = root["RPM"];
    float INJECTION_TIME = root["INJECTION_TIME"];

    lcd.setCursor(0, 0);
    lcd.print(LOAD);

    lcd.setCursor(8, 0);
    lcd.print(RPM);

    lcd.setCursor(0, 1);
    lcd.print(INJECTION_TIME);    
  }

  //------------------------GAS_PRESSURE-----------------------//

  GAS_Pressure =  analogRead(A2) * (5.0 / 1023.0);

  mGasPos = (maxInjPerPos - minInjPerPos) / (maxPosVolGas - minPosVolGas);
  yGasPos = mGasPos * (GAS_Pressure - minPosVolGas) + minInjPerPos;

  mGasNag = (maxInjPerNag - minInjPerNag) / (maxNagVolGas - minNagVolGas);
  yGasNag = mGasNag * (GAS_Pressure - minNagVolGas) + minInjPerNag;

  if(GAS_Pressure >= 0.00 && GAS_Pressure < 2.50)
  {
    gasInjTime = injTime + (injTime * yGasPos);
  }
  else if(GAS_Pressure >= 2.50 && GAS_Pressure <= 5.00)
  {
    gasInjTime = injTime - (injTime * yGasNag);
  }

  //--------------------Pulse Generation-----------------------//

  if((kInjTime > 0) && ((millis() - kInjTime) >= injTime))
  {
    kInjTime = 0;
    digitalWrite(kPinInj, 0);
  }                                  
}

void countRPM()
{
  RPMpulses++;

  digitalWrite(kPinInj, RPMpulses & 1); // Set or clear kPinInj
  if(RPMpulses & 1) 
  kInjTime = millis();  // Store alternate times
}

int getRPM()
{
  Final_RPM = ((RPMpulses * (60000UL / 2) * (engineCycles/engineCylinders)) / refreshInterval);
  RPM0 = RPMpulses &= 1;
  RPMpulses - RPM0;
  return Final_RPM;
}

I'm also trying to capture response as char array but not able to capture it. Please guide me about that otherwise this one string may not cause any heap fragmentation. I am so glad if someone helps me out for this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.