Capturing data at timed intervals without a delay.

Hi all,

I have a program which constantly polls the serial port waiting for data which gets sent every second from a windows application.

it then buffers the data from the serial into block of 3 characters.

First recorded value is value1, i then want to record it again as value2, 3 mins later, without stopping the rest of the program working.

Here's my code, without any timers.

void loop()
{
    GetAz();
} 
  
 
 void GetAz(){

   int x = 0;
     while (x < 4){
       x++;

 
  if( Serial.available())
  {
    char ch = Serial.read();
    if(index < MAX_LEN && ch != 13) // 13 is ascii value of carriage return
    {
      strValue[index++] = ch; // add the ASCII character to the string;
    }
    else
    {
      // here when buffer full or on the first non digit
      strValue[index] = 0;        // terminate the string with a 0
        //int value = atof(strValue);  // use atof to convert the string to a float
      index = 0;      // reset the index for the next string
  
lcd.setCursor(10,3);
      Serial.println(strValue);
        lcd.print(strValue);
       }  
     }
   }
int value1 = atoi(strValue);
 }

Thanks,
Rich.

I don't see a question.
Three minutes is 180 000 milliseconds, so don't use an "int".
Just keep looking at "millis" until you delay has elapsed.

In GetAz, you have a while loop. The while loop terminates when x gets to be 4. What is the purpose of x?

GetAz returns after 4 checks to see whether there was data available to be read, regardless of whether or not there was data.

At most you will get 4 bytes in strValue, which you show on the LCD, as you are building the not-properly-NULL-terminated string.

At the end of GetAz, you store the integer value of the possibly-not-NULL-terminated string in a local variable that immediately goes out of scope, and is, therefore, lost.

There may be more problems, but those occur to me right off the bat.

So, what is it you are trying to accomplish? You aren't doing anything with time, so the time-related aspect of your initial question do not seem to have an answer.

