IOT Holiday Lights, Projects, Tutorials & Guides

Writing a protocol on Arduino on Serial Interrupts – The Tree Controller Code

Preface

My project for the Internet of Holoday lights was based around our living room which was not very livable. It was a mess and with the upcoming holidays I wanted to set the living room in such a way that it would be suitable for entertaining guests. Additionally I wanted to accomplish the above mentioned in such a way that the holiday lighting becomes part of the living room and I don’t need to remove it after the holidays. Hence the concept of Dynamic Living-room Lighting.

In this post while I wait for my video to upload, I explain the code for the tree.

The problem

The basic issue that I was facing is the ability to connect two pieces of my project which is the YUN and the Tree together. I initially though of using a wireless route but in the end, since I needed to send a direct audio line to the tree anyways, hence I chose to use the wired approach and an old school way of doing things on it. There are a couple of methods of doing what I am doing like libraries and stuff and any suggestions are welcome.

The Approach

My approach was to build in two steps.
Step 1. Build the communication
Step 2. Build the activity functions around the communication.
I will briefly explain the code for both in the next few sections.

The communications code

I built the communications part on top of the serial interface of the arduino. I generally use the interrupts system in any microcontroller since it makes sure I ‘don’t wanna miss a thinngg'(-Aerosmith). Sorry about that pun.
Anyways I start with the example code on the arduino and I use the Serial Event example

String inputString = ""; // a string to hold incoming data
boolean stringComplete = false; // whether the string is complete
+ expand sourceview plain
void setup() {
// initialize serial:
Serial.begin(9600);
// reserve 200 bytes for the inputString:
inputString.reserve(200);
}


void loop() {
// print the string when a newline arrives:
if (stringComplete) {
Serial.println(inputString);
// clear the string:
inputString = "";
stringComplete = false;
}
}


/*
SerialEvent occurs whenever a new data comes in the
hardware serial RX. This routine is run between each
time loop() runs, so using delay inside loop can delay
response. Multiple bytes of data may be available.
*/
void serialEvent() {
while (Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar == '\n') {
stringComplete = true;
}
}
}

Here you can see that there is a function called serialEvent() which executes automatically every time the arduino receives a character. There are two global variables that can be accessed from anywhere in the arduino program where we save the received string and a notification flag that a string was completely received. BUT I don’t need that so I start by deleting way the code in the functions and write my own.

The serialEvent is supposed to be triggered everytime I get a single byte over the UART and hence the code becomes something like…

void serialEvent() {
while (Serial.available()) {
// Read a char
char inChar = (char)Serial.read();
if(inChar==':'){ // Start New Frame
memset(ptr, 0, FRAMESIZE);
inFrame=true;
myIndex=0;
}
if(inFrame==true && myIndex<FRAMESIZE){ // Add a byte
*(ptr+myIndex)=inChar;
myIndex++;
}
if(myIndex==FRAMESIZE){
inFrame=false;
if(inChar=='#')
memcpy(&myFrame, ptr, FRAMESIZE);
}
}
}

In my code, I have a global flag inFrame which tells me if I am in between frame receives. The reason why I have it as a global and not a static is because I later want to implement a timer and a time out which means that if it takes too long to receive a complete frame then prolly something is wrong and I need to discard the data because something went wrong.
In this code I simply wait for ‘:’ which is my start of frame and then use memset to initialize the space with 0s and set some flags. In the next iteration, the function will be ‘inFrame’ and hence it will copy the data to the memory. I understand pointers so I just use that instead of the dozen other methods. I also check for my maxFrameSize since my protocol has a fixed frame size. I can use a variable frame size too but maybe some other day.
In the end if the received data matches the frame size, we check for the endofframe which is a ‘#’. Everything in between can be a ascii character or anthing else but our code does not care about that. The question is what is that pointer pointing to?

The protocol

I made a structure for my protocol and it’s quite simple.

struct sFrame{
char cStart; // Expect :
char cMode; // A-Audio, M-Manual with RGB, P-Pattern
char cRed;
char cGreen;
char cBlue;
char cEnd;
};

As you can see that there are char type variables for everything. These can be replaced but again not our motive right now. In the global space, I do the following.

struct sFrame myFrame, buffer; // Object to store the frame
char *ptr = (char*)&buffer; // Point to the object

This creates an object without using the heap (malloc) since I will need a fixed size throughout the lifetime of my system. Next I create a pointer to this buffer BUT cast it into a char type. This makes sure when I ptr++, I jump to the next char in my structure. Easy! But how do I use this?

The Loop

The code for the loop is given below.

void loop() {
// print the string when a newline arrives:

if(myFrame.cMode=='A'){
//Serial.println("Audio Mode");
hue0 = constrain(map(analogRead(channel), 0, 400, 0, 255), 0, 255); // Read Audio
uint32_t color0 = Wheel(hue0);
//Shift the current values.
for (i = 0; i<NUMPIXELS; i++){
data_array[i+1] = data_array[i];
}
data_array[0] = color0;
for(i=0; i<NUMPIXELS; i++){
pixels.setPixelColor(i, data_array[i]);
pixels.show(); // This sends the updated pixel color to the hardware.
}
}else if(myFrame.cMode=='M'){ // Manual mode
for(i=0; i<NUMPIXELS; i++){
pixels.setPixelColor(i, pixels.Color(myFrame.cGreen, myFrame.cRed, myFrame.cBlue));
pixels.show(); // This sends the updated pixel color to the hardware.
}
}else if(myFrame.cMode=='P' && myFrame.cRed==0x00){
rainbowCycle(20);
}else if(myFrame.cMode=='P' && myFrame.cRed==0x01){
colorWipe(pixels.Color(240, 0, 0), 200); // Red
colorWipe(pixels.Color(0, 240, 0), 200); // Green
colorWipe(pixels.Color(0, 0, 240), 200); // Blue
colorWipe(pixels.Color(240, 240, 0), 200); // Red
colorWipe(pixels.Color(0, 240, 240), 200); // Green
colorWipe(pixels.Color(240, 0, 240), 200); // Blue
}
}

In this example, I use the functions from Adafruit’s NeoPixel Library to implement the patterns. When in the loop, I check for the mode settings. If its A then so something and if M then do something and if P then do something else. The serial interrupt takes care of serial communication in the background. Since I have created simple objects for the structure hence I can access the member functions with the . operator. Nothing to it.

Conclusion

I wanted to write a short article to explain the working of asynchronous events on a microcontroller and here it is. This is the simplest possible implementation and you can expand it as you like. There is no library code size since there is no library and I hope you got something while reading this. Any suggestions are most welcome and I if you do a project and use any snippet, just say Hi in the comments.

Thanks,
IP

Advertisements

2 thoughts on “Writing a protocol on Arduino on Serial Interrupts – The Tree Controller Code”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s