OI-DEMO Input/Output

Goals

  • Introducing Environment Installation

  • Introducing Openindus modules : OI-Core and OI-Mixed

  • Read values from I²C sensor

  • Diplay info on I²C display

  • Manage input events with tasks and interrupts

  • Read analog voltages

  • Drive an RGB Led with PWM outputs

  • Drive Leds with outputs

Requirements

  • Visual Studio Code

  • VSCode Openindus extension (Recommanded)

  • SiliconLabs USB Driver installed (CP2102N - USB<->UART)

  • Understanding Start coding chapter


Description

../_images/oidemo_io.png

Wiring diagrams

Demo IO kit is wired as described below :

../_images/oi-demo_kit_entrees-sorties%5Balimentation%2Bautomate%5D.png ../_images/oi-demo_kit_entrees-sorties%5Bcapteur_et_actionneurs%5D.png

Source code details

  • Libraries declaration

    First, include all libraries needed for each sensor or output devices.

    // Peripherals libs
    #include "Adafruit_I2CDevice.h"
    #include "Adafruit_GFX.h"
    #include "Adafruit_SSD1306.h"
    #include "Adafruit_Sensor.h"
    #include "Fonts/FreeMono9pt7b.h"
    #include "Adafruit_AM2320.h"
    

  • OI Modules instances

    // First, init the master device
    OICore core;
    
    // Then add slaves devices here :
    OIMixed mixed1;
    

    These lines should be automatically created while using OpenIndus extension. It creates instances for each OI Module found on the OI-Rail.


  • Variables / constants declaration

    // Declarations for button debounce function
    hw_timer_t * timer = NULL;
    unsigned long lastDebounceTime;
    bool debounceexpired = true;
    #define DEBOUNCEDELAY   200
    

    For the button debounce function, we need a timer (hw_timer_t) and variables to use it. See below.

    // Declarations for PWM : RGB led and white led
    #define PWM_MAX_VAL     16384 // 14 bits resolution
    

    PWM_MAX_VAL define the max value for PWM functions (RGB and Led outputs)

    // Declarations for LCD display
    #define SCREEN_WIDTH    128 // OLED display width, in pixels
    #define SCREEN_HEIGHT   64 // OLED display height, in pixels
    // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
    #define OLED_RESET      -1 // Reset pin # (or -1 if sharing Arduino reset pin)
    #define SCREEN_ADDRESS  0x3D ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
    
    // declare LCD display
    Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
    // declare humidity and temperature sensor
    Adafruit_AM2320 th_sensor = Adafruit_AM2320();
    // Declare semaphore
    SemaphoreHandle_t xMutex = NULL;
    

    Constants declarations are about size of the LCD Display. For SCREEN_ADDRESS, please refer to LCD Display datasheet.

    // declare humidity and temperature sensor
    Adafruit_AM2320 th_sensor = Adafruit_AM2320();
    

    Create an instance of temperature and humidity sensor.


  • Setup() function

    This function is executed once at startup. Initialisations have to be done here.

    Serial.begin(115200);
    

    Initialise serial interface (USB) at 115200 bauds. Debug message will be displayed on a terminal software configured à 115200 bauds 8-N-1 (8 bits, Parity Even, 1 stop bit).

    // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
    if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C))
    {
        Serial.println(F("SSD1306 allocation failed"));
        for(;;); // Don't proceed, loop forever
    }
    

    LCD Display has to generate its own 3.3V, initialise internal register with this setup.

    // Show initial display buffer contents on the screen --
    // the library initializes this with an Adafruit splash screen.
    display.setFont((const GFXfont *)&FreeMono9pt7b);
    display.display();
    delay(2000); // Pause for 2 seconds
    // Clear the buffer
    display.clearDisplay();
    

    Set Font to use while displaying text. Then clear screen after Adafruit logo sequence (2 seconds long).

    // set AIN_1 to analog mode with voltage measure (potentiometer)
    mixed1.analogInputMode(AIN_1, AIN_MODE_VOLTAGE);
    mixed1.analogInputVoltageRange(AIN_1, AIN_VOLTAGE_RANGE_0_5V12 );
    // set AIN_2 to analog mode with current measure (proximity sensor)
    mixed1.analogInputMode(AIN_2, AIN_MODE_CURRENT);
    

    Initialize analog inputs :

    • OI-Mixed[AIN1] is wired to the potentiometer so we specify this input as an analog voltage mode.

    • As potentiometer is supply by 5V, OI-Mixed[AIN1] is set to a range from 0 - 5.12V to get full scale resolution of ADC.

    • OI-Mixed[AIN2] is wired to 4-20mA sensor (proximity sensor), so we specify this input as an current input.

    // set PWM outputs for RGB led
    mixed1.outputMode(DOUT_1, DOUT_MODE_PWM );   // Red Led
    mixed1.outputMode(DOUT_2, DOUT_MODE_PWM );   // Green led
    mixed1.outputMode(DOUT_3, DOUT_MODE_PWM );   // Blue led
    

    Set PWM ouputs for RGB LED : OI-Mixed[DOUT_x]. Each led of the RGB LED is driven by a PWM to set luminosity of each color individualy.

    // set PWM frequency
    mixed1.setPWMFrequency(DOUT_1, 100);
    mixed1.setPWMFrequency(DOUT_2, 100);
    mixed1.setPWMFrequency(DOUT_3, 100);
    

    Set frequency of each PWM output. For RGB led, 100 Hz will be enough to avoir retinal persistence.

    // set all RGB leds off
    mixed1.setPWMDutyCycle(DOUT_1, 0);
    mixed1.setPWMDutyCycle(DOUT_2, 0);
    mixed1.setPWMDutyCycle(DOUT_3, 0);
    

    By default, set cycle to 0 to shutdown RGB leds at startup.

    // set PWM outputs for white led
    mixed1.outputMode(DOUT_4, DOUT_MODE_PWM );
    // set PWM frequency
    mixed1.setPWMFrequency(DOUT_4, 100);
    // set white led off
    mixed1.setPWMDutyCycle(DOUT_4, 0);
    

    Proceed to same configuration for the white Led wired on OI-Mixed[DOUT_4].

    core.attachInterrupt(DIN_1, displaymodechange, RISING_MODE, NULL );
    

    This function configures an interrupt : a rising event on OI-Core[DIN_1] will call displaymodechange() function.

    core.attachInterrupt(DIN_2, blue_led, CHANGE_MODE, NULL );
    

    This function configures an interrupt : a rising or falling event on OI-Core[DIN_2] will call blue_led() function.

    xTaskCreate(measuredistance, "Measure distance", 20000, NULL, 1, NULL);
    

    This function create a task measuredistance() that runs in parallel of Loop() function. Its priority is set to 1.

    xTaskCreate(rgb_pot, "rgb_pot", 10000, NULL, 2, NULL);
    

    This function create a task rgb_pot() that runs in parallel of Loop() function. Its priority is set to 2, that is an higher priority than measuredistance().

    Serial.println(F("Setup done."));
    

    When everything is initialized, we can send a debug message.


  • Loop() function

    void loop(void)
    {
    
        switch(display_mode)
        {
            case 0 :
            default:
                displaytemperature();
                break;
    
            case 1 :
                displayhumidity();
                break;
    
            case 2 :
                displaydistance();
                break;
        }
    
        delay(100);
    }
    

    The main function is looping on the management of the rolling menu that changes display content on each button action. Interrupt function attached to the button event incremets ‘display_mode’ variable.

    ‘delay(100)’ is strongly recommended in the loop() function to let operating system execute its own task.


  • Others functions called in Setup() and Loop() functions

    • displaytemperature()

      void displaytemperature(void)
      {
          display.clearDisplay();
          display.setTextSize(1);
          display.setTextColor(WHITE);
          display.setCursor(0,25);
          display.println(F("Temperature: "));
          display.setCursor(25,45);
          display.print(th_sensor.readTemperature(), 2);
          display.println(F(" °C"));
          display.display();
      }
      

      This function is called periodically in the Loop() function. Temperature is get from sensor and displayed on LCD.

    • displayhumidity()

      void displayhumidity(void)
      {
          display.clearDisplay();
          display.setTextSize(1);
          display.setTextColor(WHITE);
          display.setCursor(15,25);
          display.println(F("Humidite: "));
          display.setCursor(25,45);
          display.print(th_sensor.readHumidity(), 2);
          display.println(F(" %"));
          display.display();
      }
      

      This function is called periodically in the Loop() function. Humidity is get from sensor and displayed on LCD.

    • displaydistance()

      void displaydistance(void)
      {
          display.clearDisplay();
          display.setTextSize(1);
          display.setTextColor(WHITE);
          display.setCursor(15,25);
      
          display.println(F("Distance: "));
      
          // meandistance is computed periodically in measuredistance()
          if (meandistance <= 10)
          {
              display.setCursor(25,45);
              display.println(F(" < 10 mm"));
              meandistance = 10;
          }
          else if (meandistance >= 100)
          {
              display.setCursor(25,45);
              display.println(F(" > 100 mm"));
              meandistance = 100;
          }
          else
          {
              display.setCursor(25,45);
              display.print(meandistance, 2);
              display.println(F(" mm"));
          }
          display.display();
      }
      

      This function is called periodically in the Loop() function.

      meandistance is get from a global variable and displayed on LCD.

      meandistance is computed by measuredistance() that is a task dedicated to this measure.

    • measuredistance()

      void measuredistance(void*)
      {
          int nSAMPLES = 10;
          std::vector<float> rdist;
          rdist.resize(nSAMPLES);
      
          // infinite loop for capturing distance
          while(1)
          {
              // acquire multiple values of distance
              for(int i=0; i < nSAMPLES; i++)
              {
                  rdist[i] = 5.625 * mixed1.analogReadMilliAmp(AIN_2) - 12.5;
                  delay(5);
              }
      
              // compute mean distance over multiple samples
              std::sort(rdist.begin(), rdist.end());
              size_t size = rdist.size();
              if (size % 2 == 0)
              {
                  // store result in global variable, may be use in  displaydistance()
                  meandistance =  (rdist[size / 2 - 1] + rdist[size / 2]) / 2.0;
              }
              else
              {
                  // store result in global variable, may be use in  displaydistance()
                  meandistance = rdist[size / 2];
              }
      
              // set out of range value to 0-100
              if (meandistance > 100)
              {
                  meandistance = 100;
              }
              else if (meandistance < 10)
              {
                  meandistance = 10;
              }
      
              // PWM duty cycle resolution is 2^14 . remapping is reversed to increase luminosity while decreasing distance (led is off when distance is > 100 mm)
              // remap meandistance to 0-16384 pwm range
              int pwmwhiteled = map(meandistance, 10, 100, PWM_MAX_VAL, 0);
              // adjust white led intensity
              mixed1.setPWMDutyCycle(DOUT_4, pwmwhiteled);
      
              delay(5);
          }
      }
      

      This function compute median value of distance over 100 acquisitions in an infinite loop (while(1)).

      // acquire multiple values of distance
      for(int i=0; i < nSAMPLES; i++)
      {
          rdist[i] = 5.625 * mixed1.analogReadMilliAmp(AIN_2) - 12.5;
          delay(5);
      }
      

      With this code, a table a 100 values is filled with an analog read of OI-mixed[AIN_2] input. Analog read is converter to millimeter with a formula.

      // compute mean distance over multiple samples
      std::sort(rdist.begin(), rdist.end());
      size_t size = rdist.size();
      if (size % 2 == 0)
      {
          // store result in global variable, may be use in  displaydistance()
          meandistance =  (rdist[size / 2 - 1] + rdist[size / 2]) / 2.0;
      }
      else
      {
          // store result in global variable, may be use in  displaydistance()
          meandistance = rdist[size / 2];
      }
      

      A median value is better than a mean value because it cancels errors from sensor. The median is the value in the middle of a data set, meaning that 50% of data points have a value smaller or equal to the median and 50% of data points have a value higher or equal to the median. To compute the median value, an easy method consist to sort values of a table and read the value in the middle of this table.

      // set out of range value to 0-100
      if (meandistance > 100)
      {
          meandistance = 100;
      }
      else if (meandistance < 10)
      {
          meandistance = 10;
      }
      

      Proximity sensor has a measure range given for 10mm to 100 mm. To stay in this range where sensor has garanted measure, we limit value to this range.

      // PWM duty cycle resolution is 2^14 . remapping is reversed to increase luminosity while decreasing distance (led is off when distance is > 100 mm)
      // remap meandistance to 0-16384 pwm range
      int pwmwhiteled = map(meandistance, 10, 100, PWM_MAX_VAL, 0);
      // adjust white led intensity
      mixed1.setPWMDutyCycle(DOUT_4, pwmwhiteled);
      
      delay(5);
      

      After median value is computed, the white led PWM output is update to adjuste luminosity. The lower distance, the lower luminosity. map() function is useful to convert a range value to an other one. In this code we convert [10-100] range to [16384-0] (PWM_MAX_VAL) range. It allows to convert distance to PWM equivalent value and inverting value.

    • displaymodechange()

      void displaymodechange(void*)
      {
          // if debounce time is expired
          if( (millis() - lastDebounceTime) >= DEBOUNCEDELAY)
          {
              // we can enable again new event
              debounceexpired = true;
          }
      
          // if debounce time is expired, we can accept a new button event
          if (debounceexpired == true)
          {
              // same timestamp of event
              lastDebounceTime = millis();
              // reset debounceexpired flag
              debounceexpired = false;
              // update display mode
              display_mode++;
              if (display_mode >= 3)
              {
                  display_mode = 0;
              }
          }
      }
      

      displaymodechange() is called on every rising event of push button. This button has to change the value of display_mode variable in order to change value displayed on LCD.

      Mechanical buttons make electricals bounces that can cause unwanted multiple detections. To avoid these unwanted detection, we can add a debounce function. This debounce function use millis() (milliseconds elapsed since startup). At the first rising event of button, we store millis() in a variable. Since the debounce time is not elapsed , we do not consider a rising event as a new event.

    • blue_led()

      void blue_led(void*)
      {
          static int inductive_sensor;
          inductive_sensor = core.digitalRead(DIN_2);
          if (inductive_sensor == 1)
          {
              core.digitalWrite(DOUT_3, HIGH);
          }
          else
          {
              core.digitalWrite(DOUT_3, LOW);
          }
      }
      

      blue_led() is called on every change of magnetic sensor state. This function set blue led ouput (OI-Mixed[DOUT_3]) following inductive sensor output state (OI-Mixed[DIN_2]).

    • rgb_pot()

      void rgb_pot(void*)
      {
          // Values for each pin of the RGB LED.
          int currentColorValueRed = 0;
          int currentColorValueGreen = 0 ;
          int currentColorValueBlue = 0 ;
          int potPinValue;
      
          while(1)
          {
              // read potentiometer value (0 - 4096)
              // and convert it to a RGB range (0 - PWM_MAX_VAL).
              potPinValue = map(mixed1.analogRead(AIN_1), 0, 4096, 0, PWM_MAX_VAL);
      
              // Explanation of the code can be found on this link :
              // https://electronics.stackexchange.com/questions/240185/controlling-color-and-brightness-of-rgb-led-strip-using-one-potentiometer
              // Note: 1/6th of 255 is 42.5
      
              if (potPinValue <= (PWM_MAX_VAL * 1/6))
              {
                  currentColorValueRed = PWM_MAX_VAL;
                  currentColorValueGreen = potPinValue * 6;
                  currentColorValueBlue = 0;
              }
      
              if ((potPinValue > (PWM_MAX_VAL * 1/6)) && (potPinValue <= (PWM_MAX_VAL * 2/6)))
              {
                  currentColorValueRed = PWM_MAX_VAL - (potPinValue - (PWM_MAX_VAL * 1/6)) * 6;
                  currentColorValueGreen = PWM_MAX_VAL;
                  currentColorValueBlue = 0;
              }
      
              if ((potPinValue > (PWM_MAX_VAL * 2/6)) && (potPinValue <= (PWM_MAX_VAL * 3/6)))
              {
                  currentColorValueRed = 0;
                  currentColorValueGreen = PWM_MAX_VAL;
                  currentColorValueBlue = (potPinValue - (PWM_MAX_VAL * 2/6)) * 6;
              }
      
              if ((potPinValue > (PWM_MAX_VAL * 3/6)) && (potPinValue <= (PWM_MAX_VAL * 4/6)))
              {
                  currentColorValueRed = 0;
                  currentColorValueGreen = PWM_MAX_VAL - (potPinValue - (PWM_MAX_VAL * 3/6)) * 6;
                  currentColorValueBlue = PWM_MAX_VAL;
              }
      
              if ((potPinValue > (PWM_MAX_VAL* 4/6)) && (potPinValue <= (PWM_MAX_VAL* 5/6)))
              {
                  currentColorValueRed = (potPinValue - (PWM_MAX_VAL* 4/6)) * 6;
                  currentColorValueGreen = 0;
                  currentColorValueBlue = PWM_MAX_VAL;
              }
      
              if ((potPinValue > (PWM_MAX_VAL* 5/6)) && (potPinValue <= (PWM_MAX_VAL* 6/6)))
              {
                  currentColorValueRed = PWM_MAX_VAL;
                  currentColorValueGreen = 0;
                  currentColorValueBlue = PWM_MAX_VAL - (potPinValue - (PWM_MAX_VAL* 5/6)) * 6;
              }
      
              // adjust RGB colors following measured potentiometer value
              mixed1.setPWMDutyCycle(DOUT_1, currentColorValueRed);
              mixed1.setPWMDutyCycle(DOUT_2, currentColorValueGreen);
              mixed1.setPWMDutyCycle(DOUT_3, currentColorValueBlue);
              delay(50);
          }
      }
      

      rgb_pot() is a task that run in an infinite loop. This loop update RGB leds color following position of the potentiometer.

      potentiometer value is read on OI-Mixed[AIN_1] input. This analog value [0-4096] is converted with map() function into PWM range value [0-16384].

      To drive each color (Red, Green and Blue) from a single value, the principle is to convert into six quadrants as presented in the figure below.

      potPinValue value is divided in a sixth and then each RGB value is affected to a value as described in the figure.

      ../_images/rgb.png

