1

I'm using Nmradcc.h in combination with a OLED I2C.

The nrmadcc.h is using a interrupt 0 on Pin 2, the OLED uses A4 and A5.

After initialisation of the OLED and the Function

The problem is, I can use the Funktion with the Interrupt or the OLED, Not together. But i want to. Can I stop the interrupt function with nointerrupt and than I2C and otherwise, or is there a better war?

Thanks Bert


#include <SPI.h>                  ////
#include <Wire.h>                 ////
#include <Adafruit_GFX.h>         ////
#include <Adafruit_SSD1306.h>     ////
#include <DCC_Decoder.h> 
#define kDCC_INTERRUPT 0

Adafruit_SSD1306 display(128, 64, &Wire, -1);   ////

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Fill in the number of accessories / functions you want to control
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const byte maxaccessories=1;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

typedef struct {
  int               address;          // Address to respond to
  byte              mode;             // 0=continuous, 1=oneshot, 2=flasher
  byte              output;           // State of accessory: 1=on, 0=off (for internal use only)
  int               outputPin;        // Arduino output pin
  byte              highlow;          // State of outputpin: 1=HIGH, 0=LOW
  boolean           finished;         // Memory location that says the oneshot is finished
  int               durationonMilli;  // oneshot or flasher on time in ms
  int               durationoffMilli; // oneshot or flasher off time in ms
  boolean           isAnalog;         // false=digital, true=analog, sends analogValue to out pin.
  byte              analogValue;      // pulse with modulation (pwm) value that is written to pin. Range: 0 - 255
                                        // goto http://arduino.cc/en/Reference/AnalogWrite to see which pins support analog pwm output
  unsigned long     onMilli;          // for internal use
  unsigned long     offMilli;         // for internal use
} 
DCCAccessoryAddress;
DCCAccessoryAddress accessory[maxaccessories];

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Fill in the attributes for every accessory / function
// COPY - PASTE as many times as you have functions. The amount must be same as in line 17 above!
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ConfigureDecoderFunctions() // The amount of accessories must be same as in line 26 above!
{
  accessory[0].address = 1;    // DCC address
  accessory[0].mode = 0;       // Continuous. HIGH until DCC switches the address off again.
  accessory[0].outputPin = 13; // Arduino pin where function is connected to.
  accessory[0].output = 0;     // Initial state (0 or 1) of output after startup.                                                  

  for(int i=0; i<maxaccessories; i++)
  {
    if (accessory[i].outputPin)
    {
      pinMode( accessory[i].outputPin, OUTPUT );
      // Set initial state (only for mode 0, continuous)
      if (!accessory[i].mode && accessory[i].output) digitalWrite(accessory[i].outputPin, HIGH);
      else digitalWrite (accessory[i].outputPin, LOW);
      }
    }
  }  // END ConfigureDecoderFunctions

  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  // DCC accessory packet handler 
  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  void BasicAccDecoderPacket_Handler(int address, boolean activate, byte data)
  {
    // Convert NMRA packet address format to human address
    address -= 1;
    address *= 4;
    address += 1;
    address += (data & 0x06) >> 1;

    boolean enable = (data & 0x01) ? 1 : 0;

    for (int i=0; i<maxaccessories; i++)
    {
      if (address == accessory[i].address)
      {
        if (enable) accessory[i].output = 1;
        else accessory[i].output = 0;
      }
    }
  } //END BasicAccDecoderPacket_Handler

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Setup (run once)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() 
{ 
  DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true);
  ConfigureDecoderFunctions();
  DCC.SetupDecoder( 0x00, 0x00, kDCC_INTERRUPT );
  pinMode(2,INPUT_PULLUP); //Interrupt 0 with internal pull up resistor (can get rid of external 10k)
  pinMode(13,OUTPUT);
  digitalWrite(13,LOW); //switch off Arduino led at startup
  for (int n=0; n<maxaccessories; n++) accessory[n].output = 0; //all servo's to min angle and functions to 0

  display.display();
  display.clearDisplay();

} // END setup

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Main loop (run continuous)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop()
{
  static int addr = 0;

  DCC.loop(); // Loop DCC library

  if( ++addr >= maxaccessories ) addr = 0; // Next address to test

  if (accessory[addr].output == 1)
  {
    if (accessory[addr].mode == 0) accessory[addr].highlow=1; // continuous

    if (accessory[addr].mode == 1) // oneshot
    {
      if (!accessory[addr].highlow && !accessory[addr].finished)
      {
        accessory[addr].highlow = 1;
        accessory[addr].offMilli = millis() + accessory[addr].durationonMilli;
      }
      if (accessory[addr].highlow && millis() > accessory[addr].offMilli)
      {
        accessory[addr].highlow = 0;
        accessory[addr].finished = true;
      }
    }

    if (accessory[addr].mode == 2) // flasher
    {
      if (!accessory[addr].highlow && millis() > accessory[addr].onMilli)
      {
        accessory[addr].highlow = 1;
        accessory[addr].offMilli = millis() + accessory[addr].durationonMilli;
      }
      if (accessory[addr].highlow && millis() > accessory[addr].offMilli)
      {
        accessory[addr].highlow=0;
        accessory[addr].onMilli = millis() + accessory[addr].durationoffMilli;
      }
    }

      display.setCursor(90, 50);  ////
      display.setTextSize(2);     ////
      display.print(F("ON")) ;    ////

  }
  else // accessory[addr].output == 0
  {
    accessory[addr].highlow=0;
    if (accessory[addr].mode == 1) accessory[addr].finished = false;

      display.setCursor(90, 50);  ////
      display.setTextSize(2);     ////
      display.print(F("OFF")) ;    ////

  }

  if (accessory[addr].highlow)
    {
      if (accessory[addr].isAnalog) analogWrite (accessory[addr].outputPin, accessory[addr].analogValue);
        else digitalWrite (accessory[addr].outputPin, HIGH);
    }
  else 
    {
      if (accessory[addr].isAnalog) analogWrite (accessory[addr].outputPin, 0);
        else digitalWrite( accessory[addr].outputPin, LOW);
  }
  display.display();
} //END loop

In this sample is the I2C OLED not working. When I change the spot of

Adafruit_SSD1306 display(128, 64, &Wire, -1);

and

DCC.SetupDecoder( 0x00, 0x00, kDCC_INTERRUPT );

The DCC interrupt is not working, the OLED does work.

1
  • 1
    Please edit the question if you have more information or updates.
    – VE7JRO
    Commented Jan 13, 2020 at 22:58

1 Answer 1

3

I2C requires precise timing to work. If interrupts fire while the Arduino is trying to read or write to the I2C bus, it will fail. I suspect you'll have to disable interrupts each time you read/write to the I2C bus and then re-enable them when you are done.

1
  • Thanks, so everywere were display is called i need to use nointerrupts()? Commented Jan 14, 2020 at 19:41

Not the answer you're looking for? Browse other questions tagged or ask your own question.