Go Down

Topic: I2C accelerometer with delay using millis(). (Read 1 time) previous topic - next topic

TERMINAL

Mar 30, 2015, 12:24 am Last Edit: Mar 30, 2015, 12:29 am by TERMINAL
Ok, so I connected the GY-521 accelerometer/gyro to my arduino and it works fine by it self, but ofcourse, since it works via I2C putting any kind of delay in the code would result in a FIFO Overflow so i tried making a function that would substitute the delay and read the accelerometer.

I made this

unsigned long mill, mill2;

void loop() {
//do something
mill = millis();
mill2 = millis();
while(mill2 - mill < 1000){
lACC();
mill2 = millis();
}
// do something else
mill = millis();
mill2 = millis();
while(mill2 - mill < 1000){
lACC();
mill2 = millis();
}

note: lACC(); Is a function that reads the port and updates values from the accelerometer

But this doesn't work.
I end up with semi-random delays that don't really work and the code stops fully after 4 or so loops.

Any ideas?
Thanks

Peter

Martin-X

Can't see any delays in that code, it just continually calls IACC() (whatever that is) for 1000ms then continually calls IACC() (whatever that is) for another 1000ms, then repeats.

The full code would help (in code tags) along with an idea of what you want to achieve.

TERMINAL

Putting in the full code would be massive since the accelerometer part isn't mine. I got it online, and it works.
anyways, what i want to do is put a wanted delay between two actions.
But if i literally put in delay(1000); the MPU6050 chip sending information to the arduino would overflow because data isn't being read in those 1000ms. I want to avoid that, so i'm trying to read the chip the whole time while other part of the program wait for the "delay" to be done.
That should work, as you described it, but it doesn't.

Peter_n

#3
Mar 30, 2015, 01:43 am Last Edit: Mar 30, 2015, 01:44 am by Peter_n
Could you give a link to that code online ?

Should IACC() be called as often as possible ? and you want other code to run once a second ? Which two actions do you mean ?
The code is probably a derivate from the I2Cdevlib.

This is an example of millis()
Code: [Select]

unsigned long prevMillis;

void setup()
{
  ...
  // At the end of setup(), set prevMillis
  prevMillis = millis();
}

void loop()
{
  // Do this part as often as possible.
  // Check for Serial.available() and so on.
  ...

  // Do this part once a second
  if( millis() - prevMillis >= 1000)
  {
    prevMillis += 1000;
    Serial.print(".");
  }
}

TERMINAL

For the life of me, i can't find the exact link, but it is a I2CDEV Implementation.
I don't want the same action to be repeated.
I'm basically building a robot(on wheels) and what i want to do is to be able to make it for example turn left for one second but while avoiding the i2c overflow. But the thing is i don't want it to just turn left i actually want to program it however i want.
Basically, in short, i'm looking to make a function that would replace the delay command so that it reads the sensor while waiting. I don't know hot to explain it better.

lACC(); needs to be called as much as possible otherwise it will result in an overflow.

aarg

lACC(); needs to be called as much as possible otherwise it will result in an overflow.
That would be done in the part of what Peter posted above that says
"// Do this part as often as possible."
  ... with a transistor and a large sum of money to spend ...
Please don't PM me with technical questions. Post them in the forum.

Peter_n

You want to turn something on, and it should turn off after some delay ?

That needs a flag, or a state machine.
This is one way to do it: you turn it on, set a flag, and timestamp the moment.
The timestamp is : prevMillis = millis();
In the loop() check for that flag, and if it has been set check the : if( millis() - prevMillis >= some_delay)
If the millis() is finally at that moment, reset the flag.

Don't create a variable for the time in the future. That would introduce a rollover problem with millis(). By timestamping the current moment, and checking it like that, it will always work.

aarg

Don't create a variable for the time in the future. That would introduce a rollover problem with millis(). By timestamping the current moment, and checking it like that, it will always work.
Really? I'm puzzled. If millis() is about to roll over, wouldn't adding an unsigned integer to the value of a unsigned integer copy of millis(), still produce a timestamp that millis() will attain in the correct time? I thought all the time calculations would be correct as long as all math is done in unsigned arithmetic.
  ... with a transistor and a large sum of money to spend ...
Please don't PM me with technical questions. Post them in the forum.

TERMINAL

I do see what you're aiming at, but it wouldn't really work for the code i'm writing..
I have functions like this

Code: [Select]
int FD(int d)
{
  m.setM0Speed(mxS);
  m.setM1Speed(mxS);
if(d != 0){delay(d); ST(0);}
  else{delay(d);}
}

int ST(int d)
{
  m.setM0Speed(0);
  m.setM1Speed(0);
  if(d != 0){delay(d); ST(0);}
  else{delay(d);}
}


So that for example, FD(1000); would move the robot forward one second and then stop, and FD(0); would make it move forward until further change.

What i want to do is after i tell the motors to start for the lACC(); to be called while the motors move forward until one second (or whatever time) has passed, and then go to the next function/command in void loop. I'm not able to dedicate the whole code to that one task.

Martin-X

A quick read of This shows that it is interrupt driven.  You need to implement an interrupt handler to manage the stream of data from this device.

TERMINAL

So i would be able to stop the data when i want to?
If so it would solve all my problems.
I would just pause the data before any delay and then start it afterwards.

aarg

The general approach to imbedding a delay using millis() in a function, would be to leave flags and time stamps for the devices in loop(), and adjust timestamps, set/reset the flags inside the function.
  ... with a transistor and a large sum of money to spend ...
Please don't PM me with technical questions. Post them in the forum.

TERMINAL


aarg

#13
Mar 30, 2015, 03:14 am Last Edit: Mar 30, 2015, 03:46 am by aarg
Can you post an example?

I've never done it.
Okay, now I have. Realize that I have a lot of distractions in front of me today. You have to polish it up.
Code: [Select]

/* Blink without Delay
modified to show how time could be used in a function */

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

// Variables will change :
int ledState = LOW;             // ledState used to set the LED
bool ledStatus = false;             // led active?

// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long ledMillis = 0;        // will store last time LED was updated

unsigned long interval = 0;           // interval at which to blink (milliseconds)
unsigned long currentMillis;

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

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

  currentMillis = millis();

  if ((currentMillis - ledMillis >= interval) && ledStatus == true) {
    ledState = LOW;
    // set the LED off:
    digitalWrite(ledPin, ledState);
    ledStatus = false;
  }
}

void ledPulse (unsigned long pulseTime)
{
  ledState = HIGH;
  digitalWrite(ledPin, ledState);
  ledStatus = true;
  interval = pulseTime;
  ledMillis = millis();
}
  ... with a transistor and a large sum of money to spend ...
Please don't PM me with technical questions. Post them in the forum.

Peter_n

TERMINAL, if you want to do another thing after the delay, you might need a variable that indicates the 'state'.
This is an example : http://forum.arduino.cc/index.php?topic=290915.msg2035290#msg2035290
Inside the big switch/case, the millis() is used just once. That is because that example has only one delay.
Do you like that code ? does it make any sense ?

aarg, to avoid the rollover problem, it is necessary to use "unsigned long" and timestamp the current moment. That way the "millis() - prevMillis" is always a positive number and that prevents the rollover problem.
When for example the time in the future is remembered, millis() could be higher or lower than that value, and that is not possible with unsigned long.
Here is an example that shows what it is like to use unsigned variables that rollover : http://playground.arduino.cc/Code/TimingRollover#arithmetic

Go Up