Source code (full)

#include "OpenIndus.h"
#include "Arduino.h"

// Peripherals libs
#include "Adafruit_I2CDevice.h"
#include "Adafruit_GFX.h"
#include "Adafruit_SSD1306.h"
#include "Adafruit_Sensor.h"
#include "Fonts/FreeMono9pt7b.h"
#include "Adafruit_AM2320.h"

// First, init the master device
OICore core;

// Then add slaves devices here :
OIMixed mixed1;

// Declarations for button debounce function
hw_timer_t * timer = NULL;
unsigned long lastDebounceTime;
bool debounceexpired = true;
#define DEBOUNCEDELAY   200

// Declarations for PWM : RGB led and white led
#define PWM_MAX_VAL     16384 // 14 bits resolution

// Declarations for LCD display
#define SCREEN_WIDTH    128 // OLED display width, in pixels
#define SCREEN_HEIGHT   64 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET      -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS  0x3D ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32

// declare LCD display
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// declare humidity and temperature sensor
Adafruit_AM2320 th_sensor = Adafruit_AM2320();

// Variable that store current mode
int display_mode = 0;
// Declare globle variable for proximity sensor
float meandistance;


void displaymodechange(void*)
{
    // if debounce time is expired
    if( (millis() - lastDebounceTime) >= DEBOUNCEDELAY)
    {
        // we can enable again new event
        debounceexpired = true;
    }

    // if debounce time is expired, we can accept a new button event
    if (debounceexpired == true)
    {
        // same timestamp of event
        lastDebounceTime = millis();
        // reset debounceexpired flag
        debounceexpired = false;
        // update display mode
        display_mode++;
        if (display_mode >= 3)
        {
            display_mode = 0;
        }
    }
}


