Simple remote with 2 button - low power consumption

Hello All,
Here a code to build an easy remote with 2 buttons (press and long press functions). I would like some suggestion to make it low consumption because attached with a 9V battery.

Serial port is included only for debugging, will be removed on the remote.
EEPROM part is not used, you can ignore it.

Thank you very much,
Igor

#include <SPI.h>
#include <EEPROM.h>

#define LEFT_BUTTON 2
#define RIGHT_BUTTON 3

extern unsigned char gucSendDat[10];

/*******************************************************************************************************************************************************
 * EPPROM
 */

 /*************************************************************************/
/* Macro define */
/*************************************************************************/
#define EPPROM_ADDR    100
#define EPPROM_OK      0xA5

#define WIFICHANEL     108
#define WIFIPIPE      0

/*************************************************************************/
/* EEPROM Process structure */
/*************************************************************************/
typedef struct _ST_EEPROM_SAVE
{
  unsigned char ucStat;

  unsigned char  ucCommChanel;
  unsigned char  ucCommPipe;
  
}ST_EPPROM_SAVE;

ST_EPPROM_SAVE    gstEepromStat;    /* Eppromni */

extern void fncEppromLoadDefault(void);

/*************************************************************************/
/* EEPROM Intialization */
/*************************************************************************/
extern void fncEppromUpdate(void);
void fncEppromInit(void)
{
  char * pEppromAdr;
  int address;
  short sCnt;

  pEppromAdr = (char *)&gstEepromStat;

  address = EPPROM_ADDR;
  for(sCnt = 0; sCnt < sizeof(gstEepromStat); sCnt++){
    *pEppromAdr = EEPROM.read(address);
    address++;
    pEppromAdr++;
  }
  
  if(gstEepromStat.ucStat != EPPROM_OK){
    fncEppromLoadDefault();
    fncEppromUpdate();
  }
}


/*************************************************************************/
/* EEPROM Update */
/*************************************************************************/
void fncEppromUpdate(void)
{
  char * pEppromAdr;
  int address;
  short sCnt;

  pEppromAdr = (char *)&gstEepromStat;

  address = EPPROM_ADDR;
  for(sCnt = 0; sCnt < sizeof(gstEepromStat); sCnt++){
    EEPROM.write(address, *pEppromAdr);
    address++;
    pEppromAdr++;
  }
}

/*************************************************************************/
/* EEPROM Load default data */
/*************************************************************************/
void fncEppromLoadDefault(void)
{
    gstEepromStat.ucStat = EPPROM_OK;

    gstEepromStat.ucCommPipe = 1;
    gstEepromStat.ucCommChanel = 108;

}


//Function codes 1(read coils), 3(read registers), 5(write coil), 6(write register)
//signed int Mb.R[0 to 125] and bool Mb.C[0 to 128] MB_N_R MB_N_C
//Port 502 (defined in Mudbus.h) MB_PORT
void setup()
{
  
  /* Epprom Init */
  fncEppromInit();

  /* Wireless Init */
  fncSlaveSetup(WIFIPIPE, WIFICHANEL);

  /* Check button init*/
  fncCheckButtonInit();

  delay(1000);
  Serial.begin(9600);
  pinMode(LEFT_BUTTON, INPUT_PULLUP); 
  pinMode(RIGHT_BUTTON, INPUT_PULLUP); 
}


/* Main loop */
void loop()
{    
    //fncSlaveSend(gucSendDat, sizeof(gucSendDat));

    fncCheckButton();
    delay(1);
}

unsigned long gulBtnTime;
unsigned long gucBtnShortTime1;
unsigned long gucBtnLongTime1;
unsigned long gucBtnShortTime2;
unsigned long gucBtnLongTime2;
unsigned char gucLeftLastSts;
unsigned char gucRightLastSts;
unsigned char gucLeftSts = HIGH;
unsigned char gucRightSts = HIGH;
unsigned char gucLeftLongSts;
unsigned char gucLeftLongActived;
unsigned char gucRightLongSts;
unsigned char gucRightLongActived;

void fncCheckButtonInit(void){
    unsigned long ulRet;
    
    ulRet = millis();
    gulBtnTime = ulRet + 10;
    gucBtnShortTime1 = ulRet + 100;
    gucBtnLongTime1 = ulRet + 1000;

    gucLeftLastSts = digitalRead(LEFT_BUTTON);
    gucRightLastSts = digitalRead(RIGHT_BUTTON);

    gucLeftLongActived = false;
    gucRightLongActived = false;
    
}

