IR decode to contact closure - Kind of works, but trying to improve code

I’m trying to improve the code of my simple IR decoder and button pusher sketch I’ve compiled for an attiny85. The purpose of the sketch is to allow me to control 3 physical pushbuttons of an external circuit with a standard IR remote control.

My attiny85 shares a common ground with the external circuit, and the 3 normally open pushbuttons of the external circuit are wired back to my pins 0, 1 and 2. The buttons on the external board are normally ~5v, and pushing a button grounds them to 0, so my sketch needs to function the same way.

I don’t see any pullup resistors on the buttons of the external board, the buttons wire back directly to pins on an unmarked IC. For this reason I was trying to steer these pins high with the internal 20K pullups using my circuit to avoid any ambiguity, and then drop them to ground to register a button press.

//----------------------------------------------------------------------------------------------------------------------
// IR_to_Button_Press
// This program for an attiny85 uses IR codes to simulate button presses on a three normally-open pushbuttons
// Shorting pushbutton to ground registers a "press"
// IR code decoding based on the TinyPCRemote by Nathan Chantrell http://nathan.chantrell.net
//
// Licenced under the Creative Commons Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) licence:
// http://creativecommons.org/licenses/by-sa/3.0/
//----------------------------------------------------------------------------------------------------------------------


// IR sensor connected to PB4 = ATtiny85 physical pin 3
// Using #define for timing purposes per original code
#define IRpin_PIN   PINB
#define IRpin   4

#define MAXPULSE 5000     // max IR pulse length, default 5 milliseconds
#define NUMPULSES 100     // max IR pulse pairs to sample
#define RESOLUTION 2      // time between IR measurements

uint16_t pulses[NUMPULSES][2];  // pair is high and low pulse
uint8_t currentpulse = 0;       // index for pulses we're storing

const int UpButton = 2;       //  Screen UP button connected to PB2 = ATtiny85 physical pin 7
const int StopButton = 1;     //  Screen STOP button connected to PB1 = ATtiny85 physical pin 6
const int DownButton = 0;     //  Screen DOWN button connected to PB0 = ATtiny85 physical pin 5

void setup()
{
  pinMode(4, INPUT);   // Make sure IR pin is set as input
  pinMode(UpButton, INPUT);  // Putting UpButton in high impedance state to be pulled up
  pinMode(StopButton, INPUT);  // Putting StopButton in high impedance state to be pulled up
  pinMode(DownButton, INPUT);  // Putting DownButton in high impedance state to be pulled up
}

void loop()
{
  digitalWrite(UpButton, HIGH);        // Turn on internal pullup
  digitalWrite(StopButton, HIGH);      // Turn on internal pullup
  digitalWrite(DownButton, HIGH);      // Turn on internal pullup
  
  unsigned long irCode = listenForIR(); // Wait for an IR Code

  // Process the pulses to get our code
  for (int i = 0; i < 32; i++)
  {
    irCode = irCode << 1;
    if((pulses[i][0] * RESOLUTION) > 0 && (pulses[i][0] * RESOLUTION) < 500)
    {
      irCode |= 0;
    }
    else
    {
      irCode |= 1;
    }
  }

  // ---------------------------------------------------------------------------------------
  // Enter IR codes to watch for and desired outcomes this section
  // ---------------------------------------------------------------------------------------

  if (irCode == 2681863583)      // Screen Up command entered, simulate pressing 'Screen Up' pushbutton
  {
    pinMode(UpButton, OUTPUT);      // Setting UpButton as an OUTPUT gets out of high impedance mode
    digitalWrite(UpButton, LOW);      // Pull down to ground momentarily to trigger pushbutton
    delay(500);
    pinMode(UpButton, INPUT);      // Putting UpButton back in a high impedance state 
  }

  else if (irCode == 2682912415)      // Screen Stop command entered, simulate pressing 'Screen Stop' pushbutton
  {
    pinMode(StopButton, OUTPUT);      // Setting StopButton as an output
    digitalWrite(StopButton, LOW);      // Pull stop button to ground momentarily
    delay(500);
    pinMode(StopButton, INPUT);      // Putting StopButton back in a high impedance state
  }

  else if (irCode == 2683961247)      // Screen Down command entered, simulate pressing 'Screen Down' pushbutton
  {
    pinMode(DownButton, OUTPUT);      // Setting DownButton as an output
    digitalWrite(DownButton, LOW);      // Pull down button to ground momentarily
    delay(500);
    pinMode(DownButton, INPUT);      // Putting DownButton back in a high impedance state
  }


} // loop end


