Elijahg:
Here's a quick countdown timer, but bear in mind there's no stopping it once it starts. For safety, you'd need to add code to stop the countdown too.
byte countdown_time_seconds = 10;
byte countdown_time_remaining;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
Serial.println("Counting down...");
}
void loop() {
// put your main code here, to run repeatedly:
for (countdown_time_remaining = countdown_time_seconds; countdown_time_remaining >= 0; countdown_time_remaining--) {
Serial.print("Will fire in: ");
Serial.println((int)countdown_time_remaining);
delay(1000);
}
Serial.print("Firing!");
}
That will work but placing a 1000 ms delay in there will cause his entire system to wait 1 second each time. During this wait, no other code can run.
MushfiqSarker:
That will work but placing a 1000 ms delay in there will cause his entire system to wait 1 second each time. During this wait, no other code can run.
That's true, but other than possibly cancelling the countdown I presume nothing else needs to run whilst the timer is counting down?
currentTime may never equal 1000, but rather skip over it, like from 998 to 1003 if anything in the loop adds up to 2 ms or more.
currentTime will increase in ever-increasing amounts since each pass it gets bumped by the total elapsed time since startTime!
My suggestion (without using delay() ):
unsigned long startTime;
int elapsed_seconds = 0;
int blastoff_seconds = 10;
void setup()
{
Serial.begin(9600);
startTime = millis();
Serial.println(blastoff_seconds);
}
void loop()
{
int new_elapsed_seconds = (millis() - startTime) / 1000;
if (new_elapsed_seconds != elapsed_seconds)
{
elapsed_seconds = new_elapsed_seconds;
Serial.println(blastoff_seconds - elapsed_seconds);
if (elapsed_seconds == blastoff_seconds)
{
Serial.println("Blast Off!");
// do Blastoff!
}
}
}
1. currentTime may never equal 1000, but rather skip over it, like from 998 to 1003 if anything in the loop adds up to 2 ms or more.
2. currentTime will increase in ever-increasing amounts since each pass it gets bumped by the total elapsed time since startTime!
My suggestion (without using delay() ):
unsigned long startTime;
int elapsed_seconds = 0;
int blastoff_seconds = 10;
void setup()
{
Serial.begin(9600);
startTime = millis();
Serial.println(blastoff_seconds);
}
if (elapsed_seconds == blastoff_seconds)
{
Serial.println("Blast Off!");
// do Blastoff!
}
}
}
I agree it may jump over. I usually use a >= (forgot to add it in the code). In my normal projects, I am OK with being off by a few milleseconds. Projects where I need more precision, I use a RTC (real time clock) with integration of the millis from microcontroller.
Thanks for your help guys, I ended up giving up and going to bed at 2am
I will look through you suggestion and see if I can get it working
I maybe should have gone into a bit more detail
This is how it should work
User presses fire button and countdown begins
System beeps every second
Countdown is displayed on LCD screen
LED's Flash
System continually checks safety features i.e. safety key is still inserted etc if not countdown stops with abort code
At the end of the chosen countdown time fire() is call which ignites the rocket motor
I can get everything to work apart from the countdown code
I have always had a problem getting my head around Millis and I just don't know why I understand the logic just can't implement it
Delay is not a option due to the safety checks that have to run continually
My response wasn't just a correction; it is different code.
It will work and allows you to put in all the checks you want and they'll have instant response as delay() is not used.
The code will look clean if you create a separate subroutine just for the checks.
It returns a zero if all is OK, otherwise it returns an abort code number.
Think of "millis()" as if it were better named to be "currentTimeFromLongAgoInMilliseconds()"
int LauncherSystemCheck()
{
if ( checkRelayPower() != 0 )
return 1;
if ( IgnitorContinuity() != 0 )
return 2;
if ( KeyInserted() != 0 )
return 3;
return 0;
}
void loop()
{
int abortCode = LauncherSystemCheck();
if (abortCode != 0)
{
Serial.print("Abort! code = ");
Serial.println(abortCode);
while (true)
; // Never start - infinite loop
}
int new_elapsed_seconds = (millis() - startTime) / 1000;
if (new_elapsed_seconds != elapsed_seconds)
{
elapsed_seconds = new_elapsed_seconds;
Serial.println(blastoff_seconds - elapsed_seconds);
if (elapsed_seconds == blastoff_seconds)
{
Serial.println("Blast Off!");
// do Blastoff!
}
}
}
Happy Father's Day! Hope you're having a great time with your offspring and this project. We're model rocketeers from way back. Here's a sketch to try, maybe it will help get past the countdown part. It's just a demo, no LCD, etc., and does not attempt to address all the features and requirements posted earlier
#include <Button.h> //https://github.com/JChristensen/Button
#include <Streaming.h> //http://arduiniana.org/libraries/streaming/
#define BUTTON_START 4 //wire from pin 4 to ground
#define BUTTON_ABORT 5 //wire from pin 5 to ground
#define redLED 6 //wire from pin 6 to ground through appropriate current limiting resistor (e.g. 330 ohm)
#define grnLED 7 //wire from pin 7 to ground through appropriate current limiting resistor (e.g. 330 ohm)
#define PIEZO 8 //wire from pin 8 to ground through appropriate current limiting resistor (e.g. 100 ohm)
#define DEBOUNCE_MS 25 //debounce interval (ms)
#define COUNTDOWN_SEC 10 //number of seconds to countdown from
Button btnStart(BUTTON_START, true, true, DEBOUNCE_MS); //instantiate the buttons, pullups on, inverted logic
Button btnAbort(BUTTON_ABORT, true, true, DEBOUNCE_MS);
unsigned long ms; //the time from millis()
unsigned long msCount; //time when the count was changed
unsigned long msLED; //time when the LED was turned on
int count; //the countdown counter
enum {START, STANDBY, COUNTDOWN, ABORT, LAUNCH, WAIT}; //states for the state machine
uint8_t STATE; //current state machine state
void setup(void)
{
Serial.begin(115200);
pinMode(redLED, OUTPUT);
pinMode(grnLED, OUTPUT);
pinMode(PIEZO, OUTPUT);
}
void loop(void)
{
ms = millis();
btnStart.read();
btnAbort.read();
switch ( STATE ) {
case START:
noTone(PIEZO);
digitalWrite(redLED, LOW);
digitalWrite(grnLED, HIGH);
Serial << endl << "Stand by to begin countdown sequence..." << endl;
STATE = STANDBY;
break;
case STANDBY:
if ( btnStart.wasPressed() ) {
count = COUNTDOWN_SEC;
tone(PIEZO, 1500, 800);
digitalWrite(redLED, HIGH);
digitalWrite(grnLED, LOW);
msCount = ms;
msLED = ms;
STATE = COUNTDOWN;
Serial << "Countdown: " << _DEC(count) << " ... ";
}
break;
case COUNTDOWN:
if ( btnAbort.wasPressed() ) {
STATE = ABORT;
break;
}
if ( ms - msLED >= 500 && count > 1) {
digitalWrite(redLED, LOW);
msLED = ms;
}
if ( ms - msCount >= 1000 ) {
msCount = ms;
digitalWrite(redLED, HIGH);
msLED = ms;
tone( PIEZO, 1500, --count == 1 ? 900 : 100 );
if ( count == 0 )
STATE = LAUNCH;
else
Serial << _DEC(count) << " ... ";
}
break;
case ABORT:
Serial << endl << "Countdown aborted at T-" << _DEC(count) << " seconds!" << endl;
STATE = START;
break;
case LAUNCH:
tone(PIEZO, 2000, 1000);
digitalWrite(redLED, HIGH);
digitalWrite(grnLED, HIGH);
msLED = ms;
Serial << "LAUNCH!" << endl;
STATE = WAIT;
break;
case WAIT:
if ( ms - msLED >= 2000 ) STATE = START;
break;
}
}
I searched all the code in your zip file. I do not see any Serial.print statements that include "CountDown2", as in your "CountDown2 Start" or "CountDown2 end"
Perhaps that is not the same code. Also, better indentation would make the code much more readable.
Ok, for the wireless you could use the xbee wireless module, or for cheaper, you could use a wireless adapter, and a router running openwrt. For the buttons and stuff I think you should break them down into pieces. ex: make that keypad so it can take the input and convert to a countdown, save that code and setup once you get it working. Next make a button that starts a timer, and save that code and get it working, then go to your fail-safe key etc. and when you are done combine all the code. It's easier to troubleshoot when it's in small bits so you can locate the problem easier.
Firstly I would like to thank everyone for all the help and advice and I would also like to apologise for not replying and updating this post.
This project has been very slow to progress, due to the massive learning curve I have encountered and work/family commitments
The Controller unit is now 98% complete, the knowledge I have gained through the development of this part of the system should hopefully allow me to complete the Pad unit very quickly.
I will add some images of the project over the next few days/weeks and I hope to be preforming live tests on the system in early November.
I am planning to use the system to launch our new rocket (Armstrong 2012) before the end of the year.