void fncCheckButton(void){
    unsigned long ulRet;
    unsigned char ucLeftBnt, ucRightBnt;
    
    ulRet = millis();
     
    if(ulRet > gulBtnTime){
        gulBtnTime = ulRet + 10;
        ucLeftBnt = digitalRead(LEFT_BUTTON);
        if(gucLeftLastSts != ucLeftBnt){
            gucLeftLastSts = ucLeftBnt;

            gucBtnShortTime1 = ulRet + 50;
            gucBtnLongTime1 = ulRet + 1000;
           
            
    
        }
        else{
            if(ulRet > gucBtnShortTime1){
                if((gucLeftSts == LOW) && (gucLeftLastSts == HIGH)){
                     if(gucLeftLongActived != true){
                        fncStartMatch();    // Increase
                     }
                }
                if(gucLeftSts != gucLeftLastSts){
                    gucLeftLongActived = false;
                }
                gucLeftSts = gucLeftLastSts;
                
            }

            if(ulRet > gucBtnLongTime1){
                if(gucLeftLastSts == LOW){
                    if(gucLeftLongActived == false){
                        fncStopMatch();    // Decrease
                        gucLeftLongActived = true;
                    }
                }
                gucLeftLongSts = gucLeftLastSts;
            }
        }
        
        
        ucRightBnt = digitalRead(RIGHT_BUTTON);
        if(gucRightLastSts != ucRightBnt){
            gucRightLastSts = ucRightBnt;

            gucBtnShortTime2 = ulRet + 100;
            gucBtnLongTime2 = ulRet + 1000;
        }
        else{
            if(ulRet > gucBtnShortTime2){
                if((gucRightSts == LOW) && (gucRightLastSts == HIGH)){
                     if(gucRightLongActived != true){
                        fncSendInc();    // Increase
                        }
                }
                if(gucRightSts != gucRightLastSts){
                    gucRightLongActived = false;
                }
                gucRightSts = gucRightLastSts;
                
            }

            if(ulRet > gucBtnLongTime2){
                if(gucRightLastSts == LOW){
                    if(gucRightLongActived == false){
                        fncSendDec();    // Decrease
                        gucRightLongActived = true;
                    }
                }
                gucRightLongSts = gucRightLastSts;
            }
        }
        
    }
}

void fncStartMatch(void){
    Serial.println("Button - Start timer");  
                     
    //memset(&gucSendDat, 0x0, sizeof(gucSendDat));
    //gucSendDat[0] = 1;
    //fncSlaveSend(gucSendDat, sizeof(gucSendDat));
}

void fncStopMatch(void){
    Serial.println("Button - reset timer");  
    
    //memset(&gucSendDat, 0x0, sizeof(gucSendDat));
    //gucSendDat[0] = 2;
    //fncSlaveSend(gucSendDat, sizeof(gucSendDat));    
}
void fncSendInc(void){
    Serial.println("Button - increase");  
                     
    //memset(&gucSendDat, 0x0, sizeof(gucSendDat));
    //gucSendDat[0] = 3;
    //fncSlaveSend(gucSendDat, sizeof(gucSendDat));
}

void fncSendDec(void){
    Serial.println("Button - decrease");  
    
    //memset(&gucSendDat, 0x0, sizeof(gucSendDat));
    //gucSendDat[0] = 3;
    //fncSlaveSend(gucSendDat, sizeof(gucSendDat));    
}

Read the rules and post your code correctly.

Put capacitors on that regulator.

Throw away that 9V battery.

Learn about sleep mode.

If you are using say a Uno which consumes 50mA when doing nothing, then there is no point in optimising the code. If you move to a barebones ATMEGA328P (or similar) then look at nick Gammon's power saving article and maybe use the buttons to trigger an interrupt so the device can sleep if not doing anything.

Grumpy_Mike:
Read the rules and post your code correctly.

Put capacitors on that regulator.

Throw away that 9V battery.

Learn about sleep mode.

Thank you, where I find rules?

Where I have to put the capacitors and how it works without battery?

Grumpy_Mike:
Learn about sleep mode.

Yes, i'm trying

6v6gt:
If you are using say a Uno which consumes 50mA when doing nothing, then there is no point in optimising the code. If you move to a barebones ATMEGA328P (or similar) then look at nick Gammon's power saving article and maybe use the buttons to trigger an interrupt so the device can sleep if not doing anything.
Gammon Forum : Electronics : Microprocessors : Power saving techniques for microprocessors

Yes,
I use a ATMEGA328P and the link is very interessant, thank you.
I think is the chapter "Detecting key presses on a keypad whilst asleep"

Someone know how much time will be the battery consummed with this hardware and software?

Thank you

IgorRF:
Thank you, where I find rules?

At the top of every section of the Forum is How to use this forum - please read. How could you miss it?

...R

Where I have to put the capacitors

Between the input and ground and the output and ground. See the data sheet for the exact manafacaturer of this chip you are using for the values to use.

how it works without battery?

DER! Throw THAT battery away it is useless.

You could always route the actual power for the arduino through each button and also have each button goto a different pin.

