Arduino blog

Arduino blog

Arduino thinkering

This blog is about things I come by related to Arduino which I feel are inspiring/important/funny enough to write about.

Controlling Arduino over the web: Blinking a led the cool way.

Arduino sketch experiancesPosted by Jan Wed, September 11, 2013 20:37:35
In the previous article I talked about how to get sentences over the serial line to arduino with the aim to control a Arduino sketch via the internet.
If we want a sketch to control I need a sketch. (I know you are eager to get on the internet but we have to do this step by step. Bear with me)

I took the sample sketch "Blink without delay" made a c++ class for it and made a sketch "may way" (read with loop and setup methods).
(OK; I modded quite a bit but it all started from the blink without delay and I added functionality to have a different on than off time.)

Then I extended the Serial string example we used before with a blinking led.

#include "SerialStringReader.h"
#include "BlinkLed.h"
SerialStringReader mySerialReader;
BlinkLed led13(LED_BUILTIN,500,2000);


//The setup function is called once at startup of the sketch
void setup()
{
Serial.begin(9600);
led13.setup();
mySerialReader.setup();
}

// The loop function is called in an endless loop
void loop()
{
mySerialReader.loop();
led13.loop();
if (mySerialReader.messageReceived())
{
Serial.println("You have send a message to Arduino.");
Serial.println("And the message is:");
Serial.println(mySerialReader.getMessage());
}
}


Lets look at the important parts:
BlinkLed led13(LED_BUILTIN,500,2000);
States the led is connected to pin LED_BUILTIN (13 on most arduinos) and is 500 millis on and 2000 millis off.
led13.setup();
Is to initialize the class. And
led13.loop();
Makes sure the led blinks.
If you want more leds blinking just add more leds to your Arduino and add more classes, setups and loops. You can use a different timing for each led.

If you download the BlinkLed library from github you can compile and upload the sketch to your Arduino.

Now that we have a sketch to change values; we can finally think about changing values. With this sketch we want to be able to change the on and the off time of the blinking led via the serial monitor. But we also want to be able to see the status, know the pin. In other words all the variables of the class must be visible.
Remember I talked about "Kind of memory dump". What we need to do is tell Arduino what the kind of memory dump looks like.
We do this by creating a new class that is derived from BlinkLed and from SerialDataInterface.
SerialDataInterface is a helper class that allows you to easily create the "kind of memory dump" for a class.

The myBlink header looks like this
#ifndef MYBLINKLED_H_
#define MYBLINKLED_H_

#include <BlinkLed.h>
#include <SerialDataInterface.h>

class MyBlinkLed: public BlinkLed, public SerialDataInterface
{
private:
//For SerialDataInterface
static const uint8_t NUMFields = 5;
static const uint8_t NUMChildren = 0;
FieldData myDataFields[NUMFields];
SerialDataInterface * myDataChildren[NUMChildren];
public:
MyBlinkLed(const char* name,uint8_t ledPin,uint32_t onInterval ,uint32_t offInterval);
};

#endif /* MYBLINKLED_H_ */

NUMFields = 5 states there are 5 fields I want in the "kind of memory dump". We are talking about integers, floats, strings ...
NUMChildren = 0; states there are nu children. Children are object derived from SerialDataInterface.
The rest of the private section is always the same is is used to correctly allocate memory.
MyBlinkLed(const char* name,uint8_t ledPin,uint32_t onInterval ,uint32_t offInterval);
Is exactly the same as
BlinkLed(uint8_t ledPin,uint32_t onInterval ,uint32_t offInterval);
Except for I added a name we can use in the serial monitor to reference this particular instance of the class.

If we look at MyBlinkLed source we get

#include "MyBlinkLed.h"

MyBlinkLed::MyBlinkLed(const char* name, uint8_t ledPin,uint32_t onInterval ,uint32_t offInterval)
:BlinkLed( ledPin, onInterval ,offInterval)
{

myDataFields[0].set(name, F("myOnInterval"),MOD_WRITE|MOD_SAVE,&myOnInterval);
myDataFields[1].set(myDataFields[0].myClassName, F("myOffInterval"),MOD_WRITE|MOD_SAVE,&myOffInterval);
myDataFields[2].set(myDataFields[0].myClassName, F("myLedState"),0,&myLedState);
myDataFields[3].set(myDataFields[0].myClassName, F("myPreviousMillis"),0,&myPreviousMillis);
myDataFields[4].set(myDataFields[0].myClassName, F("myLedPin"),0,&myLedPin);

SerialDataInterface::myFields = myDataFields;
myNumFields = NUMFields;
myNumChildren = NUMChildren;
myChildren = myDataChildren;
}

