Hi Folks. I'm new to Arduino/C++ and MoBaTools. I was just working with MoBaTools' Timebase and Timer to light an LED (both are in the code below although one has been commented out). The code is supposed to wait 5 seconds after Arduino is powered on and then light the LED for 500ms. Nothing is happening when I upload the sketch. Can anyone see what I'm doing wrong?
#include <MobaTools.h> // Include MobaTools
MoToSoftLed myLed;
MoToTimer myTimer1;
MoToTimer myTimer2;
MoToTimebase myBase;
MoToTimebase myBase2;
int ledPin = 13;
void setup()
{
Serial.begin(115200);
myLed.attach(ledPin);
}
void loop()
{
////////// USING BASETIME //////////
myBase.setBasetime(5000); // set a timer for 5 seconds after startup
myBase.start(); // begin timer
if (myBase.tick() == true) // if the timer is up...
{
myBase2.setBasetime(500); // set a second timer for 500ms
myBase2.start(); // start second timer
myLed.on(); // turn on led
}
if(myBase2.tick() == true) // if timer 2 is up...
{
myLed.off(); // turn off led
}
////////// USING TIMER //////////
myTimer1.setTime(5000); // start a 5 second timer
if (myTimer1.expired() == true ) // if timer expires...
{
myTimer2.setTime(500); // start a second 500ms timer
myLed.on(); // turn on the LED
}
if (myTimer2.expired() == true ) // if timer expires...
{
myLed.off(); // turn off led
}
}
@blh64 is right. Because you restart the timers over and over they will never expire.
MoToTimebase is meant to create ticks in regular intervals. Usually you set the time once in setup() and you will get timer events ( ticks ) at the set interval. You don't need to restart it.
MoToTimer is a one-time running timer ( just like a retriggerable HW MonoFlop ). You start the time and you will get a single event when the timer expires. If you set the time again before it expires it will start over.
I've shortened your sketch to a simple example with only one Timebase (myBase) and one Timer (myTimer1). The LED is switched on in regular 5 sec intervals, and every time it is switched on a timer is started to switch it off 1 sec later.
#include <MobaTools.h> // Include MobaTools
MoToSoftLed myLed;
MoToTimer myTimer1;
MoToTimer myTimer2;
MoToTimebase myBase;
MoToTimebase myBase2;
int ledPin = 13;
void setup()
{
Serial.begin(115200);
myLed.attach(ledPin);
myBase.setBasetime(5000); // set a timer to tick every 5 seconds
//myBase2.setBasetime(500); // set a second timer to tick every 500ms
}
void loop()
{
////////// USING BASETIME //////////
if (myBase.tick() == true) // if the timer is up...
{
myLed.on(); // turn on led
myTimer1.setTime(1000); // turn it off in 1 second
}
if (myTimer1.expired() == true) // if timer 1 expired
{
myLed.off(); // turn off led
}
}
Thank you. I was confused. Not that it's all clear now but I'm working at it.
In my application, upon button press, I'd like to wait for 500ms, then flash the LED rapidly 3 times (20 ms on, 20 ms off, 20 ms on, 20ms off, 20 ms on and 20 ms off again), then have the LED stay on solid for 4 seconds, and then flash three times rapidly, as before, before turning off.
Is this doable with Base/Timers? I'm struggling with this one.
Thank you. I was truly befuddled (which is easy as I'm just starting out). I'm going to play around with the code for a bit a see if I can get something together that works.
Since you are new to all this. I would set aside this sketch and the MobaTools library and start off much more basic.
look at the Button and Debounce examples (File->examples->02.basic...) to learn about buttons.
After you have that working, you can simply use delay() to make your LED do what you want.
After you have mastered that, then look at the BlinkWithoutDelay example to see how to remove your delay() calls so your program can be more responsive all the time (e.g. another button press). At that point, you can start to work with the MobaTools library.
You are still setting your timer every time through loop() so it will never expire which means all the code in your nested if() statements will never execute.
Even if that is fixed, how do you think setting a timer and then immediately testing it for expiration will ever succeed?
I would suggest reading my previous post - set this project aside while you are coming up the learning curve.
Thank you. I took one more stab at the MoBaTools but I'm afraid its not working and I'm further afraid that I'm not even close to the solution. I posted the code for comments.
I'll take a peek at blink without delay. I had hoped to stay away from delay() as it would block other aspects of the sketch.
A good goal but based on your current understanding level, start out with delay() and get the sketch to at least run exactly how you want (blinking, etc.) and then worry about removing delay(). The sketch you posted doesn't have "any other code" that needs to be running. If this is the start of a larger sketch, you still can have individual sketches to understand how things work.
Hi Tony,
you don't need that much timer to blink one LED. One is sufficent.
You should study how a FSM (finite-state-machine) works. This programming technique is a great solution for many problems and nonblocking programming.
Here is an a little bit simplified solution ( only one sequence of fast blinking ) with a state machine. It is not really easy to understand at first how a FSM works, but it's worth learning it. The start button must be connected between pin 2 and Gnd.
#include <MobaTools.h> // Include MobaTools
// blink sketch using a FSM
MoToSoftLed myLed;
MoToTimer myTimer;
// 'const' are all values that never change in the sketch
const byte maxBlink = 3; // blinking 3 times
const int waitTime = 500;
const int blinkTime = 50;
const int solidOnTime = 4000;
const byte ledPin = 13;
const byte startPin = 2; // The sequence starts, if this pin is connected
// to Gnd ( e.g. by a button )
// our FSM needs the following states:
// Later that should be defined with an enum
const byte IDLE = 1; // waiting for the button press
const byte WAIT1 = 2; // first delay until blinking
const byte BLINK_ON = 3; // Blink ON state
const byte BLINK_OFF = 4; // Blink off state
const byte WAIT2 = 5; // last ON time
byte blinkState = IDLE; // FSM starts in first state
byte blinkCount; // count the number of blink cycles
void setup()
{
Serial.begin(115200);
myLed.attach(ledPin);
pinMode( startPin, INPUT_PULLUP );
}
void loop()
{
// within every loop() cycle only the statements of the active
// FSM state ( = switch case ) are executed, all others are ignored
switch ( blinkState ) {
case IDLE: // here we are waiting for the button press
if ( digitalRead(startPin) == LOW ) {
// Start button has been pressed
Serial.println("Start button pressed, wait a moment ... ");
myTimer.setTime( waitTime );
blinkState=WAIT1; // now we only wait for the timer to expire
}
break; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
case WAIT1: // waiting the first delaytime
if ( myTimer.expired() ) {
Serial.println("Start blinking now...");
blinkCount= maxBlink; // counting the blinking
myLed.on();
myTimer.setTime(blinkTime); // start time for on time
blinkState=BLINK_ON;
}
break; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
case BLINK_ON: // Led is on, wait until on time is over
if ( myTimer.expired() ) {
// now switch off and wait off time
myLed.off();
myTimer.setTime(blinkTime); // start time for off time
blinkState=BLINK_OFF;
}
break; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
case BLINK_OFF: // Led is off, wait until off time is over
if ( myTimer.expired() ) {
myLed.on();
// now we must decide wether there have been enough blink cycles
blinkCount--; // decrement counter
if ( blinkCount > 0 ) {
// still blinking ... so switch to BLINK_ON again
myTimer.setTime(blinkTime); // start time for on time
blinkState=BLINK_ON;
} else {
// blinking finished, switch to solid on
Serial.println("Blinking finished, now solid on");
myTimer.setTime(solidOnTime);
blinkState = WAIT2;
}
}
break; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
case WAIT2: // Led is solid on, wait until everything is finished
if ( myTimer.expired() ) {
Serial.println("full sequence finished, wait for button press again");
myLed.off();
blinkState = IDLE;
}
break; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
} // End of FSM
}
The FSM code is not blocking, so it is easy to expand the sketch ( with other nonblocking code - e.g. another FSM ).
I tried to include some comments that hopefully make it more understandable. But feel free to ask...
Have fun,
F-P
Hi Tony,
because I just enjoyed it , I wrote a class with which an arbitrary blinking pattern can be realised. You can simply copy the blinksequence.h file into your sketch directory to use it.
blinksequence.h:
/* BlinkSequence
A class for realizing arbitrary blink sequences.
The sequence is defined by an array of data triplets:
repeatCount, ontime, offtime
The end of the sequence is marked by setting repeatCount to 0
e.g.
blkPatten_h blkSq[] = {
{ 1,0,500 }, // because onTime = 0 here, sequence starts with led off
{ 3,50,50 }, // 3 times on/off 50ms
{ 1,4000,0 },
{ 0,0,0} // if onTime is >0 in last pattern, the sequence loops forever
}
Class methods:
init( blkPatten_h *sequence, byte ledPin, int riseTime ); // riseTime is optional and 0 by default
void process() // must be called frequently in loop
void start() // start the sequence
void stop() // stop the sequence at any time
bool running() // returns true while the sequence is running
*/
#include<MobaTools.h>
struct blkPatten_h {
byte repeat;
uint16_t onTime;
uint16_t offTime;
};
class BlinkSequence {
public:
BlinkSequence() {
}
void init( blkPatten_h *sequence, byte ledPin, int bulbTime = 0 ) {
_sequence = sequence;
_blkLed.attach(ledPin);
_blkLed.riseTime( bulbTime );
}
void start() {
// start a blink sequence
_seqIx = 0;
// start first step
_startPattern();
}
void stop() {
_seqRunning = false;
}
bool running() {
return _seqRunning;
}
void process() {
// process the sequence
if ( _seqRunning ) {
if ( !_blkTimer.running() ) {
if ( _ledOn ) {
_blkLed.off();
_ledOn = false;
_blkTimer.setTime( _sequence[_seqIx].offTime );
} else {
// Led was off - checking if we should still blink in this pattern entry
if ( --_blkCount > 0 ) {
// switch led on in same pattern
_ledOn = true;
_blkLed.on();
_blkTimer.setTime( _sequence[_seqIx].onTime );
} else {
// no, switch to next pattern entry
_seqIx++;
_blkCount = _sequence[_seqIx].repeat;
// Check for end of sequence
if ( _sequence[_seqIx].repeat == 0 ) {
// is last entry, check for endless repaet
if (_sequence[_seqIx].onTime > 0 ) {
// is endless, start over
_seqIx = 0;
_startPattern();
} else {
_seqRunning = false;
}
} else {
// no end, start pattern
_startPattern();
}
}
}
}
}
}
private:
MoToTimer _blkTimer;
MoToSoftLed _blkLed;
blkPatten_h *_sequence;
byte _blkCount; // to count the blinking in one sequenc entry
byte _seqIx; // Index in sequence array
bool _seqRunning;
bool _ledOn;
void _startPattern () {
// start actual pattern
_seqRunning = true;
_blkCount = _sequence[_seqIx].repeat;
if ( _blkCount == 0 ) _blkCount = 1; // must be greater 0
_blkTimer.setTime( _sequence[_seqIx].onTime );
if ( _sequence[_seqIx].onTime > 0 ) {
// don't really switch on, if on time is 0
_blkLed.on();
}
_ledOn = true;
}
};
[Edit] As it is now, max on and off time is limited to about 64 seconds. If you need longer times you must change the uint16_t in struct blkPatten_h to uint32_t. But this needs considerable more memory - especially if you define many or long sequences.
Thank you. I’ve been digesting your code and I think I’m making sound progress. I may have a couple questions for you but I’m waiting until I think I understand it as much as possible.
Again, thank you for spending some of your time on my. It’s very much appreciated.
You should be able to use the BlinkSequence class without diving deeper into it's internals. ( as it is with most libraries ). But of course you can have a closer look and try to understand how it works. Feel free to ask if something is unclear
I think I've mentioned the project I'm working on. A dinosaur that will have a few features, such as moving legs, eyes that light up, a jaw that moves (hopefully I've left enough room in the model for this), and lights on his spine that blink (the same ones you helped me with by creating a FSM).
Over the weekend I've been working on converting my leg movement code to a FSM. I thought my logic was sound but I'm not getting any movement. Honestly, I was super excited at the prospect that I might have worked it out on my own. Alas, I think I need a little nudge in the right direction.
Would you please take a peek at it to see anything obviously wrong with the code?
#include <MobaTools.h> // Include MobaTools
#include <ezButton.h>
MoToSoftLed myLed;
MoToTimer myTimer;
MoToServo myServoLeft;
MoToServo myServoRight;
MoToServo myServoJaw;
ezButton legsButton(4);
ezButton jawButton(5);
ezButton ledsButton(7);
//******************************* LED FSM *********************************
// LEDs on Dinosaur's back light up
// 'const' are all values that never change in the sketch
const byte maxBlink = 8; // blinking 3 times
const int waitTime = 250; // wait 250ms
const int blinkTime = 50; // time on for blinks
const int solidOnTime = 4000; // solid state
const int ledPin = 12; // led pin
// our FSM needs the following states:
// Later that should be defined with an enum
const byte IDLE = 1; // waiting for the button press
const byte WAIT1 = 2; // first delay until blinking
const byte BLINK_ON = 3; // Blink ON state
const byte BLINK_OFF = 4; // Blink off state
const byte BLINK_OFF2 = 5; // Off
const byte BLINK_AGAIN = 6; // Series of short blinks
const byte WAIT2 = 7; //
byte blinkState = IDLE; // FSM starts in first state
byte blinkCount; // count the number of blink cycles
byte blinkCount2;
//******************************* MOTOR FSM *******************************
// Legs on Dinosaur move
const int servoLeftLegMinPos = 90; //set initial Left Leg pos as 90
const int servoRightLegMinPos = 90; //set initial Right Leg pos as 90
const int servoLeftLegMaxPos = 130; //set max position of Left Leg as 130 deg
const int servoRightLegMaxPos = 130; //set max position of Right Leg as 130 deg
const int servoLeftLegInitialPos = 110; //set Left Leg initial pos at 110 deg
const int servoRightLegInitialPos = 110; //set Right Leg initial pos at 110 deg
const int legServoSpeed = 5;
const byte IDLE2 = 1; // waiting for the button press, move from resting pos
const byte SWING1 = 2; // leg swings back
const byte SWING2 = 3; // leg swings forward
const byte SWING3 = 4; // leg swings back
const byte SWING4 = 5; // leg swings forward
const byte SWING5 = 6; // leg swings back
const byte BACK_TO_START = 9; // leg swings to initial/resting pos
byte motorState = IDLE2; // FSM starts in first state
//*************************************************************************
//******************************* SETUP ***********************************
void setup() {
// set the digital pin as output:
Serial.begin(115200); // serial monitor for debugging
myLed.attach(ledPin); // led pin attach
legsButton.setDebounceTime(50); // debounce button
jawButton.setDebounceTime(50); // debounce button
ledsButton.setDebounceTime(50); // debounce button
myServoLeft.attach(9); // attach left servo motor
myServoRight.attach(10); // attach right servo motor
myServoJaw.attach(8); // attach jaw motor
}
//******************************* LOOP ************************************
void loop() {
legsButton.loop(); // call button function legs
ledsButton.loop(); // call button function leds
//*************************************************************************
//******************************* MOTOR FSM *******************************
// The objective is to move a servo motor back and forth. It will have a leg attached and
// is supposed to look like the dinosaur is walking. The legs will hanging straight down to start
// and then swing back and forth with servo motor between certain angles (min and max). The angles I'm using are
// just starting points.
switch ( motorState ) {
case IDLE2:
if ( legsButton.isPressed() ) {
Serial.println("Move from resting/initial pos");
myServoLeft.setSpeedTime(legServoSpeed);
myServoLeft.write(servoLeftLegMaxPos);
motorState=SWING1;
}
break; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
case SWING1:
if ( myServoLeft.read() == servoLeftLegMaxPos) {
Serial.println("Swing forward 1");
myServoLeft.setSpeedTime(legServoSpeed);
myServoLeft.write(servoLeftLegMinPos);
motorState=SWING2;
}
break; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
case SWING2:
if ( myServoLeft.read() == servoLeftLegMinPos) {
Serial.println("Swing back 1");
myServoLeft.setSpeedTime(legServoSpeed);
myServoLeft.write(servoLeftLegMaxPos);
motorState=SWING3;
}
break; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
case SWING3:
if ( myServoLeft.read() == servoLeftLegMaxPos) {
Serial.println("Swing forward 2");
myServoLeft.setSpeedTime(legServoSpeed);
myServoLeft.write(servoLeftLegMinPos);
motorState=SWING4;
}
break; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
case SWING4:
if ( myServoLeft.read() == servoLeftLegMinPos) {
Serial.println("Swing back 2");
myServoLeft.setSpeedTime(legServoSpeed);
myServoLeft.write(servoLeftLegMaxPos);
motorState=SWING5;
}
break; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
case SWING5:
if ( myServoLeft.read() == servoLeftLegMaxPos) {
Serial.println("Swing forward 3");
myServoLeft.setSpeedTime(legServoSpeed);
myServoLeft.write(servoLeftLegInitialPos);
motorState=BACK_TO_START;
}
break; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
case BACK_TO_START:
if ( myServoLeft.read() == servoLeftLegInitialPos) {
Serial.println("Return to resting/initial pos. Goto Idle2");
myServoLeft.setSpeedTime(legServoSpeed);
motorState=IDLE2;
}
break; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
}
//*************************************************************************
//******************************* LED FSM *********************************
// within every loop() cycle only the statements of the active
// FSM state ( = switch case ) are executed, all others are ignored
switch ( blinkState ) {
case IDLE: // here we are waiting for the button press
if ( ledsButton.isPressed() ) { // if ( digitalRead(ledsButton) == LOW ) {
// Start button has been pressed
Serial.println("Start button pressed, wait a moment ... ");
myTimer.setTime( waitTime );
blinkState=WAIT1; // now we only wait for the timer to expire
}
break; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
case WAIT1: // waiting the first delaytime
if ( myTimer.expired() ) {
Serial.println("Start blinking now...");
blinkCount= maxBlink; // counting the blinking
blinkCount2 = maxBlink;
myLed.on();
myTimer.setTime(blinkTime); // start time for on time
blinkState=BLINK_ON;
}
break; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
case BLINK_ON: // Led is on, wait until on time is over
if ( myTimer.expired() ) {
// now switch off and wait off time
myLed.off();
myTimer.setTime(blinkTime); // start time for off time
blinkState=BLINK_OFF;
}
break; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
case BLINK_OFF: // Led is off, wait until off time is over
if ( myTimer.expired() ) {
myLed.on();
// now we must decide wether there have been enough blink cycles
blinkCount--; // decrement counter
if ( blinkCount > 0 ) {
// still blinking ... so switch to BLINK_ON again
myTimer.setTime(blinkTime); // start time for on time
blinkState=BLINK_ON;
} else {
// blinking finished, switch to solid on
Serial.println("Blinking finished, now solid on");
myTimer.setTime(solidOnTime);
blinkState = BLINK_OFF2;
}
}
break; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
case BLINK_OFF2: // Led is solid on, wait until everything is finished
if ( myTimer.expired() ) {
Serial.println("Solid on over");
myLed.off();
myTimer.setTime(blinkTime);
blinkState = BLINK_AGAIN;
}
break; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
case BLINK_AGAIN: // Led is off, wait until off time is over
if ( myTimer.expired() ) {
myLed.on();
// now we must decide wether there have been enough blink cycles
blinkCount2--; // decrement counter
if ( blinkCount2 > 0 ) {
// still blinking ... so switch to BLINK_ON again
myTimer.setTime(blinkTime); // start time for on time
blinkState=BLINK_OFF2;
} else {
// blinking finished, wait for next button press
Serial.println("Blinking finished, now wait for button press.");
myLed.off();
blinkState = IDLE; //
}
}
break; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
} //end FSM
//*************************************************************************
}
Oh, I also modified your FSM Led code and added an extra sequence of rapid blinks at the end. And I'll be looking to see about implementing your BlinkSequence Library soon. I did look at the code in there and as you surmised it's pretty heavy stuff for me. I'm going to stick to working on developing my knowledge and use of FSMs.