Go Down

Topic: Need help with loop time/interrupt programming (Read 2337 times) previous topic - next topic

_Leo_

Everyone,

I'm in need of your programming expertize.

As basis I'm using a UNO R3 with 16MHz, eeprom 512 and a MS5611 barometric pressure sensor.
At a later date I will be using a 328 with 8 MHz (3.3v) and my ultimate goal is to use the Attiny85.

Essentially I have everything working however due to my lack of knowledge with Timer/Interrupt programming I am unable to find a good solution in putting everything together.

Here is what I want to do:

The program is for a model rocket that records the altitude to eeprom and sets off 2 deployments.

-> Get pressure from sensor and save in array (50 / sec)
-> Calculate average pressure from array (10 / sec)
-> Calculate the altitude (10 / sec)
-> Write altitude to eeprom ( 10 / sec)
-> Check to see if lift-off has occurred (10 /sec)
-> Check if max altitude has been reached -> deploy parachute (10 / sec)
-> Check if preset altitude has been reached -> deploy parachute (10 / sec)
-> Check if touchdown occurred -> exit loop to read out the altitude via led flash

Now my first questions are:

What would be the best way to go about this?

Do I use a timer interrupt and if so how should I implement it?

Thanks!
Leo

Project "ALTDuino" - A homemade altimeter for model rockets.
http://www.altduino.de

AWOL

Quote
Do I use a timer interrupt

I don't really see any reason for this, based on the low sample rates.
YMMV.

robtillaart

Quote
What would be the best way to go about this?


you should read the blink without delay example that should help you

a quick dump of your list into code with functions that need to be elaborated.
Code: [Select]


unsigned long T1 = 20;
unsigned long T2 = 100;
long p = 0;

void loop()
{
 // 50 / sec items
 if (millis() - T1 > lastPressureTime)
 {
   lastPressureTime += T1;
   p += readPressure();
 }  

 // 10/sec items
 if (millis() - T2 > lastAverageTime)
 {
   lastAverageTime+= T1;
   pressure = p/5;
   p = 0; // reset

   altitude = calcAltitude(pressure);
   writeEEprom(altitude);  // wears out if written too often ... consider an external eeprom that can be replaced)

   flag = checkLiftOffOccured();
   if ((altitude < highest && parachuteClosed() )  || (altitude >= presetAltitude))
   {
      doParachute();
   }
   highest = max(altitude, highest);
   if (touchDown())
   {
      exit();
   }
 }


this is incomplete code but it gives you an idea how it is done. The functions must be written still or can be replaced by the actual code .

Succes!
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

_Leo_

Thanks AWOL. I'll try it without using timer interrupts.


Thank you Rob.

I am using an external eeprom for that very reason.

I had the program written in a manner that you have posted but was not happy with it.

I'll give it another try and report here with my concerns, if any.

Leo

Project "ALTDuino" - A homemade altimeter for model rockets.
http://www.altduino.de

robtillaart

Please post your unhappy code so we can see if we can fix it  (we is the forum)
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

_Leo_

Rob,

I thought I'd give your millis loop example a try:

Code: [Select]
unsigned long T1;
unsigned long lastPressureTime;
int loopCounter;

void setup()
{
  Serial.begin(115200);

  T1 = 1000;
  lastPressureTime = 0;
  loopCounter = 0;
}

void loop()
{
  if (millis() - T1 > lastPressureTime)
  {
    lastPressureTime += T1;

    Serial.println(loopCounter); // print every second
    loopCounter++;
  } 
}


It doesn't seem to be working correctly.
Leo

Project "ALTDuino" - A homemade altimeter for model rockets.
http://www.altduino.de

AWOL

Quote
It doesn't seem to be working correctly

Grrrr.

_Leo_

Leo

Project "ALTDuino" - A homemade altimeter for model rockets.
http://www.altduino.de

_Leo_

Rob,

I took another look at your code and made slight modifications.

Now it is working correctly.

Code: [Select]
unsigned long T1;
unsigned long lastPressureTime;
int loopCounter;

void setup()
{
  Serial.begin(115200);

  T1 = 1000;
  lastPressureTime = T1;
  loopCounter = 0;
}

void loop()
{
  if (millis() + T1 >= lastPressureTime)
  {
    lastPressureTime += T1;

    Serial.println(loopCounter); // print every second
    loopCounter++;
  } 
}
Leo

Project "ALTDuino" - A homemade altimeter for model rockets.
http://www.altduino.de

robtillaart


Sorry to say but you should not use + addition with millis() compares , it is explained here - http://www.faludi.com/2007/12/18/arduino-millis-rollover-handling/ -


a retry which includes the value of millis(), give it a try

Code: [Select]

unsigned long T1=1000;
unsigned long T2=250;
unsigned long lastPressureTime=0;
unsigned long lastCalcTime=0;
int counter1=0;
int counter2=0;

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  unsinged long now = millis();
  if (now - T1 >= lastPressureTime)
  {
    lastPressureTime += T1;

    Serial.print(now);
    Serial.print("\t ");
    Serial.println(counter1); // print every second
    counter1++;
  } 
  if (now - T2 >= lastCalcTime)
  {
    lastCalcTime += T2;

    Serial.print("\t\t ");
    Serial.print(now);
    Serial.print("\t ");
    Serial.println(counter2); // 4x /second
    counter2++;
  } 
}
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