This is some hocuspocus code that links the variables to the names of the 5 fields and to the activities you can do with them.
The first line states that the string "myOnInterval" refers to the variable myOnInterval.
MOD_WRITE|MOD_SAVE states that this variable can be changed by the SET command and MOD_SAVE states that the current value can be saved in EEPROM with the "SAVE" command.
If we assume that name is "led" we can change the value of myOnInterval by sending the following string followed by CR to Arduino.
SET led.myOnInterval=3456
If we want to save this value so that next time Arduino starts working it will use this value we send
SAVE

The next 4 lines are doing the same for the other fields. Note that if you see lots of garbage in the serial moniotor you probably made a mistake here or NUMFields is wrong.

The last 4 lines are always the same when the class doesn't have children.

Where are we?
We have a class that is able to read line by line from the serial monitor.
We have a class that does what we want to do BlinkLed.
We have a class that describes the "kind of memory dump" of BlinkLed.
What we now need is a class that handles the serial monitor line by line and links it to the memory dump.
This class is called SerialCommunicator.

So lets look at the sketch code:
#include "SerialStringReader.h"
#include "SerialCommunicator.h"
#include "MyBlinkLed.h"
#include "BlinkLed.h"
#include "SerialDataInterface.h"
const char * mySketchName="ssrDemo Part 2";

SerialCommunicator mySerialCommunicator(A5);
MyBlinkLed led13("BuildInLed",LED_BUILTIN,500,2000);


//The setup function is called once at startup of the sketch
void setup()
{
Serial.begin(9600);
led13.setup();
mySerialCommunicator.setup(&led13);
}

// The loop function is called in an endless loop
void loop()
{
mySerialCommunicator.loop();
led13.loop();
}


leds go over it line by line
const char * mySketchName="ssrDemo Part 2";
The SerialCommunicator needs a name for the program. this is just a display name.
SerialCommunicator mySerialCommunicator(A5);
This line replaces SerialStringReader mySerialReader;. With this code you need to connect pin A5 to reset if you want Arduino to reset when you send "RESET".
MyBlinkLed led13("BuildInLed",LED_BUILTIN,500,2000);
Replaces BlinkLed led13(LED_BUILTIN,500,2000);. So we added a name for reference in the serial monitor.
The next difference is
mySerialCommunicator.setup(&led13);
This used to be
mySerialReader.setup();
As there is only one object in the "kind of memory dump" we simply pass this object. Note that his object can have children. Therefore there you can always create 1 object corresponding to the "kind of memory dump".
And finally I deleted the echoing of the serial monitor.

If you downloaded the libraries, compiled the sketch and uploaded the sketch. You will see ..... that the led is not blinking....
open a serial monitor and send the SET command.
SET will show you all the variables that you can change in the command format.
On my board this gives
SET Admin.ResetCount=10
SET Admin.logLevel=255
SET Admin.RestartDelay=65535
SET Admin.DelaybetweenLogs=65535
SET BuildInLed.myOnInterval=4294967295
SET BuildInLed.myOffInterval=4294967295
As you can see BuildInLed.myOnInterval is a huge number. This explains why trhe led is not blinking.
Set it to 2000milis with the following command
SET BuildInLed.myOnInterval=2000
and also give a nice off interval with
SET BuildInLed.myOffInterval=5000

Now the led is blinking again.
You are probably thinking "We have set the intervals in the code. How did they get lost?"
Well we have indeed set the values but we also have overwritten them later on.
Remember we said that myOnInterval was MOD_WRITE|MOD_SAVE.
MOD_WRITE means we enable the SET command on this fields.
MOD_SAVE means we can save the value to EEPROM. It is no use saving the value when you do not read it.
So when we called mySerialCommunicator.setup(&led13); The value was replaced by what is in EEPROM and that will be different based on the history of the board.
Send the SAVE command and reset the board.
Run the SET command again and the values should be OK now.

The Admin stuff is the memory dump of mySerialCommunicator.
ResetCount tells you how many times the board has been reset.
logLevel is a flag telling wether log is on or off. Bit 0 is used for serial monitor logging. So in my case serial monitoring is on.
RestartDelay is a delay time before restart is triggered.
I put this on 850
DelaybetweenLogs tells how many times the serial monitor will get a logging. I mostly start with 1000 meaning every second the serial monitor will get a line with the "kind of memory dump" in a csv line style.
To know what is what dump the header with the LOG HEADER command
LOG VALUE;15;255;65535;65535;730022;0;789;4294967295;4294967295;0;0;13;
>>Send to /dev/ttyUSB0: "LOG HEADER"<<
LOG HEADER;Admin.ResetCount;Admin.logLevel;Admin.RestartDelay;Admin.DelaybetweenLogs;Admin.LoopCounter;Admin.AveragebetweenLoops;Admin.MaxbetweenLoops;BuildInLed.myOnInterval;BuildInLed.myOffInterval;BuildInLed.myLedState;BuildInLed.myPreviousMillis;BuildInLed.myLedPin;

If you understood all this you are up to the next episode: "controlling the serial monitor with an openwrt"


  • Comments(0)//blog.baeyens.it/#post8