I made a simple remote using an arduino nano, an nrf24L01 module and a 3 axis joystick. The joystick uses 3 analog pins, 1 for the X axis, 1 for the Y and 1 for click. As it is a remote, it works on battery and stays off most of the time. Therefore I want it to stay asleep and to wake up as soon as any bouton is used. There is the code:
#define CLIENT_ADDRESS 1
#define SERVER_ADDRESS 2
#define DEBUG 1
#include <avr/sleep.h>
#include <RHReliableDatagram.h>
#include <RH_NRF24.h>
#include <SPI.h>
#include "DebugUtils.h"
RH_NRF24 driver;
RHReliableDatagram manager(driver, CLIENT_ADDRESS);
const byte XPIN = A1;
const byte YPIN = A2;
const byte CPIN = A3;
const byte LEDPIN = 2;
const unsigned int wakeTimeout = 3000;
unsigned long previousWakeTimeout;
ISR (PCINT1_vect) { sleep_disable(); DEBUG_PRINT("*"); } // handle pin change interrupt for A0 to A5
void setup ()
{
Serial.begin(9600); delay(100);
pinMode(LEDPIN, OUTPUT);
pinMode(XPIN, INPUT);
pinMode(YPIN, INPUT);
pinMode(CPIN, INPUT);
digitalWrite(LEDPIN, LOW);
DEBUG_PRINTLN("CLIENT");
if (!manager.init()) DEBUG_PRINTLN("init failed");
PCMSK1=(1<<PCINT9)|(1<<PCINT10)|(1<<PCINT11); //want pins A1 to A3
PCIFR|= bit (PCIF1); // clear any outstanding interrupts
PCICR|= bit (PCIE1); // enable pin change interrupts for A0 to A5
DEBUG_PRINT("Idle x;y value: ("); DEBUG_PRINT(analogRead(XPIN)); DEBUG_PRINT(";"); DEBUG_PRINT(analogRead(YPIN)); DEBUG_PRINTLN(")");
}
void loop ()
{
if (millis() - previousWakeTimeout >= wakeTimeout)
{
previousWakeTimeout = millis();
DEBUG_PRINTLN("SLEEP"); delay(100);
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
sleep_mode ();
}
readInput();
}
void readInput()
{
if (digitalRead(CPIN) == 0) { rf_sendString("Click"); }
else if (analogRead(YPIN) > 700) { rf_sendString("Down"); }
else if (analogRead(YPIN) < 400) { rf_sendString("Up"); }
else if (analogRead(XPIN) > 700) { rf_sendString("Left"); }
else if (analogRead(XPIN) < 400) { rf_sendString("Right"); }
}
void rf_sendString(char str[RH_NRF24_MAX_MESSAGE_LEN])
{
previousWakeTimeout = millis();
uint8_t rf_data[RH_NRF24_MAX_MESSAGE_LEN];
strcpy((char*)rf_data, str);
digitalWrite(LEDPIN, HIGH);
manager.sendtoWait(rf_data, sizeof(rf_data), SERVER_ADDRESS);
digitalWrite(LEDPIN, LOW);
//delay(70);
DEBUG_PRINT((char*)rf_data);
DEBUG_PRINT(" ("); DEBUG_PRINT(analogRead(XPIN)); DEBUG_PRINT(";"); DEBUG_PRINT(analogRead(YPIN)); DEBUG_PRINTLN(")");
}
Strangely, it works fine when the joystick is clicked, or pushed Up or Right, but does not work for Left nor Down. Here's the serial output, where the interrupt is represented by an asterisk (*) and the X,Y shown in parantheses:
CLIENT
Idle x;y value: (513;518)
**Down (513;737)
Down (513;1023)
Down (513;1023)
Down (513;518)
*Up (*513;*0)
Up (*513;*0)
Up (*513;*0)
Up (513;518)
*Left (1023;518)
Left (1023;518)
Left (1023;518)
Left (1022;518)
Left (513;518)
*Right (0;*518)
*Right (0;*518)
*Right (513;517)
Notice how the interrupt is triggered for all Up and Right gesture, but not for Down and Left, altought they use the same pins. I suspect that it might have something to do with the type of change, as Up and Right are decreasing values, and Down and Left are increasing values. Any hint would be greatly appreciated!