_Leo_

Under normal circumstances rollover occurs after 50 days.
My hardware would be used for no more than 1 hour at the max.

Sorry Rob. Your second example doesn't work either.
Leo

Project "ALTDuino" - A homemade altimeter for model rockets.
http://www.altduino.de

_Leo_

Ok, I was able to find an easy fix with the rollover issue using the working code I posted earlier:

Code: [Select]
unsigned long T1, T2;
unsigned long lastPressureTime, lastPrintTime;

int loopCounter;

void setup()
{
  Serial.begin(115200);

  T1 = 20;
  T2 = 1000;
  lastPressureTime = 0;
  lastPrintTime    = 0;
  loopCounter      = 0;
}

void loop()
{
  if (millis() >= lastPressureTime + T1) // loop 50 times per second
  {
    lastPressureTime += T1;

    loopCounter++;
  } 

  if (millis() >= lastPrintTime + T2) // print every second
  {
    lastPrintTime += T2;

    Serial.println(loopCounter);
    loopCounter = 0;
  } 
}


The output for every second I get is this:

50
49
51
50
49
51
50
49
50
51
50
49
51
50
49
51
50

It should output a constant 50 but it doesn't. Any idea why that is?


Leo

Project "ALTDuino" - A homemade altimeter for model rockets.
http://www.altduino.de

robtillaart

you still are using the addition :(

You have two different calls to millis() and expect they return an identical value.

try this variation
Code: [Select]

unsigned long T1, T2;
unsigned long lastPressureTime, lastPrintTime;

int loopCounter;

void setup()
{
  Serial.begin(115200);

  T1 = 20;
  T2 = 1000;
  lastPressureTime = 0;
  lastPrintTime    = 0;
  loopCounter      = 0;
}

void loop()
{
  unsigned long now = millis();
  if (now >= lastPressureTime + T1) // loop 50 times per second
  {
    lastPressureTime += T1;
    loopCounter++;
  } 

  if (now >= lastPrintTime + T2) // print every second
  {
    lastPrintTime += T2;

    Serial.println(loopCounter);
    loopCounter = 0;
  } 
}
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

_Leo_

You are correct. The 2 millis were the issue. With only one millis I'm getting a constant 50 printout now.
Leo

Project "ALTDuino" - A homemade altimeter for model rockets.
http://www.altduino.de

_Leo_

I have corrected the code to be overflow conform:

Code: [Select]
unsigned long T1, T2;
unsigned long lastPressureTime, lastPrintTime;

int loopCounter;

void setup()
{
  Serial.begin(115200);

  T1 = 20;   
  T2 = 1000;
  lastPressureTime = 0;
  lastPrintTime    = 0;
  loopCounter      = 0;
}

void loop()
{
  unsigned long now = millis();
 
  if (now - lastPressureTime >= T1) // loop 50 times per second
  {
    lastPressureTime = now;

    loopCounter++;
  } 

  if (now - lastPrintTime >= T2) // print every second
  {
    lastPrintTime = now;

    Serial.println(loopCounter);
    loopCounter = 0;
  } 
}
Leo

Project "ALTDuino" - A homemade altimeter for model rockets.
http://www.altduino.de

Go Up