AdeV the motor will be controlled by the Arduino but hadn't thought about stopping it automatically but I like the idea I might see if I can get it into the code but not sure if I can have multiple milllis()?
Time to brave the sometimes brutal arduino forums I think.
They can be brutal, I agree. The most common, and most annoying IMHO, response often being "Why do you want to do THAT?". To which my keyboard always seems to reply "None of your damn business!"
Anyway... feel free to post your code here if you want, I'm happy to take a look at it & see if I can help. Personally, I'd implement it along these lines (this is makey-uppy-pseudocode, you'll have to convert it to real code yourself...)
First: Define the states for your motor; typically: Stopped, Starting, Running, Stopping. How you get from "stopped" to "starting" I leave up to you (press a button? power on?)
Second, define the duration of each state (excluding Stopped, assuming you don't want it to cycle forever until switched off).
At the start of the main loop, set a variable to the current millis() value (e.g. "_timeNow")
Have a second variable (e.g. _currentStateTime). If this is the first loop, set it to _timeNow, and set your current state to Starting (I assume you want the carousel to start immediately when it's powered on)
Subtract _currentStateTime from _timeNow to give you the number of millis into the current state you are. For Starting and Stopping, divide this value by the duration to give you the proportion of the elapsed state time (between 0 and 1). For Starting, multiply this by your maximum motor speed (e.g. 127, or 1024 if you're using a PWM output) & set the current motor speed to that value. For stopping, use (1-proportion) instead. This will give you a smooth ramp up in speed from zero to flat out; or a smooth ramp down from flat out to stopped. When _timeNow - _currentStateTime >= current state max duration, switch state & set _currentStateTime to _timeNow again. Thus re-setting the clock. For running & stopped, you don't need to alter the motor speed (unless you want to set it to max/zero to make absolutely sure it's on or off).
OK, let's try that in pseudo-code...
// Adjust times to personal preference
const unsigned long startingTime = 5000; // 5 seconds
const unsigned long runningTime = 20000; // 30 seconds
const unsigned long stoppingTime = 7500; // 7.5 seconds
const unsigned long stoppedTime = 10000; // 10 seconds
byte _currentState = 0; // 0=undefined, 1=starting, 2=running,3=stopping,4=stopped
unsigned long _currentStateTime = 0;
unsigned long _timeNow = 0;
loop()
_timeNow = millis();
switch (_currentState) {
case 0: // Undefined
// First run comes here, set state to Starting.
_currentStateTime = timeNow;
_currentState = 1;
break;
case 1: // Starting
if (_timeNow - _currentStateTime >= startingTime) {
_currentStateTime = timeNow;
_currentState = 2;
analogSet(motorPin, 1024); // Ensure we're at maximum speed
} else {
float __proportionElapsed = (_timeNow - _currentStateTime) / startingTime;
analogSet(motorPin, __proportionElapsed*1024); // accelerating
}
break;
case 2: // running
if (_timeNow - _currentStateTime >= runningTime) {
_currentStateTime = timeNow;
_currentState = 3;
}
break;
case 3:
if (_timeNow - _currentStateTime >= stoppingTime) {
_currentStateTime = timeNow;
_currentState = 4;
analogSet(motorPin, 0); // Ensure we're completely stopped
} else {
float __proportionElapsed = (_timeNow - _currentStateTime) / startingTime;
analogSet(motorPin, (1 - __proportionElapsed) * 1024); // slowing...
}
break;
case 4: // Stopped
if (_timeNow - _currentStateTime >= stoppedTime) {
_currentStateTime = timeNow;
_currentState = 1; // Go back to starting
}
break;
}
// Rest of code (that looks after the light show)
}
OK, so unlike my description above, that will loop continuously, with a 10s stop period. If you wanted to start the carousel on a button push, you'd use an interrupt to set a "start" flag (which would then be ignored until the sequence was complete). The final "stopped" section would reset the "start" flag, and the loop would idle until the button was pushed, setting the start flag & starting the whole sequence again.
Also... I presume you'd want the light show to stop with the carousel; or perhaps change to a partial (constant) display; you could use the _currentState variable to control the light show as well...
Un-mentioned on the
Arduino millis() page is the fact that, being an unsigned long integer means that when the millis() variable runs out of space (overflows), the "millis() - previous time" logic continues to work properly! e.g. let's say millis overflows after 255 (byte sized), because of the way microprocessors do arithmetic on integers, 10 - 250 = 16 (for unsigned 8-bit bytes). In your head, you have to imagine it's actually (256 + 10) - 250. In the MCU, the overflow flag gets set, and ignored. Of course, the more bits in the integer, the higher the overflow number.... so a 10-bit word would overflow on 1024.
If you want REALLY fine control over the durations, use micros() instead!
