High current draw when an input pin is put LOW

I'm monitoring a mailbox.

There's a latch (for letters) and a door (for parcels) on the front and another door on the back (for the owner to retrieve his mail).

The ATmega328P is running on batteries, so I'm having it sleep most of the time. Since there are only two interrupts and I'm monitoring three switches, I'm using another digital pin to differenciate letters from parcels. PIN6 is set to be HIGH in the code but is LOW when the door is closed ("NO" PIN of the limit switch). It goes HIGH only when the mailman opens it.

#include <avr/sleep.h>
#include <VirtualWire.h>


int pinEntree = 2;
int pinSortie = 3;
int pinPorteAv = 6;
volatile int int_flag = 0;

const char *lettre = "let";
const char *av = "avt";
const char *arr = "arr";


void entree()
{
  int_flag = 1; 
}


void sortie()
{    
  int_flag = 2;
}


void setup()
{
  vw_set_tx_pin(4);  //Pin d'émission
  vw_setup(2000);      //Vitesse en bps
  
  pinMode(pinEntree, INPUT_PULLUP);
  pinMode(pinSortie, INPUT_PULLUP);
  pinMode(pinPorteAv, INPUT_PULLUP);
  digitalWrite(pinEntree, HIGH);
  digitalWrite(pinSortie, HIGH);
  digitalWrite(pinPorteAv, HIGH);
  
  const char *set = "retour"; // To let the user know batteries have been replaced.
  for (int k = 0; k < 2; k++)
  {
    vw_send((uint8_t *)set, strlen(set));
    vw_wait_tx();
  }
  
//  Serial.begin(9600);
}


void loop()
{
  ADCSRA = 0;
  
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);  
  sleep_enable();
  
  attachInterrupt(0, entree, FALLING);
  attachInterrupt(1, sortie, FALLING);
  
  MCUCR = bit (BODS) | bit (BODSE);
  MCUCR = bit (BODS); 
  
  interrupts();
  sleep_cpu();
  
  
  if(int_flag==1)
  {
    detachInterrupt(0);
    delay(100); // Button bounce. I'm giving the button time to pull pinPorteAv HIGH.
    if(digitalRead(pinPorteAv) == LOW)
    {
      for (int i = 0; i < 2; i++)
      {
        for (int j = 0; j < 4; j++)
        {
  //        Serial.print(j);
          vw_send((uint8_t *)lettre, strlen(lettre));  //Sending via RF
          vw_wait_tx();  //Waiting for message to be sent
        }
  //      Serial.println();
        delay(2500);
      }
    }
    else if(digitalRead(pinEntree) == LOW)
    {
      for (int i = 0; i < 2; i++)
      {
        for (int j = 0; j < 4; j++)
        {
  //        Serial.print(j);
          vw_send((uint8_t *)av, strlen(av));  //Sending via RF
          vw_wait_tx();  //Waiting for message to be sent
        }
  //      Serial.println();
        delay(2500);
      }
    }
  }
  
  else if(int_flag=2)
  {
    detachInterrupt(1);
    delay(50);
    if(digitalRead(pinSortie) == LOW)
    {
      for (int i = 0; i < 2; i++)
      {
        for (int j = 0; j < 4; j++)
        {
  //        Serial.print(j);
          vw_send((uint8_t *)arr, strlen(arr));  //Sending via RF
          vw_wait_tx();  //Waiting for message to be sent
        }
  //      Serial.println();
        delay(2500);
      }
    }
  }
  int_flag=0;
  
}

Everything is working as it should...except that it's drawing 0.135 mA when idling.
If I unplug the pin 6 (open the circuit), the current goes into the unmeasurable (multimeter shows 0.01 µA)...but the Arduino is telling me I get a parcel when it's a letter.

I thought the internal PULLUP would reduce the current but maybe it is the case only when the pin is HIGH? Is there a programming trickery I'm not aware of or should I solder an actual resistor in series between my switch and ground?

Since there are only two interrupts and I'm monitoring three switches, I'm using another digital pin to differenciate letters from parcels.

