I would appreciate it greatly if you could take a look at my attempt to modify one of the tutorials. What I am trying to achieve is a quick blink on HIGH and a longer time on LOW. And using an analogue input change which LEDs are blinking. The code below works but as soon as the look up array (hitz) is modified the timings of all the blinks work independently of each other which is not the desired effect: I would like them to blink at the same time. I've tried various ways of trying to homogenise the previousMillis variable (which I believe is the problem but possibly not) for all 4 elements in the array but to no avail.
I must say at this point that I am not a coder so may well have missed something blindingly obvious to those more experienced but any help/ pointing in the right direction would be great:
long previousMillis[4] = {0,0,0,0}; // will store last time LED was updated
long interval[4] = {1000,1000,1000,1000}; // interval at which to blink (milliseconds)
int value[4];
int ledPin[4] = {3,4,5,9};
int average = 0;
boolean hitz[4] = {LOW,LOW,LOW,LOW};
void changeUp(){
if((average >= 100) && (average <= 400)){
hitz[0] = HIGH;
}
else{
hitz[0] = LOW;
}
if((average >= 513) && (average <= 700)){
hitz[1] = HIGH;
}
else {hitz[1] = LOW;
}
if((average >= 650) && (average<=850)){
hitz[2] = HIGH;
}
else{
hitz[2] = LOW;
}
if((average >= 800) && (average <= 1000)){
hitz[3] = HIGH;
}
else{
hitz[3] = LOW;
}
}
void setup(){
Serial.begin(9600);
for(int i=0;i<4;i++)
pinMode(ledPin[i], OUTPUT);
for(int i=0;i<4;i++)
digitalWrite(ledPin[i],HIGH);
}
void loop()
{
average = analogRead(0);
//Serial.println(average,DEC);
changeUp();
// 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.
for(int i=0;i<4;i++){
if (millis() - previousMillis[i] > interval[i]) {
previousMillis[i] = millis(); // remember the last time we blinked the LED
// if the LED is off turn it on and vice-versa.
if (value[i] == LOW){
value[i] = hitz[i];
interval[i] = 50;
}
else{
value[i] = LOW;
interval[i] = 3000;
}
digitalWrite(ledPin[i], value[i]);
}
}
}
There is no need to have a separate previousmills for each LED. You should have a single 'tick' for all 4 LEDs.
Your code, if the LED is told to be off by hitz, then you will keep checking it every 50mS and turn it off again.
Try changing the core part of your main loop from
for(int i=0;i<4;i++){
if (millis() - previousMillis[i] > interval[i]) {
previousMillis[i] = millis(); // remember the last time we blinked the LED
// if the LED is off turn it on and vice-versa.
if (value[i] == LOW){
value[i] = hitz[i];
interval[i] = 50;
}
else{
value[i] = LOW;
interval[i] = 3000;
}
digitalWrite(ledPin[i], value[i]);
}
}
to
// turn on the LEDs that should be on
for(int i=0;i<4;i++){
digitalWrite (ledPin[i], hitz[i]);
}
delay(50);
// turn off all the LEDs
for(int i=0;i<4;i++){
digitalWrite (ledPin[i], LOW);
}
delay(3000);
I haven't compiled that code, but it should at least give you the idea. There's no need to keep track of timings or of anything except which LEDs should be on.
However I am trying write this code without using delay(). The issue is that I need to have other time based code running and using delay() will prevent this from happening.
If you have any other ideas that would be much appreciated..
However I am trying write this code without using delay(). The issue is that I need to have other time based code running and using delay() will prevent this from happening.
If you have any other ideas that would be much appreciated..
Cheers,
Dave
I was keeping things simple to give you the idea of where your problem was.
As John_Ryan says, you can use a counter in loops, but if you need any precision, it becomes very hard to keep track of how long each iteration of the loop takes to run.
You can create a function that uses Millis to tell you if enough time has passed, call it once each loop, and act only if it returns true. Have it tell you when 50mS has passed, and for the led off part of your loop, just increment a counter each time. When you've counted 60 times, that's your 3000mS.
Sorry if that's not clear, but it's not an elegant solution so it's hard to explain clearly.
The way I would do it is using a timer interrupt to generate a tick and count ticks in my loop.
Declare int counter in the variables declarations section.
You'll need to experiment with the trigger values (counter > trigger) to figure out the timing.
That is the simplest way, but we don't know what he's planning to run in his loop, so we don't know that each iteration will take around the same length of time.
Actually, in JAL on the PIC Micros, I very often used the Interval library: Jal
Basically you call the interval function like you would delay on the Arduino, but whatever code that comes after that runs instantly without a delay. Then there's a second function to delay until the original interval is used up.
Something like:
//Pseudocode
Interval(10mS)
// do stuff here
EndInterval
// 10mS has passed since the original interval call as long as the stuff took less than 10mS.
I'm not sure if the Arduino has a library for this functionality yet though.
It's a basic framework for pausing without hanging 'the loop', so he could cut in at 2000 and do something else. I've used it before and once the intervals were determined it was quite stable.
Millis is another good one and rather more predictable, it wouldn't take much of a hack to implement that rather than counter.
Thats brilliant thank you very much Oracle and John_Ryan, you've been a great help...
I've ended up doing the millis() counter hack you talked about and it seems to be working fine.
I did look into the timer interrupt before, maybe i'll go back and try it again now i've gained some more knowledge from trying out different ways to solve this problem...