void blue_led(void*)
{
    static int inductive_sensor;
    inductive_sensor = core.digitalRead(DIN_2);
    if (inductive_sensor == 1)
    {
        core.digitalWrite(DOUT_3, HIGH);
    }
    else
    {
        core.digitalWrite(DOUT_3, LOW);
    }
}

void displaytemperature(void)
{
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0,25);
    display.println(F("Temperature: "));
    display.setCursor(25,45);
    display.print(th_sensor.readTemperature(), 2);
    display.println(F(" °C"));
    display.display();
}

void displayhumidity(void)
{
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(15,25);
    display.println(F("Humidite: "));
    display.setCursor(25,45);
    display.print(th_sensor.readHumidity(), 2);
    display.println(F(" %"));
    display.display();
}

void measuredistance(void*)
{
    int nSAMPLES = 10;
    std::vector<float> rdist;
    rdist.resize(nSAMPLES);

    // infinite loop for capturing distance
    while(1)
    {
        // acquire multiple values of distance
        for(int i=0; i < nSAMPLES; i++)
        {
            rdist[i] = 5.625 * mixed1.analogReadMilliAmp(AIN_2) - 12.5;
            delay(5);
        }

        // compute mean distance over multiple samples
        std::sort(rdist.begin(), rdist.end());
        size_t size = rdist.size();
        if (size % 2 == 0)
        {
            // store result in global variable, may be use in  displaydistance()
            meandistance =  (rdist[size / 2 - 1] + rdist[size / 2]) / 2.0;
        }
        else
        {
            // store result in global variable, may be use in  displaydistance()
            meandistance = rdist[size / 2];
        }

        // set out of range value to 0-100
        if (meandistance > 100)
        {
            meandistance = 100;
        }
        else if (meandistance < 10)
        {
            meandistance = 10;
        }

        // PWM duty cycle resolution is 2^14 . remapping is reversed to increase luminosity while decreasing distance (led is off when distance is > 100 mm)
        // remap meandistance to 0-16384 pwm range
        int pwmwhiteled = map(meandistance, 10, 100, PWM_MAX_VAL, 0);
        // adjust white led intensity
        mixed1.setPWMDutyCycle(DOUT_4, pwmwhiteled);

        delay(5);
    }
}