If you are trying to create an array that holds no more than 3 integers, and each call to GetAz puts the value it gets into one of the positions in that array, then GetAz needs to do some of the work (getting the value), and loop needs to do some (putting it in the array in the right place.

Hi paul,

I'm trying trying to read 3 characters from the serial port and then store the array of 3 characters in a value (e.g. value1)

I then want to wait around 3 minutes, and do the same again but storing the 3 characters to a different value (e.g. value2)

But during the 3 between writing the value1 and value2, i dont want to pause the arduino program.

Use the millis() function to get the time when there is serial data available. Store the result in a global variable called previousMillis. Collect the serial data as you are doing now, in the if block. (I don't know what the while block is doing.)

Change GetAz to return an int. Store that int, in loop.

Also in loop, check to see if millis() - previousMillis is greater than the desired delay. If it is, call GetAz again, and store the results in another variable (or the next position in an array).

Hi Paul,

I'll take a look at the millis() function when i get home tonight. I've already removed the "while" statement as i realized that the serial termination was controlled by the carrige return.

to store an int in the GetAz loop i was thinking of using
int value = atoi(strValue); which should do the trick.

I'll probably be back later for some help on the millis fucntion.

Rich.

There is a example program in the digital section of the Arduino IDE:

/* Blink without Delay
 
 Turns on and off a light emitting diode(LED) connected to a digital  
 pin, without using the delay() function.  This means that other code
 can run at the same time without being interrupted by the LED code.
 
  The circuit:
 * LED attached from pin 13 to ground.
 * Note: on most Arduinos, there is already an LED on the board
 that's attached to pin 13, so no hardware is needed for this example.
 
 
 created 2005
 by David A. Mellis
 modified 17 Jun 2009
 by Tom Igoe
 
 http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
 */

// constants won't change. Used here to 
// set pin numbers:
const int ledPin =  13;      // the number of the LED pin

// Variables will change:
int ledState = LOW;             // ledState used to set the LED
long previousMillis = 0;        // will store last time LED was updated

// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval = 1000;           // interval at which to blink (milliseconds)

void setup() {
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT);      
}

void loop()
{
  // here is where you'd put code that needs to be running all the time.

  // check to see if it's time to blink the LED; that is, is the difference
  // between the current time and last time we blinked the LED bigger than
  // the interval at which we want to blink the LED.
  if (millis() - previousMillis > interval) {
    // save the last time you blinked the LED 
    previousMillis = millis();   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;
      
    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}

Lefty

Ribuck,

Have a look at this:
http://www.arduino.cc/playground/Code/Metro

This is a quite interesting library that helps you to make delays without stopping the processor. It just processes millis(). It's very simple to use it just looking at the examples.

Regards,

/me

Hi guys having a few problems,

Paul you mentioned storing the serial data into as an int value.

Change GetAz to return an int. Store that int, in loop.

I'm having some problems storing the array of 3 characters as a Int value. I thought just doing some sort of conversion might work.

 void GetAz(){ 
  if( Serial.available())
  {
    char ch = Serial.read();
    if(index < MAX_LEN && ch != 13) // 13 is ascii value of carriage return
    {
      strValue[index++] = ch; // add the ASCII character to the string;
    }
    else
    {
      // here when buffer full or on the first non digit
      strValue[index] = 0;        // terminate the string with a 0
        int value = atoi(strValue);  // use atoi to convert the string to int
      index = 0;      // reset the index for the next string
  
        lcd.setCursor(10,3);
      Serial.println(strValue);
        lcd.print(strValue);
        
    }  
  }
 }

I figure i could just use this line of code to do the conversion but it just hangs up the whole process.

int value = atoi(strValue);

Anyone got any other idea's of how to convert an array to an int value ?

It's hard to say what the problem is without any idea what data you are reading from the serial port. Show us the serial monitor data, and we can make better recommendations.

One thing I see, though, is that you are not NULL terminating the string. atoi is looking for the NULL, to know where to stop reading the array of characters.

Hi paul,

the serial data is simply 3 numbers sent to the serial port from a windows application every second.

e.g. 356

from my code if i just do a lcd.print(strValue); i see the correct value being displayed and updated.

Sorry i forgot to post thati have the follow defined globally at the beginning of my code.

const int MAX_LEN = 3; // the max digits
char  strValue[MAX_LEN + 1]; // add one for the terminating null

So i thought that along with this line in my function, would terminate properly.

 if(index < MAX_LEN && ch != 13) // 13 is ascii value of carriage return

The whole code is as follows

const int MAX_LEN = 3; // the max digits in the number plus decimal point
char  strValue[MAX_LEN + 1]; // add one for the terminating null

int index = 0;

void loop()
{
  millis();
    GetAz();
    ButtonPress();
    llegirPos();
    delay(100);
} 
  
 
 void GetAz(){ 
  if( Serial.available())
  {
    char ch = Serial.read();
    if(index < MAX_LEN && ch != 13) // 13 is ascii value of carriage return
    {
      strValue[index++] = ch; // add the ASCII character to the string;
    }
    else
    {
      // here when buffer full or on the first non digit
      strValue[index] = 0;        // terminate the string with a 0
        int value = atoi(strValue);  // use atof to convert the string to a float
      index = 0;      // reset the index for the next string
  
        lcd.setCursor(10,3);
      Serial.println(strValue);
        lcd.print(strValue);

        
    }  
  }
 }

Rich

Upon further review of the code, I see this:

strValue[index] = 0;

Typically, that would be done like this:

strValue[index] = '\0';

The results are supposed to be the same.

Does the same string get printed to the serial monitor window?

Hi paul,

yes the serial.print function to StrValue works perfectly. I'll try changing to your suggestion with the \0 and see if that makes any difference.

Rich.

hi Paul,

no joy.

If i use the code below it's fine,

Serial.print(strValue);

As soon as i do a conversion with code below it just lock the whole process when i try a a serial print or lcd print.

int value = atoi(strValue);

e.g. if i do the following it just locks up

Serial.print(value);    or    lcd.print(value);

Rich.

The Serial.print(value) statement needs a qualifier:

Serial.print(value, DEC).

Otherwise, it tries to display the ascii character who's value is stored in value. If value is 356, there is no corresponding ascii value.

Hi paul,

Serial.print(value); works fine for me.

Anyway, getting back to the problem at hand, how to convert the array to an int value without locking up arduino.

Maybe i should create a new post of as we have gone way off topic from my original post of timers.

Hi all,

Managed to get the timer function working properly, so i'm going to create a new post to try and solve the problem converting an array to an int.

Rich.