Why? "You've got mail" means a trip to the mailbox, regardless of whether it's a letter or a package or junk mail.

Why are you attaching and detaching interrupts in loop()?

Why does retrieving the mail need to wake the Arduino up?

PaulS:

Since there are only two interrupts and I'm monitoring three switches, I'm using another digital pin to differenciate letters from parcels.

Why? "You've got mail" means a trip to the mailbox, regardless of whether it's a letter or a package or junk mail.

Because I decided it would work this way :grin:
If you receive a parcel in the afternoon it's...well, a parcel. If it's "mail", it's going to be junk.

Why are you attaching and detaching interrupts in loop()?

Because the first thing you should do after the interrupt is triggered is to detach it (to make sure it's not triggered twice) before running the code. Then you reattach it and put the µC to sleep.

Why does retrieving the mail need to wake the Arduino up?

Because the Raspberry Pi that is receiving the message is then deleting the mail (through imap) from the owner's e-mail box.
That way they don't have to do it themselves and the Pi won't send a new snail mail notification if the former letter/package hasn't been retrieved (in case of holidays).

I'd like to center the topic back to my problem: the current draw.

I'd like to center the topic back to my problem: the current draw.

I don't see a difference in the way any of the switches are read. So, I can't see a reason why one of them makes the Arduino draw more current.

PaulS:

I'd like to center the topic back to my problem: the current draw.

I don't see a difference in the way any of the switches are read. So, I can't see a reason why one of them makes the Arduino draw more current.

The two interrupts are constantly HIGH (i.e. switches are open) and go LOW when a door or the latch are open.

The DigitalPin6 is constantly connected to ground (so it's LOW) and goes HIGH only when the front door is open.

In the first try I made, the PIN6 was behaving like the others (ie. HIGH when idle, LOW when open) but that meant effectively connecting PIN2 and PIN6 together (on the NC pin of the switch) and I was having weird results from that.

Bianco:
The DigitalPin6 is constantly connected to ground (so it's LOW) and goes HIGH only when the front door is open.

But your code disagrees with that:

int pinPorteAv = 6;

pinMode(pinPorteAv, INPUT_PULLUP);

I'm activating the pullup resistor on PIN6.

As a result, the PIN6 is LOW by default.

I'm connecting the PIN6 to the NO (normally open) pin of my switch and ground to C (common).

When the door is closed, the switch is activated, meaning current does float from C to NO.

As a result, the PIN is connected to ground and LOW when idling, going HIGH only when the door is open.

As a result, the PIN is connected to ground and LOW when idling

With the internal pullup resistor, LOW means that the pin is connected to ground, and current is flowing.

HIGH means that the pin is not connect to ground, and no current is flowing.

Since you goal is to minimize current flow, you need to rewire the switch that is connected to that pin, to match the other two switches.

Everything is working as it should...except that it's drawing 0.135 mA when idling.
If I unplug the pin 6 (open the circuit), the current goes into the unmeasurable (multimeter shows 0.01 µA)...but the Arduino is telling me I get a parcel when it's a letter.

I thought the internal PULLUP would reduce the current but maybe it is the case only when the pin is HIGH? Is there a programming trickery I'm not aware of or should I solder an actual resistor in series between my switch and ground?

What I take from this that your switch contacts are NC (normally-closed) where one terminal is connected to pin 6 and the other connected to GND. It makes sense that this would "normally" draw 0.135 mA when idling and no current draw when in sleep mode.

You wouldn't want to reverse the logic here or you would get the high current draw when sleeping. If the "on time" is such that 0.135 mA is an issue, you could reduce this by about 5X by not using the internal pullup and use an external 200K pullup resistor with 0.01µF connected from pin 6 to GND. This will filter noise and will have a 2 millisecond response.

EDIT: Umm ... critical information came in (should have read it) ... I'm giving my crystal ball to PaulS (I think it just needs new batteries).

Anyways, you would still have to be careful that any changes don't transfer the high current draw to sleep mode.

dlloyd:
Anyways, you would still have to be careful that any changes don't transfer the high current draw to sleep mode.

This is the case Today. I have 0.135 mA of current draw when the µC is sleeping and nobody is touching anything.

While nothing happens, PIN6 is connected to ground and hence is LOW.

Let me reformulate the question:

  • does current flow through the pullup resistor of the ATmega328P when the pin is connected to ground?
  • if not, is it possible to use some internal thingy or should I connect an actual resistor between PIN6 and my switch?

does current flow through the pullup resistor of the ATmega328P when the pin is connected to ground?

I would say yes, since there's a circuit from high, thru resistor, out the pin, thru closed switch, to ground.

The way I see it is the way I show it in the attached schematic.

This is the case Today. I have 0.135 mA of current draw when the µC is sleeping and nobody is touching anything.

Ahh - I wasn't relating the word "idling" to sleep mode.

Let me reformulate the question:

  • does current flow through the pullup resistor of the ATmega328P when the pin is connected to ground?

Yes.

  • if not, is it possible to use some internal thingy or should I connect an actual resistor between PIN6 and my switch?

I think you should connect it so you have the high current draw when µC is running and no current draw when the µC is sleeping. The 0.135 mA current draw won't be very significant if, for example, the µC is running only 10% of the time.

EDIT: As in previous post diagram "SW1" (thanks JimboZA) and use "RISING" to trigger your interrupt.

JimboZA:

does current flow through the pullup resistor of the ATmega328P when the pin is connecte
d to ground?

I would say yes, since there's a circuit from high, thru resistor, out the pin, thru closed switch, to ground.

The current seems quite high.

dlloyd:

This is the case Today. I have 0.135 mA of current draw when the µC is sleeping and nobody is touching anything.

Ahh - I wasn't relating the word "idling" to sleep mode.

You're right, that was misleading. I meant "the mailbox is idling", i.e. all doors and latch are closed and PIN6 is pulled to ground.

I think you should connect it so you have the high current draw when µC is running and no current draw when the µC is sleeping. The 0.135 mA current draw won't be very significant if, for example, the µC is running only 10% of the time.

I said earlier I can't do it because that means connecting PIN6 to PIN2 and weird shit happens then.

What I can do though is modify the code and draw PIN6 HIGH only when interrupt 0 is triggered (once a day).

Or solder a 100k resistor in series between the switch and PIN6 (I'd prefer not to have to reprogram the ATmega)?

Or solder a 100k resistor in series between the switch and PIN6 (I'd prefer not to have to reprogram the ATmega)?

If the internal pullup is 50K, then the 100K in series will only swing the voltage down to 1.66V (could be a problem).

With a small change to the code (remove PULLUP) and use an external 100K or 200K pullup (connected pin 6 to 5V, leaving switch connections as is), you should get much less current draw and still have full voltage swing on pin 6. You may need a small capacitor of around 0.01µF to filter any noise and provide hardware debounce.

dlloyd:
With a small change to the code (remove PULLUP) and use an external 100K or 200K pullup (connected pin 6 to 5V, leaving switch connections as is), you should get much less current draw and still have full voltage swing on pin 6.

Understood.

You may need a small capacitor of around 0.01µF to filter any noise

On a simple setup like that running off 3*AAA batteries, is there an actual risk of noise?

Bianco:
Since there are only two interrupts...

All the pins of an ATmega328P are capable of generating a pin-change interrupt. Which would suit your application well. And would eliminate the need to overload any pins.

[quote author=Coding Badly link=topic=270962.msg1910592#msg1910592 date=1412631933]

Bianco:
Since there are only two interrupts...

All the pins of an ATmega328P are capable of generating a pin-change interrupt. Which would suit your application well. And would eliminate the need to overload any pins.[/quote]
Waking-up interrupts?

(It's sleeping 99% of the time)

Yes.

Nice, I didn't know that.

I gave a chance to the datasheet (page 70 and following) but I do not fully understand it. I'll stick with INT0 and INT1 for the moment :grin: