@tslater & @peekay123: I know there might be better ways to do this and it’s not completely bullet proof, but here I’ve got a little demo code that supports short/long/excessive button-press recoginition via an interrupt.
The two range-check blocks can be filled with any functionality (including System.reset(), WiFi.listen(), …) and there is also the option for double tap recognition
//SYSTEM_THREAD(ENABLED)
SYSTEM_MODE(SEMI_AUTOMATIC)
STARTUP(prepare())
#define DEBOUNCE 5
#define SHORTPRESS 1500
#define LONGPRESS 3000
#define DBLTAP 1500
const int pinIRQ = D6;
volatile uint32_t blinkPattern = 0x88;
volatile uint32_t msTrig; // when was last reliable trigger
volatile uint32_t msPress; // when was the last press/hold
volatile uint32_t msRelease; // when did it get released
volatile uint32_t msHeld; // how long was it held
volatile uint32_t msDblTap; // how much time since last release
void ISR()
{
if (millis() - msTrig <= DEBOUNCE) return;
msTrig = millis();
if (!digitalRead(pinIRQ))
{ // PRESSED
msPress = msTrig;
msDblTap = msPress - msRelease;
msRelease = 0;
if (msDblTap > DBLTAP)
msDblTap = 0;
}
else
{ // RELEASED
msRelease = msTrig;
msHeld = msRelease - msPress;
msPress = 0;
// ******************** range check for hold time *********************
if (DEBOUNCE < msHeld && msHeld < SHORTPRESS)
blinkPattern = 0x08;
else if (SHORTPRESS < msHeld && msHeld < LONGPRESS)
blinkPattern = 0x80;
else
blinkPattern = 0x88;
// ********************************************************************
}
}
void prepare()
{
pinMode(D7, OUTPUT);
pinMode(pinIRQ, INPUT_PULLUP);
attachInterrupt(pinIRQ, ISR, CHANGE);
Particle.connect();
}
void setup() { }
void loop()
{
uint32_t msHold;
uint8_t factor = 0;
if (msPress)
{ // feedback during hold
msHold = millis() - msPress;
factor = 4; // dim the LED
}
else // after release
msHold = msHeld;
// ******************** range check for hold time *********************
if (DEBOUNCE < msHold && msHold < SHORTPRESS)
{
RGB.control(true);
RGB.color(0, 0, 255 >> factor);
}
else if (SHORTPRESS < msHold && msHold < LONGPRESS)
{
RGB.control(true);
RGB.color(255 >> factor ,128 >> factor, 0);
}
else
RGB.control(false);
// ********************************************************************
digitalWrite(D7, (millis() >> 2) & blinkPattern);
}
@tslater, have a play with the time constants and get a feel about the response time
One thing you need to consider is that Listening Mode takes exclusive access to shared resources and hence the attempt to access these from application code will block the application thread.
For this the new firmware 0.4.9 has got some tricks - have a look https://docs.particle.io/reference/firmware/photon/#system-thread
You can try calling WiFi.disconnect() before calling WiFi.listen() - this will interrupt the current connection attempt and enter listening mode more quickly.
Anyone solved this?
I have a button on a5, I can’t attach an interrupt. If the photon is connecting to wifi (blinking green) and I press the button, I see with serial logger that it’s pressed and I call wifi.listen but I have to wait 30-40sec. I also try to put wifi.listen in a timer but same behaviour.
Thansk, Flavio
I can’t quite make sense of the last if statement. lastRead will always be an arbitrary value when coming into the function, or will be set to 2, so in any case it’s highly unlikely that it will ever be lastRead == lastAnalogRead.
So in almost every cases this would do just the same thing
if(valoreSelettore > 2500) request_pulsante = 2;
And even if you declared it a static int, it’s not always true that two analogRead() actions will actually give you exactly the same value, even if the external signal has not changed.
Sorry, it’s only a little piece of the code…
I do it because I call wifi.listen only when I release the button…
This code is working, I can see it with serial logger… The problem is that it takes 30 seconds to execute wifi.listen. If I’m connected to the cloud it’s immediate, if It’s connecting no…
I can’t interrupt particle.connect(). If I try wifi.connect and particle.connect on wifi.ready It works well, but I don’t want to handle both wifi and particle connections… It could be complicate in some case.
Thanks a lot!
I see, have you ever tried my interrupt driven code further up?
Or WiFi.disonnect() as MDMA suggested?
BTW: When you say: “when I release the button”, why are you using analogRead() instead of digitalRead()?
A button would definetly call for an interrupt driven approach.
I tried Wifi.disconnect, not the interrupt (I can’t)
The project is complicated, I don’t have enough pin for every input I need, I have to use an analog pin with a divider to connect 3 button to 1 pin.
So I can’t attach an interrupt to an analog pin… But right now no solution…
Thanks, Flavio
I can’t, the photon it’s not accesible, It’s closed in a box and hidden.
It’s not possible to create a software interrupt? I tryed also a timer but It didn’t do the trick…
Thanks a lot!
You can still lead the SETUP button to the outside of your eclosure since there is a dedicated solder pad underneath (ment for SMD but still available for through hole use).
That would be pad 26 in this schema
You can create interrupts via hardware timers but that would go a bit deeper.
A good library that does that for you is SparkIntervalTimer which can be found on Web IDE.
As well as calling WiFi.disconnect(), be sure to also disconnect from the cloud first (Particle.disconnect()) when in automatic/semi-automatic mode, or the system will try to re-establish the cloud connection, and bring up Wi-Fi again.