Part II: All Pin Interrupt method for RC in Arduino

I hope you are already aware of the basics of the RC communication and Hardware connection with the Arduino. If you are not, then just have a quick look at the previous blog in the series… 🙂

After looking into the problems of the polling method, The second method to interface the RC is Interrupt method. Well, as you know there are only two external hardware interrupts available in Arduino boards like Uno, Dueminalove etc.. (Ofcourse, Due is an exception 😛 ). For further clarification on this topic, click for Interrupts. I am taking Arduino Uno as a typical example here.

For interfacing all the six channels of RC you need 4 more interrupts. What can we do. Obviously we have to go for the software interrupts.

Here comes the PinChangeInterrupt for the rescue…

What are Pin Change interrupts? The ATmega processor has two different kinds of interrupts: “external”, and “pin change”. There are only two external hardware interrupt pins, INT0 and INT1, and they are mapped to Arduino pins 2 and 3. These interrupts can be set to trigger on RISING or FALLING signal edges, or on low level. Being hardware interrupts, they are very fast.

On the other hand the pin change interrupts can be enabled on any or all of the Arduino’s signal pins (Uno/Duemilanove/Nano). They are triggered equally on RISING or FALLING signal edges, so it is up to the interrupt code to set the proper pins to receive interrupts, to determine what happened (which pin? …did the signal rise, or fall?), and to handle it properly. Furthermore, the pin change interrupts are grouped into 3 “port”s on the MCU, so there are only 3 interrupt vectors (subroutines) for the entire body of 20 pins. This makes the job of resolving the action on a single interrupt even more complicated. The interrupt routine should be fast, but more the complication, lesser is the speed. The PinChangeInt library is designed to handle the Arduino’s pin change interrupts as quickly and reasonably as possible.

Well, how can you use it?? This is just a little finger’s work (literally :P)

1. Download the library from this link.

2. Extract the zip to the Arduino library folder on your computer.

3. Include the header file in the sketchbook.

4. Use it as normal interrupt function.

I used pinchangeint-v1.72, which contained 3 folders: PcChangeInt, cppfix,MemoryFree.

The skeleton sketchbook works like this after the inclusion of PcIntChange library.

PcIntChange Demonstration

Now the RC interfacing part…

We need to define the pinchange Interrupt for all the 6 pins to which channels are attached.

This is the code to get the value of the 1 channel to help you understand the code flow..

 

</pre>
//This code is just for one channel, to make you understand the code flow
//By: Shantanu Sharma
//Date: 23/10/2013.
//contact me at : shantanu.785@gmail.com

#include <PinChangeInt.h>
#include <PinChangeIntConfig.h>

int led = 13;
int ch6_pin=11;
//Global variables to hold the value of pulse width on ch6
volatile uint16_t ch6_start=0, ch6_global_count=0;
volatile uint8_t flag=LOW;//global flag
volatile uint8_t ch6_global_flag=LOW;//global flag

void setup()
{
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
Serial.begin(9600);
PCintPort::attachInterrupt(ch6_pin,ch6_count,CHANGE); //calling ch6_count as ISR
Serial.println("press the button");
}

// the loop routine runs over and over again forever:
void loop() {
// Global variables must not be used inside a loop as their
// value can change at any time. So we need to store those
// values in local values and should use the local values
// for computation, updating them at the start of every loop.

//use of volatile is to tell the compiler not to optimise
//the value of the variable,
//that it can change at any time.
volatile static uint16_t ch6_static_count;//local count
volatile static uint8_t updateflags;//lcoal flag
volatile static uint8_t ch6_update_flag;//lcoal flag
//if flag is HIGH
if(flag)
{
//during the loop, no interrupts should arise to avoid the nesting of interrupts,
//which can affect the process.
noInterrupts();
//update all the local values
updateflags=flag;
ch6_update_flag=ch6_global_flag;
if(ch6_update_flag)
{
ch6_static_count=ch6_global_count;
}

// use this ch6_static_count for your purpose.
Serial.print("ch6: ");
Serial.println(ch6_static_count);// use this value for your need
Serial.print("\t");

ch6_global_count=0;
ch6_global_flag=0;
ch6_update_flag=0;

flag=0;
interrupts();
}
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
delay(200); // wait for a second
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
delay(200);
}
void ch6_count()
{
// to calculate the width of the pulse, we need to first check
//whether pulse is HIGH or LOW,
//for a low pulse, we should wait for it to be high

//if Pulse is already High, start the timer. And when the
//pulse goes low again, Subtract the current timer reading
// from the previous one to get the value of Pulse Width.

if(digitalRead(ch6_pin)==HIGH)
{
ch6_start= micros();
}
else
{
//subtracting to get the pulse width
ch6_global_count=(uint16_t)(micros()-ch6_start);
flag=HIGH;
ch6_global_flag=HIGH;
}
}