So you press button, that button allows 9volts to flow into the barrel jack and through a voltage divider into say pin D2.

Arduino boots up, reads D2 as high and sends your command.

Release button and everything shuts down for 100% power save mode.

You can get these things to boot up pretty quick as a bare chip.

IgorRF:
Yes,
I use a ATMEGA328P and the link is very interessant, thank you.
I think is the chapter "Detecting key presses on a keypad whilst asleep"

Someone know how much time will be the battery consummed with this hardware and software?

Thank you

If you organise the sketch so that the device can sleep most of the time and can switch off the power to the peripheral devices (I see relics of a radio device in your code) and move to a lower voltage battery which does not need a regulator ( < 5.5 volts ) the consumption goes down to the micro amp level and the battery could last years. It just depends what the device is doing when it is not sleeping and how long those awake periods are.
You can estimate the power consumption as it is with an ammeter.

6v6gt:
If you organise the sketch so that the device can sleep most of the time and can switch off the power to the peripheral devices (I see relics of a radio device in your code) and move to a lower voltage battery which does not need a regulator ( < 5.5 volts ) the consumption goes down to the micro amp level and the battery could last years. It just depends what the device is doing when it is not sleeping and how long those awake periods are.
You can estimate the power consumption as it is with an ammeter.

Yes, that's my goal. Is a scoreboard of my volleyball team, I would like to use it on our tournament. The scoreboard is a receiver RF, then I have 2 remote to pilot points and time.

Is like a TV remote with 2 button.. But with RF.

Anyone has an example of code with interrupt and sleeping functions ready to use? there are 3 main points that is heavy:

  • buttons can handle press and long press
  • debouncing problem
  • sleeping mode

Anyone remember an example on some post?

Thank you very much

(deleted)

spycatcher2k:
You have already been given the link to Nick Gammon's site, this gives you examples, and even an explanation as to what is happening.

Thank you, now I don't have the board because is in delivery. Yet I have only a arduino uno r3. When I will get, I will try.

Ah found:

http://www.home-automation-community.com/arduino-low-power-how-to-run-atmega328p-for-a-year-on-coin-cell-battery/

this is the way :slight_smile:

IgorRF:
Thank you, now I don't have the board because is in delivery. Yet I have only a arduino uno r3. When I will get, I will try.

You can do everything with the Uno and do all your development on it including testing sleep mode etc. You will simply not be able to benefit from the power savings.

What board have you ordered ?

Hello,

I implemented the logical of sleeping. When a interrupt (button) is fired, it wake up the board, it fix a timeout after 5 second and go to sleep mode when is reached. It seem to be very stable.

#include <SPI.h>
#include "LowPower.h"

#define LEFT_BUTTON 2
#define RIGHT_BUTTON 3

#define EPPROM_ADDR    100
#define EPPROM_OK      0xA5
#define WIFICHANEL     108
#define WIFIPIPE      0

unsigned long wakeUP;
unsigned long gulBtnTime;
unsigned long gucBtnShortTime1;
unsigned long gucBtnLongTime1;
unsigned long gucBtnShortTime2;
unsigned long gucBtnLongTime2;
unsigned char gucLeftLastSts;
unsigned char gucRightLastSts;
unsigned char gucLeftSts = HIGH;
unsigned char gucRightSts = HIGH;
unsigned char gucLeftLongSts;
unsigned char gucLeftLongActived;
unsigned char gucRightLongSts;
unsigned char gucRightLongActived;
unsigned long ulRetWakeUp;

void setup()
{
  fncSlaveSetup(WIFIPIPE, WIFICHANEL);
  delay(1000);
  Serial.begin(9600);
  pinMode(LEFT_BUTTON, INPUT_PULLUP); 
  pinMode(RIGHT_BUTTON, INPUT_PULLUP); 
  wakeUP = 0;
}

/* Main loop */
void loop()
{   

    if(wakeUP == 0){
      Serial.println("SLEEP");
      Serial.flush();
      detachInterrupt(digitalPinToInterrupt(LEFT_BUTTON)); 
      detachInterrupt(digitalPinToInterrupt(RIGHT_BUTTON));        
      attachInterrupt(digitalPinToInterrupt(LEFT_BUTTON), wakeMeUp, RISING);
      attachInterrupt(digitalPinToInterrupt(RIGHT_BUTTON), wakeMeUp, RISING);
      LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
      detachInterrupt(digitalPinToInterrupt(LEFT_BUTTON)); 
      detachInterrupt(digitalPinToInterrupt(RIGHT_BUTTON));      
    }
    attachInterrupt(digitalPinToInterrupt(LEFT_BUTTON), wakeMeUp, RISING);
    attachInterrupt(digitalPinToInterrupt(RIGHT_BUTTON), wakeMeUp, RISING);
      
    fncCheckButton();
    
}

