Hello Everyone!
I am writing here to ask for your help. I have been struggling with one of my assigments and honestly I have run out of ideas. I looked for a solution on the internet, but couldn't find a suitable help.
Here's some backround: I need to write a code which would light up each layer of 3x3x3 LED Cube (like this one for example: Arduino Playground - LEDCube3x3) for 1 sec., turn it off and move to the next one. All in loop. The catch is that the code needs to be written using millis() function. This is the biggest issue I have a problem with. There was absolutely no issue when I used delay() function. Could you please help here?
It looks like a state machine would be ideal for what you want to do. It sounds scary but isn't
Your cube has 3 layers which you want to light in turn so it can be in one of 3 states, one for each layer on. So, if you had a variable named state with possible values 0, 1 or 2 then you would know which layer to light and which ones to turn off
You could do this a number of ways but using switch/state makes it easy to write and understand. Use the state number as the switch variable and its value to determine which layer to light and which ones to turn off
Use millis() timing in each state to control the amount of time that a layer is on
Psuedo code
state = 0
start time = millis()
period = whatever suits you
start of loop()
current time = millis()
switch(state)
{
case 0
//code here to turn layers on/off for state 0
if current time - start time >= period
set state to next value
start time = current time
end if
case 1
//code here to turn layers on/off for state 1
if current time - start time >= period
set state to next value
start time = current time
end if
case 2
//code here to turn layers on/off for state 2
if current time - start time >= period
set state to next value
start time = current time
end if
}
end of loop()
Note that I have deliberately not written real code so you have work to do to work out the real code and get the syntax right but I hope that you can see the basic idea
I have adjusted the code according to the remarks above, but it still does not work. I am clearly doing something wrong. Where I might have done a mistake?
const unsigned long period = 1000;
unsigned long starttime = 0;
unsigned long currenttime;
int state=0;
void setup(){
for (int i=2; i<=13; i++) {
pinMode(i, OUTPUT);
}
}
void fill() {
for (int i=2; i<=10; i++) {
digitalWrite(i, HIGH);
}
}
void empty() {
for (int i=2; i<=10; i++) {
digitalWrite(i, LOW);
}
}
void loop() {
currenttime = millis();
starttime = millis();
switch(state)
{
case 0:
digitalWrite(11, HIGH);
fill();
if (currenttime - starttime <= period) {
digitalWrite(11, LOW);
empty();
starttime = currenttime;
}
break;
case 1:
digitalWrite(12, HIGH);
fill();
if (currenttime - starttime <= period) {
digitalWrite(12, LOW);
empty();
starttime = currenttime;
}
break;
case 2:
digitalWrite(13, HIGH);
fill();
if (currenttime - starttime <= period) {
digitalWrite(13, LOW);
empty();
starttime = currenttime;
}
break;
}
}
One obvious mistake is that you are setting starttime to millis() every time through loop() when you should be setting it only when a new state starts, ie once at the start of the sketch and subsequently whenever a new state starts
A second problem is that you don't increment the state variable when the timing period in the current state ends so the code never leaves state 0
Why are you using a for loop ?
Let loop() do what it does best ?
if (currenttime - starttime <= period)
You have the period comparisons the wrong way round
When the timing period for a state ends, set the state variable to the next state to be moved to
Try this
const unsigned long period = 1000;
unsigned long starttime = millis();
unsigned long currenttime;
int state = 0;
void setup()
{
Serial.begin(115200);
for (int i = 2; i <= 13; i++)
{
pinMode(i, OUTPUT);
}
Serial.println("starting in state 0");
}
void fill()
{
for (int i = 2; i <= 10; i++)
{
digitalWrite(i, HIGH);
}
}
void empty()
{
for (int i = 2; i <= 10; i++)
{
digitalWrite(i, LOW);
}
}
void loop()
{
currenttime = millis();
switch (state)
{
case 0:
digitalWrite(11, HIGH);
fill();
if (currenttime - starttime >= period)
{
digitalWrite(11, LOW);
empty();
starttime = currenttime;
Serial.println("moving to state 1");
state = 1; //switch to next state
}
break;
case 1:
digitalWrite(12, HIGH);
fill();
if (currenttime - starttime >= period)
{
digitalWrite(12, LOW);
empty();
starttime = currenttime;
Serial.println("moving to state 2");
state = 2;
}
break;
case 2:
digitalWrite(13, HIGH);
fill();
if (currenttime - starttime >= period)
{
digitalWrite(13, LOW);
empty();
starttime = currenttime;
Serial.println("moving to state 0");
state = 0;
}
break;
}
}
The code could be written to only once when the state variable changes but the cube won't care how many times you write to it.
The time calculations in the cases are easy. Basically, subtract the start time of the state from the current time and test whether the required period has passed.
Note that the start time for the current state is set when the period for the previous state ends