C++ in arduino : ISR() in a class

In the last post https://whileinthisloop.blogspot.com/2016/04/c-in-arduino-interrupted-adc-with-free.html I showed you how to run the ADC in free-running mode. In this post I am going to show you how to wrap up the ISR() in a Class

I don't know if you have tried it or not but implementing ISR() in a class is a bit tricky ;)

Handling interrupts is not only a job for C or assembly language actually  C++ can also handle it. In a later post, I will show how to wrap up the ISR() with the help of some advanced concepts of c++ like virtual function. 

But in this post, I am going to show you a quick & simple way that may help you if you don't understand advanced concepts of C++. So if you are willing to design and maintain OOP concepts and want to implement your  ISR() in a class in a simple way then this post may help you.

Note: The way I am going to show is kind of mixing C & C++ concepts.

To keep our embedded context relevant, we are going to make a Sensor Class from the last post's codes,

First Let us make the declaration file (sensor.h)


#ifndef SENSOR_H_     //tells compiler to compile this class only once 
#define SENSOR_H_

#include <Arduino.h>
#include <avr/interrupt.h>

class Sensor
{
    //variables
  public:
  private:

    //functions
  public:
    Sensor();
    ~Sensor();
    void init(void);
    unsigned int readAdcValue(void);
};

#endif

you can see that there is no ISR(ADC_vect) function declaration in the header file.

now let's make the implementation file (sensor.cpp)

#include "Sensor.h"

static unsigned int adcValue; //this variable's scope is only this file 

//constructor
Sensor::Sensor()
{}

//destructor
Sensor::~Sensor()
{}
void Sensor::init(void)
{
  //initiating variables
  adcValue = 0;

  //initiating registers
  ADMUX |= (1 << REFS0); //AVCC with external capacitor at AREF pin
  ADMUX |= (1 << MUX2) | (1 << MUX0); //0101adc channel 5 selected for adc input
  ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); //prescalar 128 selected ADC clk = 125KHz
  ADCSRA |= (1 << ADEN); //adc enabled
  ADCSRA |= (1 << ADATE); // ADC Auto Trigger Enable
  ADCSRA |= (1 << ADIE); //adc interrupt enable such that interrupt will happen after each conversion
  ADCSRA |= (1 << ADSC); //conversion process begins
  sei();                 //global interrupt enabled
}

unsigned int Sensor::readAdcValue(void)
{
  return adcValue;
}


ISR(ADC_vect)       //adc interrupt service routine /tasks which will be executed by microprocessor after each conversion
{
  adcValue = ADCL;      //ADCL data register read
  adcValue += (ADCH << 8); //ADCH data register read
}

Note that the adcValue variable is a  static unsigned int type global variable & this variable gets updated in the interrupt service routine but why I have not declared this variable as a Class member variable? the answer is as 
the ISR() function is not a Class member function you won't be able to access any Class member variable in the ISR() .  

Also, note that the adcValue is a static variable which means its scope is limited to the cpp implementation file only. This pattern provides a data abstraction like private variables in a class. This is kind of implementing a C++ feature in C.

As per language pattern One may argue on the above approach but I found this simple solution working without any runtime / compile time issue but obvisously there may be better ways to implement.

1 comment:

Categories

Pages

Firmware Engineer

My photo
Works on Firmware, Embedded Linux, Smart Metering, RTOS, IoT backend

Contact Form

Name

Email *

Message *

Copyrighted by Hassin. Powered by Blogger.