this is my very first post here and also I am super new to Arduino and electronics - I am a professional programmer for web-applications in my normal life - so, please bear with me!
Since 2 days, I've started working with Arduino and electronics, and I want to build a 8-button remote for an Android-application as a hobby project.
For this, I've built a resistor ladder and it's working great. Now I want to save power, because it should run as long as possible on a 400mAh battery.
So I thought I could do this:
void loop(){
 if(keyPressed){
  keyCode = whichKeyIsPressed(false);
  if (keyCode != -1) {
   sendKey(keyCode);
  }
  keyPressed = false;
 }
 delay(100);
}
where "whichKeyIsPressed" is my resistor-ladder logic which works great, reading an analog input.
bool keyPressed is set to true like this:
However, I now have a problem with my PCB. I want to design it so that any button that is pressed sets INTERRUPT_PIN "high" and of course the analog pin must still read the correct voltage.
My current circuit-design is attached, and I need input as it surely is wrong somehow... for simplification, I only drew it for 3 buttons btw.
Thanks for reading, looking forward to your comments,
Raphi
for your Arduino to see a RISING condition, the voltage needs to go from LOW to HIGH
from the top of my memory, for a 5V board, the ATmega will report LOW if a voltage less than 1.5V is present at the pin (or ~1.0V for 3.3V boards) and it will report HIGH if a voltage greater than 3.0V is present (2.0V for 3.3V boards)
In between you are a bit in no-mans land.
==> it seems you are on a 3.3V system, so You need to make sure your resistor ladder never reports below 2.0V when a button is pressed. having one more suitably calculated resistor in the ladder that no button drives could probably help.
I was thinking about a passive resistor ladder, that only becomes active after an (external) interrupt.
The ladder is between GND and an output pin that is LOW in idle/sleepmode.
The buttons from the different laddersteps go to the analogread pin but also to the (external) interrupt pin.
The interupt pin has the internal pullup active. If any of the buttons is pressed the interrupt pin will go from HIGH (pullup) to LOW, as the entire ladder is at LOW level.
The MCU wakes up and sets the output pin from LOW to HIGH. Now current starts to flow through the ladder and an analogread can be performed. Do what you want with it, set the output pin to the ladder LOW again and put the MCU to sleep.
In idle/sleepmode the ladder will not consume power.
The activated internal pullup resistor may have a small effect on the analogreading value, but I expect that effect to be always the same, so you can compensate that in software, if needed at all.
[edit] I see that if you press the top and bottom button at the same time, you may blow up the output pin, so for safety better leave out either one of those buttons.
@hmeijdam - that looks like the perfect idea! Thinking about it I see no reason why it shouldn't work and I'll try it out asap and report back here. Thanks!!
What did you mean with "external" interrupt pin?
There are two types of interrupts. "External Interrupts" and "Pinchange Interrupts",
Here you can read more about that:
I thought that you could only wake up from powerdown with an External Interrupt, but according to the datasheet (page 34) both interrupts can wake up the MCU from powerdown state, and that's all you want to do. You don't even care which pin on the port (pin change interrupt work per port) caused the interrupt, as you only want it to wake up.
Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf
thanks so much. My board is an Adafruit nRF53832, so I will have to look this up.
I wrote a simple and very reduced (read: not compiling) code sample to think about your idea.
Is that more or less how you thought it should be?
bool someKeyPressed = false;
const int INTERRUPT_PIN = 3;
const int POWER_PIN = A0;
const int BUTTON_PIN = A1;
void setup() {
 pinMode(INTERRUPT_PIN, INPUT_PULLUP);
 attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), keyPress, RISING);
 pinMode(POWER_PIN, OUTPUT);
 pinMode(BUTTONS_PIN, INPUT);
}
void loop() {
 if(someKeyPressed){
  digitalWrite(POWER_PIN, HIGH);
  analogRead(BUTTONS_PIN); //very much simplified, needs averaging etc.
  digitalWrite(POWER_PIN, LOW);
  someKeyPressed = false;
 }else{
  //put the MCU to sleep
 }
}
void keyPress() {
 someKeyPressed = true;
}
I had no thoughts yet about the actual coding, only about the (logic of the) design to implement a resistor ladder using the least amount of power.
Coding will be your learning path.
Apart from the straightforward code you will be using two more advanced features. Interrupt service routines and sleepmodes.
I recommend you google for some examples of those two area's before you put your sketch together and add the sleepmode/wakeup in a second phase.
Personally I would first build a:
version where a pin is switched from low to high after interrupt occurs, blik a led and put low again.
Then replace "blink a led" with your ladder and analogread the ladder
Then build your switch/case routine for the buttonpress
Then add the sleepmode
Save all the interim versions, so that you can always go back to a version that worked, should you get lost.
@hmeijdam I'm slowly starting with the HW- and SW-build and one thing I do not understand. Having the interrupt-pin set to INPUT_PULLUP means basically setting it to 3v3, so the ladder has some current even without the digital out set to high - what am I doing wrong?
Edit: I think I understand: while no button is closed, the ladder is low, so digital in is also pulled low - is that correct?
Heck of a learning curve for me, sorry and thanks for your patience.
slople:
so digital in is also pulled low - is that correct?
Correct. The internal pullup in the Atmega processor is about 34K, so no match for the overall 8K resistance of your entire ladder, that will force it low.
One more thing that popped in my mind, during my morning walk.
I mentioned to leave out the top or bottom button, to avoid a shortcircuit. Leaving out the top button has one more advantage. Imagine that a button is just opening again before the analogread is done or the button is bouncing while pressed (Google for Button Debouncing). In that situation the analogread will report a full high 3,3V as the pullup resistor is pulling it high again.
You now can disqualify that reading as false, because you removed the top button, so there is no buttton that could ever produce a full high at 3.3V.