The program has been explained with the comments. If you have any doubts, comment below..

The following is the code for getting the value of all 6 channels of RC. The code looks lengthy but it is very easy and repetitive. However, you should read the above code for the sake of understanding.

</pre>
//This is the full code for RC
//By: Shantanu Sharma
//Date: 23/10/2013.
//contact me at : shantanu.785@gmail.com
#include <PinChangeInt.h>
#include <PinChangeIntConfig.h>

int led = 13;
int ch6_pin=11;
int ch5_pin=10;
int ch4_pin=9;
int ch3_pin=8;
int ch2_pin=7;
int ch1_pin=6;
// global values for all the channels
volatile uint16_t ch6_start=0, ch6_global_count=0;
volatile uint16_t ch5_start=0, ch5_global_count=0;
volatile uint16_t ch4_start=0, ch4_global_count=0;
volatile uint16_t ch3_start=0, ch3_global_count=0;
volatile uint16_t ch2_start=0, ch2_global_count=0;
volatile uint16_t ch1_start=0, ch1_global_count=0;

volatile uint8_t flag=LOW;//global flag

volatile uint8_t ch6_global_flag=LOW;//global flag
volatile uint8_t ch5_global_flag=LOW;//global flag
volatile uint8_t ch4_global_flag=LOW;//global flag
volatile uint8_t ch3_global_flag=LOW;//global flag
volatile uint8_t ch2_global_flag=LOW;//global flag
volatile uint8_t ch1_global_flag=LOW;//global flag

// the setup routine runs once when you press reset:
void setup()
{
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
Serial.begin(9600);
// ISR for all channels
PCintPort::attachInterrupt(ch6_pin,ch6_count,CHANGE);
PCintPort::attachInterrupt(ch5_pin,ch5_count,CHANGE);
PCintPort::attachInterrupt(ch4_pin,ch4_count,CHANGE);
PCintPort::attachInterrupt(ch3_pin,ch3_count,CHANGE);
PCintPort::attachInterrupt(ch2_pin,ch2_count,CHANGE);
PCintPort::attachInterrupt(ch1_pin,ch1_count,CHANGE);
Serial.println("press the button");
}