void wakeMeUp(){
    wakeUP = 1;
    ulRetWakeUp = millis() + 5000;
}


void fncCheckButtonInit(void){
    unsigned long ulRet;
    
    ulRet = millis();
    gulBtnTime = ulRet + 10;
    gucBtnShortTime1 = ulRet + 100;
    gucBtnLongTime1 = ulRet + 1000;

    gucLeftLastSts = digitalRead(LEFT_BUTTON);
    gucRightLastSts = digitalRead(RIGHT_BUTTON);

    gucLeftLongActived = false;
    gucRightLongActived = false;
    
}

void fncCheckButton(void){
    unsigned long ulRet;
    unsigned char ucLeftBnt, ucRightBnt;
    ulRet = millis();
    
    if(ulRet > gulBtnTime){
        gulBtnTime = ulRet + 10;
        ucLeftBnt = digitalRead(LEFT_BUTTON);
        if(gucLeftLastSts != ucLeftBnt){
            gucLeftLastSts = ucLeftBnt;
            gucBtnShortTime1 = ulRet + 50;
            gucBtnLongTime1 = ulRet + 1000;
        }
        else{
            if(ulRet > gucBtnShortTime1){
                if((gucLeftSts == LOW) && (gucLeftLastSts == HIGH)){
                     if(gucLeftLongActived != true){
                        fncStartMatch();
                     }
                }
                if(gucLeftSts != gucLeftLastSts){
                    gucLeftLongActived = false;
                }
                gucLeftSts = gucLeftLastSts;
                
            }
            if(ulRet > gucBtnLongTime1){
                if(gucLeftLastSts == LOW){
                    if(gucLeftLongActived == false){
                        fncStopMatch();    // Decrease
                        gucLeftLongActived = true;
                    }
                }
                gucLeftLongSts = gucLeftLastSts;
            }
        }
        
        
        ucRightBnt = digitalRead(RIGHT_BUTTON);
        if(gucRightLastSts != ucRightBnt){
            gucRightLastSts = ucRightBnt;
            gucBtnShortTime2 = ulRet + 100;
            gucBtnLongTime2 = ulRet + 1000;
        }
        else{
            if(ulRet > gucBtnShortTime2){
                if((gucRightSts == LOW) && (gucRightLastSts == HIGH)){
                     if(gucRightLongActived != true){
                        fncSendInc();    // Increase
                        }
                }
                if(gucRightSts != gucRightLastSts){
                    gucRightLongActived = false;
                }
                gucRightSts = gucRightLastSts;
                
            }

            if(ulRet > gucBtnLongTime2){
                if(gucRightLastSts == LOW){
                    if(gucRightLongActived == false){
                        fncSendDec();    // Decrease
                        gucRightLongActived = true;
                    }
                }
                gucRightLongSts = gucRightLastSts;
            }
        }
        
    }
    if (ulRetWakeUp < millis()) {
      wakeUP = 0;
      //Serial.println(" Sleep please");  
      
    }
}

void fncStartMatch(void){
    Serial.println("Button - Start timer");  
                     
    //memset(&gucSendDat, 0x0, sizeof(gucSendDat));
    //gucSendDat[0] = 1;
    //fncSlaveSend(gucSendDat, sizeof(gucSendDat));
}

void fncStopMatch(void){
    Serial.println("Button - reset timer");  
    
    //memset(&gucSendDat, 0x0, sizeof(gucSendDat));
    //gucSendDat[0] = 2;
    //fncSlaveSend(gucSendDat, sizeof(gucSendDat));    
}
void fncSendInc(void){
    Serial.println("Button - increase");  
                     
    //memset(&gucSendDat, 0x0, sizeof(gucSendDat));
    //gucSendDat[0] = 3;
    //fncSlaveSend(gucSendDat, sizeof(gucSendDat));
}

void fncSendDec(void){
    Serial.println("Button - decrease");  
    
    //memset(&gucSendDat, 0x0, sizeof(gucSendDat));
    //gucSendDat[0] = 3;
    //fncSlaveSend(gucSendDat, sizeof(gucSendDat));    
}

6v6gt:
If you organise the sketch so that the device can sleep most of the time and can switch off the power to the peripheral devices (I see relics of a radio device in your code) and move to a lower voltage battery which does not need a regulator ( < 5.5 volts ) the consumption goes down to the micro amp level and the battery could last years. It just depends what the device is doing when it is not sleeping and how long those awake periods are.
You can estimate the power consumption as it is with an ammeter.

Thank you, I changed my code and now it manage the sleeping mode.

If I understood correctly if I link a battery 18650, instead of a 9V, I will arrive at 3.7V (enough for arduino nano).
Can I link directly to arduino without the component LM7805 (that convert 9V to 5V)?

After that I will remove the regulator from the board and the led connection.

I understood correctly what is need to do?

Thank you