1

I'm trying to implement a logic to detect a keypress and hold from a RF remote. Currently I'm able to detect the button press in my controller RF receiver. I'm getting the interrupt callback for every press. Now how do I detect a press and hold for 5 sec in the code?

I checked in the oscilloscope that when I press and hold a key in remote, I get the RF data in my receiver every 34ms.

All I can think of is to count the number of sequential interrupts with the same data in 5 secs and validate it but I'm not sure its the right way.

Any suggestions how to implement it. I will try it.

Thanks

  • 2
    Start a timeout each moment you receive a button press, and when it expires, check for the requested minimum hold time. – the busybee Sep 15 '22 at 13:10
  • 2
    Start a timer when you receive the first button press and check after 5s whether the button is still pressed. – the busybee Sep 15 '22 at 13:11
  • 2
    You see, these are just quick suggestions. Please [edit] your question and add more details about your requirements. And you could show us your attempt, and explain where you stumble. – the busybee Sep 15 '22 at 13:12
  • 1
    You can post your solution as an answer - it should not form part of the question. Your answer can then be commented or voted on, and you can even accept it as _the_ answer - although if the solution was inspired by somebody else's answer that would be somewhat poor form - you would do better to accept the answer that most inspired the solution. In general however "please review my code" is not a valid question on SO, and you should certainly remove that part from the question, not least because changing a question or adding new questions to one that already has answers is also poor form. – Clifford Sep 19 '22 at 15:11
  • 1
    ... if I were to review that code however, I would advise against both _magic numbers_ and symbol names that implied _magic numbers_. That is rather then for example literal `50`, you should have say `BUTTON_REPEAT_TIMEOUT_MS`, and rather then `button_timer_50ms`, say `button_repeat_timer`. The timing is implementation specific and should not be incorporated in the symbol name, otherwise it is just a _magic_number_ in any case. That is names that reflect whet the timing is _for_, not how long the period is - which may change. So `BUTTON_HOLD_MS` and `button_hold_timer` too. – Clifford Sep 19 '22 at 15:21
  • Thank you Clifford. I edited the question and added the solution as an answer. I'm gona make the changes you suggested for the variable names. It makes sense to keep the variable names to define its functionality rather than about the timings. – aspiring_programmer Sep 20 '22 at 04:58

3 Answers3

2

A good idea with any button, direct, or as in this case remote, is to detect both press and release. Then apply the press and hold timing on top of that. In that way physical and remote buttons can be handled in the same manner.

In this case you could detect release by setting a 50ms timer that is restarted on every 35ms button interrupt. Then if the 50ms timer expires, the button has been released (or gone out of range).

Then for the 5 second hold, you could have 5 second timer that can be started on button down, and cancelled on button release. Similarly, if that timer expires you trigger the hold event.

The timers could be implemented in software or hardware, although it might be a poor use of resources to dedicate two hardware timers to one button.

See also Pressing button for 3 seconds and how to measure its time with Atmega8 1MHz?. Given press/release detection as described above, you could apply the higher level hold timing as in the accepted answer to that question.

Clifford
  • 88,407
  • 13
  • 85
  • 165
1

First of all, depending on what RF technology you are using, you may not be getting the response in real-time. Some RF technologies have relatively long latency/propagation delay and many can't guarantee real-time at all. You may want to take this in account by measuring with a scope the time between the physical key press in the transmitter until the time when that key press is detected in the receiver.

Also we have to assume that the button is properly debounced on the transmitter side, or you'll be getting lots of garbage sent through the air.

Possible method 1:

  • Use a cyclic timer interrupt which reads the state of the button once every 50ms or so. You can use a counter variable which is increased by 1 if the button is pressed or set to zero if the button is released.

Possible method 2:

  • Upon getting the first keyboard interrupt, assuming it fires on rising edge, change that interrupt to now trigger on falling edge. Then start a timer and ensure that no interrupts fire during the time that timer was running.

    Some MCU timer peripherals support input capture on both edges, so you could implement various alternative methods to the above based on that.

Possible method 3:

  • If using some simple OOK stuff and the transmitter remains asleep until a button is pressed, you may be able to simply record RSSI over time by using whatever provided RSSI feature the RFIC got. But this way you need some means to detect that it was actually your transmitter that caused the RSSI to go up.
Lundin
  • 195,001
  • 40
  • 254
  • 396
0

Thank you all so much for the suggestions. I implemented the logic based on the suggestion given by users "the busybee, Clifford and Lundin" and it is working now. Please have a look.

void ISR_callback(uint32_t value) //Button press ISR
{
   button_data = (uint8_t)((value>>8) & 0xF);
   
   if(button_data == 0xB) //required button pressed
   {
      button_pressed = 1;
      button_timer_50ms = 0; //reset the independent 50ms counter, if button pressed
   }
 }

void main(void)
{
    while(1)
    {
        if (one_ms_time_expired()) //1ms timer loop
        {
          if(button_pressed) //is set in ISR, if button is pressed
          {
              timer_5sec++; //Counter to check if key is pressed for 5 sec
              button_timer_50ms++; //Independent counter to reset status if button is released

              if(button_timer_50ms==50) //if no key pressed for 50ms, reset all status
              {
                    button_timer_50ms = 0;
                    button_pressed = 0;
                    timer_5sec = 0;
                    button_data = 0;
              }
              if(timer_5sec == 5000) //5sec done
              {
                    timer_5sec = 0;
                    button_data = 0;
                    button_pressed = 0;
                    button_timer_50ms = 0;
                    //Buzzer_ON
              }
           }
        }
     }
  }