// the loop routine runs over and over again forever:
void loop() {
volatile static uint16_t ch6_static_count;//local count
volatile static uint16_t ch5_static_count;//local count
volatile static uint16_t ch4_static_count;//local count
volatile static uint16_t ch3_static_count;//local count
volatile static uint16_t ch2_static_count;//local count
volatile static uint16_t ch1_static_count;//local count

volatile static uint8_t updateflags;//lcoal flag
volatile static uint8_t ch6_update_flag;//lcoal flag
volatile static uint8_t ch5_update_flag;//lcoal flag
volatile static uint8_t ch4_update_flag;//lcoal flag
volatile static uint8_t ch3_update_flag;//lcoal flag
volatile static uint8_t ch2_update_flag;//lcoal flag
volatile static uint8_t ch1_update_flag;//lcoal flag

if(flag)
{
noInterrupts();
updateflags=flag;
ch6_update_flag=ch6_global_flag;
ch5_update_flag=ch5_global_flag;
ch4_update_flag=ch4_global_flag;
ch3_update_flag=ch3_global_flag;
ch2_update_flag=ch2_global_flag;
ch1_update_flag=ch1_global_flag;

if(ch6_update_flag)
{
ch6_static_count=ch6_global_count;
}
if(ch5_update_flag)
{
ch5_static_count=ch5_global_count;
}
if(ch4_update_flag)
{
ch4_static_count=ch4_global_count;
}
if(ch3_update_flag)
{
ch3_static_count=ch3_global_count;
}
if(ch2_update_flag)
{
ch2_static_count=ch2_global_count;
}
if(ch1_update_flag)
{
ch1_static_count=ch1_global_count;
}
// Serial.print("ch6: ");
Serial.println(ch6_static_count);
// Serial.print("\t");

// Serial.print("ch5: ");
Serial.println(ch5_static_count);
// Serial.print("\t");

// Serial.print("ch4: ");
Serial.println(ch4_static_count);
// Serial.print("\t");

// Serial.print("ch3: ");
Serial.println(ch3_static_count);
// Serial.print("\t");

// Serial.print("ch2: ");
Serial.println(ch2_static_count);
// Serial.print("\t");

// Serial.print("ch1: ");
Serial.println(ch1_static_count);
Serial.print("\n");

ch6_global_count=0;
ch6_global_flag=0;
ch6_update_flag=0;

ch5_global_count=0;
ch5_global_flag=0;
ch5_update_flag=0;

ch4_global_count=0;
ch4_global_flag=0;
ch4_update_flag=0;

ch3_global_count=0;
ch3_global_flag=0;
ch3_update_flag=0;

ch2_global_count=0;
ch2_global_flag=0;
ch2_update_flag=0;

ch1_global_count=0;
ch1_global_flag=0;
ch1_update_flag=0;
flag=0;
interrupts();

//use all the ch*_static_count for computation here.
}
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
delay(200); // wait for a second
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
delay(200);
}
void ch6_count()
{
//Serial.println(millis());
if(digitalRead(ch6_pin)==HIGH)
{
ch6_start= micros();
}
else
{
ch6_global_count=(uint16_t)(micros()-ch6_start);
flag=HIGH;
ch6_global_flag=HIGH;
}
}
void ch5_count()
{
//Serial.println(millis());
if(digitalRead(ch5_pin)==HIGH)
{
ch5_start= micros();
}
else
{
ch5_global_count=(uint16_t)(micros()-ch5_start);
flag=HIGH;
ch5_global_flag=HIGH;
}
}
void ch4_count()
{
//Serial.println(millis());
if(digitalRead(ch4_pin)==HIGH)
{
ch4_start= micros();
}
else
{
ch4_global_count=(uint16_t)(micros()-ch4_start);
flag=HIGH;
ch4_global_flag=HIGH;
}
}
void ch3_count()
{
//Serial.println(millis());
if(digitalRead(ch3_pin)==HIGH)
{
ch3_start= micros();
}
else
{
ch3_global_count=(uint16_t)(micros()-ch3_start);
flag=HIGH;
ch3_global_flag=HIGH;
}
}
void ch2_count()
{
//Serial.println(millis());
if(digitalRead(ch2_pin)==HIGH)
{
ch2_start= micros();
}
else
{
ch2_global_count=(uint16_t)(micros()-ch2_start);
flag=HIGH;
ch2_global_flag=HIGH;
}
}
void ch1_count()
{
//Serial.println(millis());
if(digitalRead(ch1_pin)==HIGH)
{
ch1_start= micros();
}
else
{
ch1_global_count=(uint16_t)(micros()-ch1_start);
flag=HIGH;
ch1_global_flag=HIGH;
}
}

DO WHATEVER YOU WANT TO DO WITH THE VALUES OF RC NOW.. Hurray !!!!

Advertisements

About Shantanu Sharma

Currently working as Software R&D member in Samsung R&D India.

Posted on October 31, 2013, in 8-Bit Embedded World, Projects and tagged , , , , , , . Bookmark the permalink. Leave a comment.

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