void displaydistance(void)
{
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(15,25);

    display.println(F("Distance: "));

    // meandistance is computed periodically in measuredistance()
    if (meandistance <= 10)
    {
        display.setCursor(25,45);
        display.println(F(" < 10 mm"));
        meandistance = 10;
    }
    else if (meandistance >= 100)
    {
        display.setCursor(25,45);
        display.println(F(" > 100 mm"));
        meandistance = 100;
    }
    else
    {
        display.setCursor(25,45);
        display.print(meandistance, 2);
        display.println(F(" mm"));
    }
    display.display();
}

void rgb_pot(void*)
{
    // Values for each pin of the RGB LED.
    int currentColorValueRed = 0;
    int currentColorValueGreen = 0 ;
    int currentColorValueBlue = 0 ;
    int potPinValue;

    while(1)
    {
        // read potentiometer value (0 - 4096)
        // and convert it to a RGB range (0 - PWM_MAX_VAL).
        potPinValue = map(mixed1.analogRead(AIN_1), 0, 4096, 0, PWM_MAX_VAL);

        // Explanation of the code can be found on this link :
        // https://electronics.stackexchange.com/questions/240185/controlling-color-and-brightness-of-rgb-led-strip-using-one-potentiometer
        // Note: 1/6th of 255 is 42.5

        if (potPinValue <= (PWM_MAX_VAL * 1/6))
        {
            currentColorValueRed = PWM_MAX_VAL;
            currentColorValueGreen = potPinValue * 6;
            currentColorValueBlue = 0;
        }

        if ((potPinValue > (PWM_MAX_VAL * 1/6)) && (potPinValue <= (PWM_MAX_VAL * 2/6)))
        {
            currentColorValueRed = PWM_MAX_VAL - (potPinValue - (PWM_MAX_VAL * 1/6)) * 6;
            currentColorValueGreen = PWM_MAX_VAL;
            currentColorValueBlue = 0;
        }

        if ((potPinValue > (PWM_MAX_VAL * 2/6)) && (potPinValue <= (PWM_MAX_VAL * 3/6)))
        {
            currentColorValueRed = 0;
            currentColorValueGreen = PWM_MAX_VAL;
            currentColorValueBlue = (potPinValue - (PWM_MAX_VAL * 2/6)) * 6;
        }

        if ((potPinValue > (PWM_MAX_VAL * 3/6)) && (potPinValue <= (PWM_MAX_VAL * 4/6)))
        {
            currentColorValueRed = 0;
            currentColorValueGreen = PWM_MAX_VAL - (potPinValue - (PWM_MAX_VAL * 3/6)) * 6;
            currentColorValueBlue = PWM_MAX_VAL;
        }

        if ((potPinValue > (PWM_MAX_VAL* 4/6)) && (potPinValue <= (PWM_MAX_VAL* 5/6)))
        {
            currentColorValueRed = (potPinValue - (PWM_MAX_VAL* 4/6)) * 6;
            currentColorValueGreen = 0;
            currentColorValueBlue = PWM_MAX_VAL;
        }

        if ((potPinValue > (PWM_MAX_VAL* 5/6)) && (potPinValue <= (PWM_MAX_VAL* 6/6)))
        {
            currentColorValueRed = PWM_MAX_VAL;
            currentColorValueGreen = 0;
            currentColorValueBlue = PWM_MAX_VAL - (potPinValue - (PWM_MAX_VAL* 5/6)) * 6;
        }

        // adjust RGB colors following measured potentiometer value
        mixed1.setPWMDutyCycle(DOUT_1, currentColorValueRed);
        mixed1.setPWMDutyCycle(DOUT_2, currentColorValueGreen);
        mixed1.setPWMDutyCycle(DOUT_3, currentColorValueBlue);
        delay(50);
    }
}