// IR receive code
int listenForIR()
{
  currentpulse = 0;
  while (1)
  {
    unsigned int highpulse, lowpulse;  // temporary storage timing
    highpulse = lowpulse = 0; // start out with no pulse length

    while (IRpin_PIN & _BV(IRpin))   // got a high pulse
    {
      highpulse++;
      delayMicroseconds(RESOLUTION);
      if (((highpulse >= MAXPULSE) && (currentpulse != 0)) || currentpulse == NUMPULSES)
      {
        return currentpulse;
      }
    }
    pulses[currentpulse][0] = highpulse;

    while (! (IRpin_PIN & _BV(IRpin)))   // got a low pulse
    {
      lowpulse++;
      delayMicroseconds(RESOLUTION);
      if (((lowpulse >= MAXPULSE) && (currentpulse != 0)) || currentpulse == NUMPULSES)
      {
        return currentpulse;
      }
    }
    pulses[currentpulse][1] = lowpulse;
    currentpulse++;
  }
}

The IR decoding I ‘borrowed’ from Nathan Chantrell’s TinyPCRemote, and I don’t entirely know how it works or why some variables are defined in the way they are. I think Nathan did a great job, and I just can’t wrap my head around how it works.

The other area of concern to me is how I handled the pin modes of the 3 pushbuttons I’m manipulating. At first I made the sketch work by digital writing the 3 pushbuttons as HIGH outputs, and dropping to LOW momentarily to trigger the button presses, but I realized I can utilize the internal pull-ups by writing HIGH input and forego the external resistors. Now I’ve since heard about INPUT_PULLUP, and I’m not sure if its more appropriate for my use or not.

Also, any other tips or advice would be very greatly appreciated. I’m going to box this thing up inside a motorized projector screen enclosure and it will be fairly difficult to get back into it down the road.

Thanks for looking

I’m not sure if it’s me, but things are a little hazy …

Is your intention to receive codes from an IR remote control and get the Arduino to change its output pins so something else thinks a switch has been pressed?

Or are there buttons (which will be pressed by a person) connected to input pins on the Arduino?

I thought I was beginning to get my head around the various I/O options when you come along with a new twist - using inputs as outputs. I hope the following is understandable and that it is correct.

The internal pullups are primarily relevant if you want the Arduino to detect a button press. pinMode(p, INPUT) followed by digitalWrite(p, HIGH) is the same as pinMode(p, INPUT_PULLUP).

Normally, if you want the Arduino to switch some external circuit you would simply use pinMode(p, OUTPUT) and digitalWrite(p, HIGH) (or LOW), making sure that the external circuit can’t draw or supply too much current.

However if the external circuit has a high impedance it may read pinMode(p, INPUT) followed by digitalWrite(p,HIGH) as “high” rather than pulling the pin to GND. In that case I should think that digitalWrite(p, LOW) will be detected as “low”. If so then another digitalWrite(p, HIGH) will be sufficient to get back to the high state with the internal pullup enabled. There should be no need to change pinMode().

…R

Robin2:
I'm not sure if it's me, but things are a little hazy ...

Sorry about that. I greatly improved the wording of my first post to explain the circuit layout and what I'm needing to do.

Thanks!

@creyc, that's much clearer now - I wish everyone took as much trouble.

However I don't have any additional words of advice (oops ... I nearly said wisdom) as I have no experience of IR remotes.

You will have to "suck-it-and-see" whether your use of INPUT and the pullup resistor works with the device you are connecting to.

If not I would suggest using a multimeter to measure the current through the switch when you ground it. If it's over, say, 30mA you should use a resistor between the positive side and your Arduino pin in order to use OUTPUT mode.

...R