millis() way off

hey,

i've got a program that uses millis(), but it seems to be way off. it seems to cover 1000ms in about 20 seconds. is this normal at all? i guess i can adjust things to go the speed i want, but it makes me a little nervous for things to be so off.

matt

That sounds really strange. Maybe interrupts are somehow being disabled for large periods of time? Can you post your code?

sure. it’s kind of a mess, but basically there are some buttons connected with a shift register and some LEDs controlled with another shift register, and pressing buttons makes the LEDs light up in certain patterns.

/* SHIFT REGISTER STUFF

*/
int led_SER = 2;
int led_RCK = 3;
int led_SCK = 4;

//define where your pins are
int btn_latch = 8;
int btn_data = 9;
int btn_clock = 7;

int led_count = 4;
boolean on[4];
boolean on_next[4];
boolean visited[4];
boolean visited_next[4];
boolean network[4][4] = {{false, true, false, true},
{true, false, true, false},
{false, true, false, true},
{true, false, true, false}};

//define an array that corresponds to values for each
//of the shift register’s pins
boolean a_button_is_pressed;
boolean btn_DOWN[8];

// uuumm… these aren’t milliseconds.
long millis_betweenUpdates = 10; // could possibly be changed with a knob. otherwise, there’s no need for the variable (if memory is an issue), since it’s only called once.
long millis_sinceUpdate = 0;
long millis_prevFrame;

void setup(){
pinMode(led_SER, OUTPUT);
pinMode(led_SCK, OUTPUT);
pinMode(led_RCK, OUTPUT);

//define pin modes
pinMode(btn_latch, OUTPUT);
pinMode(btn_clock, OUTPUT);
pinMode(btn_data, INPUT);

Serial.begin(9600);

digitalWrite(led_RCK, LOW);
digitalWrite(btn_latch, 0);

Serial.println(“ready”);
}

void loop(){
long millis_curr = millis();
millis_sinceUpdate += millis_curr - millis_prevFrame;
if(millis_prevFrame > millis_curr) millis_sinceUpdate = 0; // to account for millis() rolling over to zero after 9 hours.
if(millis_sinceUpdate > millis_betweenUpdates){
millis_sinceUpdate = 0;
updateNet();
}
millis_prevFrame = millis();

//Pulse the latch pin:
//set it to 1 to collect parallel data
pulse_btn_latch();
shiftIn();

update_leds();

if(a_button_is_pressed){
millis_sinceUpdate = 0;

int i = 0;
if(allHaveBeenVisited()){
millis_sinceUpdate = 0;

for(i = 0; i < led_count; i++){
on = false;
_ visited = false;_
on_next = false;
visited_next = false;
* }*
* }*

* for(i = 0; i < led_count; i++){
if(btn_DOWN){
_ on = true;
visited = true;
on_next = true;
visited_next = true;
}
}*_

* }*

}
void all_leds(int high_or_low){

* digitalWrite(led_RCK, LOW);
for( int x = 0; x < led_count; x ++){
_ // set SER*
* digitalWrite(led_SER, high_or_low);
pulse_led_SCK();*

* }_
pulse_led_RCK();
_}_
void update_leds(){
digitalWrite(led_RCK, LOW);
for( int x = 0; x < led_count; x ++){
_ if(on){_
digitalWrite(led_SER, HIGH);
_ } else {_
digitalWrite(led_SER, LOW);
_ }_
pulse_led_SCK();
_ }_
pulse_led_RCK();
_}
void pulse_led_SCK(){
// pulse SCK (it pushes the SER value down the line)_

digitalWrite(led_SCK, HIGH);
digitalWrite(led_SCK, LOW);
_}
void pulse_led_RCK(){
// pulse SCK (it pushes the SER value down the line)_

digitalWrite(led_RCK, HIGH);
_ delayMicroseconds(20);_
digitalWrite(led_RCK, LOW);
_}
//
// button inputs

//

void shiftIn() {
int i;
int temp = 0;_
a_button_is_pressed = false;
_ for (i=7; i>=0; i–)
{_

digitalWrite(btn_clock, 0);
_ delayMicroseconds(0.2);_
temp = digitalRead(btn_data);
_ if (temp) {_
btn_DOWN = true;
a_button_is_pressed = true;
_ }
else {
btn_DOWN = false;
}_

digitalWrite(btn_clock, 1);
_ }
}_

void pulse_btn_latch(){
digitalWrite(btn_latch,HIGH);
_ delayMicroseconds(20);_
digitalWrite(btn_latch,LOW);
_}
//
// network management

//
*
void updateNet(){
//… check network for next visited links_

* for(int u = 0 ; u < led_count; u++){
_ if(!visited){
// see if it should be updated
// check the network for linked members_

for(int c = 0; c < led_count; c++){
_ //if they are connected, and the one to check is on, turn this one on
if(network
```c_

[u][u] && on[c]){
         on_next[u] = true;
         visited_next[u] = true;
       }
     }
   }
 }
 
 // turn the current ones off
 for(int i = 0; i < led_count; i++){
   if(on[i]) on_next[i] = false;
 }
 
 // time step
 for(int i = 0; i < led_count; i++){
   on[i] = on_next[i];
   visited[i] = visited_next[i];
 }
 for(int i = 0; i < led_count; i++){
   on[i] = on_next[i];
   visited[i] = visited_next[i];
 }
 
}

boolean allHaveBeenVisited(){
 boolean toReturn = true;
 for(int i = 0; i < led_count; i++){
   if(!visited[i]){
     toReturn = false;
     break;
   }
 }
 return toReturn;
}[/u]

_```*_

Yea, I think the issue is probably with the delayMicroseconds() calls. Currently, that function disables interrupts. Do you need those delays in there for the hardware you're talking to? You could just go into the Arduino source (the lib/targets/arduino sub-directory of your Arduino application directory) and remove the cli() line from the delayMicroseconds() function in wiring.c. I think that cli() call may get removed in the next version because of issues like this.

Do you need those delays in there for the hardware you're talking to?

Honestly, I don't know. Those delayMicrosecond calls were from the code in this tutorial: http://www.arduino.cc/en/Tutorial/ShiftIn

Specifically, this code: http://www.arduino.cc/en/Tutorial/ShftIn12

I just tried it without the delays, and it works fine and the millis() measurements seem accurate. I think I'd rather do without them, because the program responds quicker when you press a button. I just wonder if there was some reason for including them in the tutorial.

On the other hand, the milliseconds don't actually have to be accurate, as long as their consistent and they won't cause problems with a project that is just left out running all the time. From what you say, this isn't the kind of bug that will cause real problems if I leave the delays in there. Am I right?

Hmm, I'd just leave out the delayMicroseconds(). Things might work with them in, because the millis() should be reasonably consistent, but it's probably better without, if your hardware still works.