void setup(void)
{
    Serial.begin(115200);

    // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
    if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C))
    {
        Serial.println(F("SSD1306 allocation failed"));
        for(;;); // Don't proceed, loop forever
    }

    // Show initial display buffer contents on the screen --
    // the library initializes this with an Adafruit splash screen.
    display.setFont((const GFXfont *)&FreeMono9pt7b);
    display.display();
    delay(2000); // Pause for 2 seconds
    // Clear the buffer
    display.clearDisplay();

    // set AIN_1 to analog mode with voltage measure (potentiometer)
    mixed1.analogInputMode(AIN_1, AIN_MODE_VOLTAGE);
    mixed1.analogInputVoltageRange(AIN_1, AIN_VOLTAGE_RANGE_0_5V12 );
    // set AIN_2 to analog mode with current measure (proximity sensor)
    mixed1.analogInputMode(AIN_2, AIN_MODE_CURRENT);

    // set PWM outputs for RGB led
    mixed1.outputMode(DOUT_1, DOUT_MODE_PWM );   // Red Led
    mixed1.outputMode(DOUT_2, DOUT_MODE_PWM );   // Green led
    mixed1.outputMode(DOUT_3, DOUT_MODE_PWM );   // Blue led
    // set PWM frequency
    mixed1.setPWMFrequency(DOUT_1, 100);
    mixed1.setPWMFrequency(DOUT_2, 100);
    mixed1.setPWMFrequency(DOUT_3, 100);
    // set all RGB leds off
    mixed1.setPWMDutyCycle(DOUT_1, 0);
    mixed1.setPWMDutyCycle(DOUT_2, 0);
    mixed1.setPWMDutyCycle(DOUT_3, 0);

    // set PWM outputs for white led
    mixed1.outputMode(DOUT_4, DOUT_MODE_PWM );
    // set PWM frequency
    mixed1.setPWMFrequency(DOUT_4, 100);
    // set white led off
    mixed1.setPWMDutyCycle(DOUT_4, 0);

    core.attachInterrupt(DIN_1, displaymodechange, RISING_MODE, NULL );
    core.attachInterrupt(DIN_2, blue_led, CHANGE_MODE, NULL );
    xTaskCreate(measuredistance, "Measure distance", 20000, NULL, 1, NULL);
    xTaskCreate(rgb_pot, "rgb_pot", 10000, NULL, 2, NULL);

    Serial.println(F("Setup done."));
}

void loop(void)
{

    switch(display_mode)
    {
        case 0 :
        default:
            displaytemperature();
            break;

        case 1 :
            displayhumidity();
            break;

        case 2 :
            displaydistance();
            break;
    }

    delay(100);
}