I've read all about millis on this forum and elsewhere and tried it on a couple LEDs to see how it worked. But I'm having difficulty trying to apply it to my project. I have 14 LEDs on the outside of a pentagon and another 14 on the inside. I want to rotate outside one direction and inside other direction. I don't know where to put my "millis" statements to get this going. I'm doing a matrix with 3 DIO from an UNO and 7 port expanders. In this program I'm only using two port expanders, one for inner, other for outer pentagon. The Loop() function of course is where all the action is. Can someone help out?
/*Name: PentCWRotMillis Test to see if I can get simultaneity using millis
Date: 3Jun2018
Desc: Outer and Inner pentagons rotate.
I2C addr used 25, 26
MCU: Arduino UNO
H/W: MCP23017 port expanders on two Pentagon sections
Vers: 1.1
*/
#include <Wire.h>
#include <Centipede.h>
Centipede CS;
const int pins[3] = {//9,10,11 are DIO pins for RGB transistors. Active high turns transistor on.
9, 10, 11 //use 9, 10, 11 because these are PWM pins on UNO
};
int x = 20;//delay between LED blink
int j;
const byte rgb[7] = {0x02, 0x04, 0x08, 0x0A, 0x06, 0x0C, 0x0E}; //02=red, 04=green, 08=blue
/*void i2cdev(int j) //function to write to the PE pin number j
{ CS.digitalWrite(j, HIGH);
delay(10);
CS.digitalWrite(j, LOW);
delay(10);
}*/
void setup() {
Wire.begin(); // start I2C
CS.initialize();
//Init all 7 I2C devices (points, 2 pentagons)keep this even though only pentagon being programmed
for (byte i = 0; i < 8; i++)
{
CS.portMode(i, 0x00); //
}
// initialize the DIO pins as outputs
for (byte i = 0; i < 3; i++)
{ pinMode(pins[i], OUTPUT);
}
}
void loop()
{ //Outer CW rotation followed by Inner CW rotation All (30) red , all green, then all blue
for (byte i = 0; i < 3 ; i++) //use i=7 for 7 colors, i=3 for 3
{ PORTB = rgb[i]; //cycle colors on pins 9,10,11
for (int j = 80; j <= 95; j++) //device 25
{
CS.digitalWrite(j, HIGH);
delay(x);
CS.digitalWrite(j, LOW);
delay(x);}
//I want this to rotate the opposite way, simultaneous with one above.
for (int j = 111; j >=96 ; j--) //Device 26
{ CS.digitalWrite(j, HIGH);
delay(x);
CS.digitalWrite(j, LOW);
delay(x);
}
}
}
In each ring of LEDs how many should be lighting at the same time?
Maybe you just need one timing interval for each ring (or maybe only a single interval for both if you want them synchronized) and an array for each group of LEDs so you can move the index along to identify which LED should (or should not) be ON.
Robin2, timing is not critical. I just want one rotation CW and the other CCW.
I tried a few things as Delta_G suggested but it didn't quite work so I think it's just a placement issue, where I put the brackets and braces.
As I changed some of those locations, I ended up with such neat OTHER patterns that I saved the file as different name.
I had something going where the outer lights were lighting every 200 mS, but the inner loop was blinking all 16 LEDS in the same color as the ones rotating on the outer edge. Kept that setup.
I have printout from the "Bald Engineer" who very nicely showed how to light two LEDs, or more using millis. That's the script I'm following.
The problem with my setup, I think, is the fact that the digitalWrite writes to 14 LEDS per side, not just two. I hope I don't have to do a "millis" setup for each of these 28 LEDS.
Maybe I could use the interrupt feature of my MCP23017 port expanders? When one port is "emptied", an interrupt gets generated that triggers the next routine?
You already have two 'state' variables, i and j. These two variables remember where the two different animations are up to in their cycle.
Now you need to add millis() timing so that each of those can advance independently. So record the last time each one moved and then look at that time in the loop() to see if it's time to increment the relevant state variable.
Note that your true number of states might increase as each value for i and j really does two timing-related things. The LED is on for a period of time, then off for a period of time. So after i moves to the next value, the LED stays on for the period x and then then off for period x before advancing i. There's a few ways to attack this - possibly the simplest is to add another state variable which remembers which half of the state it's in. (Of course there will be 2 of these, one for i and one for j.)
Remember that the names of the variables aren't downloaded to the Arduino. So there's no penalty for using long variable names. Instead of i and j, consider using something like outerRingPosition and innerRingPosition. That makes it easier for you to keep track of what's going on.
Here's what I have so far. Inside the loop function, I have one of my LED patterns using millis followed by the other pattern (going opposite direction), not using millis...yet.
The first pattern, the millis version does not work and I have moved brackets and parentheses to many different locations putting the millis commands in or outside of the For loop. No change, does not work.
The second pattern works, but this is one that I want to change so that it works simultaneously with the first one.
/*Name: PentSIMULSlowOutFastInner Test to see if I can get simultaneity using millis
Date: 3Jun2018
Desc: Outer and Inner pentagons rotate.
I2C addr used 25, 26
MCU: Arduino UNO
H/W: MCP23017 port expanders on two Pentagon sections
Vers: 1.1
*/
#include <Wire.h>
#include <Centipede.h>
Centipede CS;
const int pins[3] = {//9,10,11 are DIO pins for RGB transistors. Active high turns transistor on.
9, 10, 11 //use 9, 10, 11 because these are PWM pins on UNO
};
int x = 20;//delay between LED blink
int j;
const byte rgb[7] = {0x02, 0x04, 0x08, 0x0A, 0x06, 0x0C, 0x0E}; //02=red, 04=green, 08=blue
/*void i2cdev(int j) //function to write to the PE pin number j
{ CS.digitalWrite(j, HIGH);
delay(10);
CS.digitalWrite(j, LOW);
delay(10);
}*/
unsigned long previousMillisLED25 = 0;
unsigned long previousMillisLED26 = 0;
int intervalLED25 = 100;
int intervalLED26 = 100;
boolean LED25State = false;
boolean LED26State = false;
void setup() {
Wire.begin(); // start I2C
CS.initialize();
//Init all 7 I2C devices (points, 2 pentagons)keep this even though only pentagon being programmed
for (byte i = 0; i < 8; i++)
{
CS.portMode(i, 0x00); //
}
// initialize the DIO pins as outputs
for (byte i = 0; i < 3; i++)
{ pinMode(pins[i], OUTPUT);
}
}
void loop()
{ unsigned long currentMillis = millis();
{ //Outer does not rotate, blinks in 3 colors
for (byte i = 0; i < 3 ; i++) //use i=7 for 7 colors, i=3 for 3
{ PORTB = rgb[i]; //cycle colors on pins 9,10,11
for (int j = 80; j <= 95; j++) //device 25
if ((unsigned long)(currentMillis - previousMillisLED25) >= intervalLED25)
{ LED25State = !LED25State;
CS.digitalWrite(j, LED25State);
previousMillisLED25 = currentMillis;
}
//Inner rotates
for (int j = 111; j >= 96 ; j--) //Device 26
{ CS.digitalWrite(j, HIGH);
delay(x);
CS.digitalWrite(j, LOW);
delay(x);
}
}
}
}
Okay, I modified the program and it is a lot worse. If I put the "if" statement and LEDstate=!LEDstate inside the For loop of each part, I get ONE LED lighting up, LED 0. Nothing else.
If I put these statements outside of the IF statement, as shown in this code, I get all the outside lights, all 14 of them blinking in white (all RGB colors at same time). Nothing in inner pattern.
I'm sure it's all just a matter of placing the statements in the right sequence and the parentheses and braces/brackets in the right place.
NOTE: This time to save scrolling, I only included the LOOP(), not the entire program. (Nothing else changed.)
void loop()
{ unsigned long currentMillis = millis();
{ //Outer pattern to rotate CW
for (byte i = 0; i < 3 ; i++) //use i=7 for 7 colors, i=3 for 3
{ PORTB = rgb[i]; //cycle colors on pins 9,10,11
if ((unsigned long)(currentMillis - previousMillisLED25) >= intervalLED25)
{ LED25State = !LED25State;
for (int j = 80; j <= 95; j++) //device 25
{ CS.digitalWrite(j, LED25State);
previousMillisLED25 = currentMillis;
}
}
//Inner pattern to rotate CCW
if ((unsigned long)(currentMillis - previousMillisLED25) >= intervalLED26)
{ LED26State = !LED26State;
for (int j = 111; j >= 96 ; j--) //Device 26
{ CS.digitalWrite(j, LED26State);
previousMillisLED26 = currentMillis;
}
}
}
}
}
The program I used was from Bald Engineer website and he used two LEDS (LED12 and LED13). I have 28 LEDs.
How do I light 14 (on one side, 14 on the other) sequentially without using a FOR loop?
Making an array with 28 entries would almost give me the same effect as simultaneity...light one LED on outer, then one LED on inner, then outer, then inner.
queenidog:
How do I light 14 (on one side, 14 on the other) sequentially without using a FOR loop?
First, I would put your LEDs into an array. But instead of using a for() loop to turn them on, increment the index variable with a millis() "timer." That way you can control how quickly they turn on.
Partial/Untested code
unsigned long previousMillisIncrement = 0;
unsigned long incrementInterval = 100;
unsigned byte groupIndex = 0;
const unsigned byte maxIndex = 14;
bool onFlag = false;
byte ledPins[maxIndex] = {}; // filled with the right pins
void loop() {
if (onFlag && (millis() - previousMillisIncrement >= incrementInterval)) {
previousMillisIncrement = millis();
groupIndex++;
if (groupIndex >= maxIndex) {
// stop turning stuff on
groupIndex = 0;
onFlag = false;
} else {
digitalWrite(ledPins[groupIndex], HIGH);
}
}
Somewhere in your code, you need to set onFlag to true to make the whole thing happen. I would also "reset" prevousMillisiIncrement at the same time.
Gave up on millis. Solved my problem by doing what's in code blocks. A little ugly for the arrays but it works. I can create the arrays in 3 statements, but there is no saving in space, and then it's not that intuitive, so I will stay with the ugliness. I basically just ran the one array in reverse, so now 14 lights follow each other in sequence CW, while the other 14 rotate CCW. KISS!
I can barely program, and I wrote code to blink 4 LEDs asynchronously using millis().
/* Blink Four LEDs Without Delay
Adapted from Blink Without Delay
by Steven J Greenfield, aka Polymorph
Use however you like
*/
// constants won't change. Used here to
// set pin numbers:
const int ledPin0 = 2; // the number of the LED0 pin
const int ledPin1 = 3; // the number of the LED1 pin
const int ledPin2 = 4; // the number of the LED2 pin
const int ledPin3 = 5; // the number of the LED3 pin
// Variables will change:
int ledState0 = LOW; // ledState used to set the LED0
int ledState1 = LOW; // ledState used to set the LED1
int ledState2 = LOW; // ledState used to set the LED2
int ledState3 = LOW; // ledState used to set the LED3
unsigned long previousMillis0 = 0; // will store last time LED0 was updated
unsigned long previousMillis1 = 0; // will store last time LED1 was updated
unsigned long previousMillis2 = 0; // will store last time LED2 was updated
unsigned long previousMillis3 = 0; // will store last time LED3 was updated
// the follow variables is a long because the time, measured in milliseconds,
// will quickly become a bigger number than can be stored in an int.
unsigned long interval0 = 1000; // interval at which to blink LED0 (milliseconds)
unsigned long interval1 = 457; // interval at which to blink LED1 (milliseconds)
unsigned long interval2 = 1020; // interval at which to blink LED2 (milliseconds)
unsigned long interval3 = 742; // interval at which to blink LED3 (milliseconds)
void setup() {
// set the digital pin as output:
pinMode(ledPin0, OUTPUT);
pinMode(ledPin1, OUTPUT);
pinMode(ledPin2, OUTPUT);
pinMode(ledPin3, 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, if the
// difference between the current time and last time you blinked
// the LED is bigger than the interval at which you want to
// blink the LED.
// save the current time so it doesn't change during an operation
unsigned long currentMillis = millis();
// LED0
if(currentMillis - previousMillis0 >= interval0) {
// save the last time you blinked the LED0
previousMillis0 += interval0; // prevents time creep
// if the LED is off turn it on and vice-versa:
if (ledState0 == LOW)
ledState0 = HIGH;
else
ledState0 = LOW;
}
//LED1
if(currentMillis - previousMillis1 >= interval1) {
// save the last time you blinked the LED0
previousMillis1 += interval1;
// if the LED is off turn it on and vice-versa:
if (ledState1 == LOW)
ledState1 = HIGH;
else
ledState1 = LOW;
}
//LED2
if(currentMillis - previousMillis2 >= interval2) {
// save the last time you blinked the LED0
previousMillis2 += interval2;
// if the LED is off turn it on and vice-versa:
if (ledState2 == LOW)
ledState2 = HIGH;
else
ledState2 = LOW;
}
//LED3
if(currentMillis - previousMillis3 >= interval3) {
// save the last time you blinked the LED0
previousMillis3 += interval3;
// if the LED is off turn it on and vice-versa:
if (ledState3 == LOW)
ledState3 = HIGH;
else
ledState3 = LOW;
// set the LEDs with the ledStates of the variable:
digitalWrite(ledPin0, ledState0);
digitalWrite(ledPin1, ledState1);
digitalWrite(ledPin2, ledState2);
digitalWrite(ledPin3, ledState3);
}
}
There are other ways to do this using arrays rather than separate variables.