I understand how to use millis as a replacement for delay except for one part; in for loops. Specifically, I have a chaser with a shift register using hardware SPI but I need to be able to set the delay based on a potentiometer attached to an analog pin and not have to wait the 500 milliseconds before it changes that delay. I've only used millis to blink leds or to start a particular function at certain intervals but nothing like this. I've tried searching but can't seem to find anything helpful. Hoping posting here might be more fruitful.
Please post the program here to avoid the need to download it.
In general, you will need to remove the for loop and use the the loop() function to do what you want, perhaps updating a variable at intervals and use that variable as an index to an array (just guessing). Using loop() means that you can read the pot and change the interval each time through loop() if necessary.
Once you have asked for a delay , you can't really stop in between and change that value . So, my suggestion would be the above link.
But they use delay(20) !!
They should have coded something like this for delaying:
void checking_delay (unsigned long ms)
{
unsigned long t = millis () ;
while (millis () - t < ms)
check_all_threads () ;
}
That approach has to be used carefully as a "thread" must never directly of indirectly call check() on
itself (that causes infinite recursion). So the above function can only be used at top level, not
by any of the threads.
Its probably easier to use the standard idiom of loop() checking everything, and the rest of the
code being loop-free (ie state-machines).
Yeah, that was a thrown together / copied/pasted code. What I ended up doing is put the analogRead part inside the toggle function. Not perfect, and I'm still working on a millis version...
#include <SPI.h>
#define NUM_CHIPS 3
#define MAX_delay 250
const byte LATCH = 10;
byte data[NUM_CHIPS];
unsigned int myDelay = 500;
void setup()
{
SPI.begin();
pinMode(LATCH, OUTPUT);
for (int i = 0; i < NUM_CHIPS; i++)
data[i] = 0b00000000;
}
void loop()
{
// left to right turn on
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < NUM_CHIPS * 8; j++)
{
toggle(j);
delay(myDelay);
}
}
// right to left
for (int i = 0; i < 2; i++)
{
for (int j = (NUM_CHIPS * 8) - 1; j > -1; j--)
{
toggle(j);
delay(myDelay);
}
}
}
void toggle(int input)
{
int chip, pin;
myDelay = map(analogRead(A0), 0, 1023, 0, MAX_delay);
// TODO make the down to just a couple of lines
if (input < 8)
{
chip = NUM_CHIPS - 1;
pin = input;
}
else if (input > 7 && input < 16)
{
chip = NUM_CHIPS - 2;
pin = input - 8;
}
else if (input > 15 && input < 24)
{
chip = NUM_CHIPS - 3;
pin = input - 16;
}
else if (input > 23 && input < 32)
{
chip = NUM_CHIPS - 4;
pin = input - 24;
}
bitWrite(data[chip], pin, !bitRead(data[chip], pin));
digitalWrite(LATCH, LOW);
for (int i = 0; i < NUM_CHIPS; i++)
SPI.transfer(data[i]);
digitalWrite(LATCH, HIGH);
}
Ok, I finally got exactly what I was wanting; no delays at all. Thanks to everyone who helped out.
What it does:
It's a simple led chaser a la Knight Rider / Cylon eyes in that one led turns on up to the last and then they turn off from start to end and then repeats in the opposite direction.
I have 3 shift registers (74HC595) connected together with 24 leds. The registers are connected to the Arduino's SPI pins (clock 13, data 11, cs/latch 10) and I have a 10K pot attached to A0.
I wrote the program so any number of chips can be used, well, up to 4 but that can be changed in the if part of the toggle function.
I've been programming since 1995 but just recently got into the whole raspberry pi / odroid / micro-controller realm.
Again, thanks for all the help.
#include <SPI.h>
#define NUM_CHIPS 3
#define MAX_DELAY 250
const byte LATCH = 10;
byte data[NUM_CHIPS];
unsigned int myDelay = 500;
unsigned int prevMillis = 0;
boolean sequence1Done = false;
boolean sequence2Done = false;
int ctr_a = 0;
int ctr_b = 0;
boolean goingRight = true;
void setup()
{
SPI.begin();
pinMode(LATCH, OUTPUT);
for (int i = 0; i < NUM_CHIPS; i++)
data[i] = 0b00000000;
}
void loop()
{
unsigned int curMillis = millis();
if (sequence1Done == false)
{
if (sequence2Done == true) // end first "for" loop
{
sequence2Done = false;
if (++ctr_b > 1)
sequence1Done = true;
}
else if ((curMillis - prevMillis >= myDelay) && sequence2Done == false)
{
prevMillis += myDelay;
if (goingRight)
{
if (ctr_a > NUM_CHIPS * 8)
{
// end second "for" loop
sequence2Done = true;
ctr_a = 0;
}
if (sequence2Done == false)
toggle(ctr_a++);
}
else
{
if (--ctr_a < -2)
{
// end second "for" loop
sequence2Done = true;
ctr_a = (NUM_CHIPS * 8);
}
if (sequence2Done == false)
toggle(ctr_a);
}
}
}
else
{
if (goingRight == true)
{
goingRight = false;
ctr_a = (NUM_CHIPS * 8);
}
else
{
goingRight = true;
ctr_a = 0;
}
sequence1Done = false;
ctr_b = 0;
}
}
void toggle(int input)
{
int chip, pin;
myDelay = map(analogRead(A0), 0, 1023, 0, MAX_DELAY);
// TODO make the down to just a couple of lines
if (input < 8)
{
chip = NUM_CHIPS - 1;
pin = input;
}
else if (input > 7 && input < 16)
{
chip = NUM_CHIPS - 2;
pin = input - 8;
}
else if (input > 15 && input < 24)
{
chip = NUM_CHIPS - 3;
pin = input - 16;
}
else if (input > 23 && input < 32)
{
chip = NUM_CHIPS - 4;
pin = input - 24;
}
bitWrite(data[chip], pin, !bitRead(data[chip], pin));
digitalWrite(LATCH, LOW);
for (int i = 0; i < NUM_CHIPS; i++)
SPI.transfer(data[i]);
digitalWrite(LATCH, HIGH);
}
Thanks for the unsigned long; I'm gradually converting all of my code to get rid of all delays and am still a bit (pun intended) new to looping / micro-controller programming so I've never ran out of numbers before now.
As for the SPI vs shiftOut, I haven't found anything stating one is better than the other; although one would expect that as SPI is hardware and shiftOut is software, the hardware would be faster albeit with shiftOut you get to pick which 3 pins to use.