Button press and hold detection in microcontroller - embedded

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

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.

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.

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
}
}
}
}
}

Related

Im having problems with the collisions im GMS2 using GML

Theoretically, when I touched an enemy I would lose one life and from three hearts I would have 2. What happens is that when I collide with him, the lives are all lost restarting the room because I have to when I reach 0 lives, the room restarts. I'm using GMS2 and using GML, I don't know anything about DnD... HereĀ“s my code to collision with enemy:
//create event
global.lifes = 3
//collision event
global.lifes -= 1
You'll need to implement an invulnerability function, that'll prevent the player character from getting damaged again on the next frame.
The most simple one would be a timer that counts down if you got hit, and if that timer is still counting down, then ignore the Collission Event.
See also my answer here about adding invincibility in GMS2:
https://stackoverflow.com/a/62769522/2735344

gsap, revert animation after play

I'd like to play an animation with gsap, but after it has finished playing, I want to reset it. Like after playing that animation, reset, after it is finished. Without clicking anywhere or calculating the play time, sleeping or waiting the process. Just simply something like:
TweenLite.to(thing, 1, {x:'-20px'}).reset();
(ideally, there is no reset call in gsap.. how to acieve this?)
I can't get it to work with .seek(), .time(), .pause().
Those always interrupt the animation.
Preferable I want to use a simple TweenLite, or if it has to, a TimelineLite.
Im searching / looking for it since hours..
There are many ways to do it, but here's a simple one:
TweenLite.to(thing, 1, {x:-20, onComplete:function() {
this.pause(0); //seeks the tween (this) to 0 (playhead's starting position) and pauses immediately.
}});
Does that help?

Simulate touch on ios7/8 [duplicate]

Is possible to simulate a touch event in specific screen's coordinates pressing a specific key on a fisical external keyboard (usb via camera connection kit or bluetooth) on ios jailbroken and all the elements that jailbreak involves?
I would use this to press a button in an app (amplitude) with my foot, i want to use a keyboard as a footswitch.
Just for a private use. No Appstore or Cydia.
Thanks.
You can write scripts on your computer and use your keyboard and mouse to control your iOS device based on the simulate touch library.
iOS13-SimulateTouch is an open-source library that allows you to simulate touch events at the system level. You can write scripts using any programming languages to simulate touch events on your iOS devices either remotely or locally. Please check the source code at [Github] iOS13-SimulateTouch
IOS13-SimulateTouch
iOS 11.0 - 13.6 system-level touch simulation iOS13 simuate touch
Jailbroken device required
Description
This library enables you to simulate touch events on iOS 11.0 - 13.6 with just one line of code! All the source code will be released later.
Features
Multitouch supported (no other library you can find supports multi touching).
Programmable. Control scripts can be programmed with all the programming languages you desire.
Instant controlling supported. The ios device can be controlled with no latency from other devices/computers.
System-level touch simulation (will not inject to any process).
Installation
Open Cydia - Sources - Edit - Add - http://47.114.83.227 ("http" instead of "https"!!! Please double check this.)
Install "ZJXTouchSimulation" tweak
Done
Code Example
Python Version
import socket
import time
# event types
TOUCH_UP = 0
TOUCH_DOWN = 1
TOUCH_MOVE = 2
SET_SCREEN_SIZE = 9
# you can copy and paste this method to your code
def formatSocketData(type, index, x, y):
return '{}{:02d}{:05d}{:05d}'.format(type, index, int(x*10), int(y*10))
s = socket.socket()
s.connect(("127.0.0.1", 6000)) # connect to the tweak. Replace "127.0.0.1" with the ip address of your device
s.send(("1"+formatSocketData(SET_SCREEN_SIZE, 0, 2048, 2732)).encode()) # tell the tweak that the screen size is 2048x2732 (your screen size might differ). This should be send to the tweak every time you kill the SpringBoard (just send once)
time.sleep(1) # sleep for 1 sec to get setting size process finished
s.send(("1"+formatSocketData(TOUCH_DOWN, 7, 300, 400)).encode()) # tell the tweak to touch 300x400 on the screen
# IMPORTANT: NOTE the "1" at the head of the data. This indicates the event count and CANNOT BE IGNORED.
s.close()
Actually the touch is performed by only one line:
s.send(("1"+formatSocketData(TOUCH_DOWN, 7, 300, 400)).encode())
Neat and easy.
Perform Touch Move
s.send(("1"+formatSocketData(TOUCH_MOVE, 7, 800, 400)).encode()) # tell the tweak to move our finger "7" to (800, 400)
Perform Touch Up
s.send(("1"+formatSocketData(TOUCH_UP, 7, 800, 400)).encode()) # tell the tweak to touch up our finger "7" at (800, 400)
Combining them
s.send(("1"+formatSocketData(TOUCH_DOWN, 7, 300, 400)).encode())
time.sleep(1)
s.send(("1"+formatSocketData(TOUCH_MOVE, 7, 800, 400)).encode())
time.sleep(1)
s.send(("1"+formatSocketData(TOUCH_UP, 7, 800, 400)).encode())
First the finger touches (300, 400), and then it moves to (800, 400), and then "leaves" the screen. All the touch events are performed with no latency.
Usage
After installation, the tweak will start listening at port 6000.
Use socket to send touch data field to the tweak
data field should always be decimal digits, specified below
NOTE: Usage might be updated in the future. I will update this post but please keep track on github at Usage_iOS13-SimulateTouch
Event Count(1 digit): Specify the count of the single events. If you have multiple events to send at the same time, just increase the event count and append events to the data.
Inside a single event
Type(1 digit): Specify the type of the single event.
Supported event type:
Event: Touch Up. Flag: 0. Description: Specify the event as a touch-up event
Event: Touch Down. Flag: 1. Description: Specify the event as a touch-down event
Event: Touch Move. Flag: 2. Description: Specify the event as a touch-move event (move the finger)
Event: Set Size. Flag: 9. Description: Set screen size (required!! Will be explained below)
Touch Index(2 digits): Apple supports multitouch, so you have to specify the finger index when posting touching events. The range of finger index is 1-20 (0 is reserved, don't use 0 as finger index).
x Coordinate(5 digits): The x coordinate of the place you want to touch. The first 4 digit is for integer part while the last one is for the decimal part. For example, if you want to touch (123.4, 2432.1) on the screen, you should fill "01234" for this.
y Coordinate(5 digits): The y coordinate of the place you want to touch. The first 4 digit is for integer part while the last one is for the decimal part. For example, if you want to touch (123.4, 2432.1) on the screen, you should fill "24321" for this.
Moreover
So if you want to touch down (123.4, 1032.1) with finger "3" on the screen, just connect to the tweak using socket and send "11030123410321".
Digit 0: "1" indicates there is only one event to perform.
Digit 1: "1" indicates event type: TOUCH_DOWN (the flag is 1).
Digit 2-3: "03" indicates this event is performed by finger "3".
Digit 4-8: "01234" indicates the x coordinate 123.4.
Digit 9-13: "10321" indicates the y coordinate 1032.1.
Important Note
The touch coordinate does not depend on the orientation of your device. See picture below to get more information. However you place your device, the click point on the screen will not be changed.

Libgdx - How to spawn particles only when I hold mouse button?

So I slowly got to know how to manipulate particle system and emitter in-game through the code, but there is one simple task I can't get to know how... How can I spawn particles ONLY when I hold the mouse button? I tried a work-around by setting the maxCount of emmiter to 0 when its not pressed but then it either doesnt emit particles at all, or just makes the existing ones disappear immidiately, which looks very unnatural and I don't want it. Is there a way to emit them "manually" in render method?
You probably want to do set the Emission scaled value on the particle emitter. You can leave the max count at whatever maximum particle number you want.
To turn off the creation of particles:
emitter.getEmission().setLow(0);
emitter.getEmission().setHigh(0);
To turn it back on:
emitter.getEmission().setLow(10);
emitter.getEmission().setHigh(10);
Try using a Pool combined with your listeners:
gitHub link
Ok this is what I got to make it work. "blowing" is basically a boolean that is true when holding mouse button and false when not.
if (blowing) {
effectEmitter.start();
} else {
effectEmitter.allowCompletion();
}

How would I go about creating levels in a game that scroll automatically?

I'm working on a 2D shmup, and the idea is that the level continuously scrolls automatically, and your character can move around the screen.
Now, I'm having trouble figuring out how I would implement this and Google hasn't been any help. Right now I have a scrolling background (the background position is simply decremented for each frame) and the player can move around freely in the window, but how would I go about creating the objects in the level? Would I just use a timer to trigger objects and enemies or is there a way to do it based on the position/width of the background (I'd prefer the second method...But I have no clue how that would be done)?
Since this is a general question and doesn't really pertain to any of my code that I've already written as far as I know, I don't think I need to include any of it...But I'll be happy to provide any part of it if needed.
I'd recommend either:
Use physical triggers
Use a list of timed events
Physical triggers
Simply place a box on your level. When it scrolls partially or completely onto the screen (whichever makes more sense - maybe use both in different cases?), you trigger the event associated with that trigger.
This would be simpler to support in a level editor because the physical nature is inherently very easy to visualize.
Timed events
You basically create a timer object at the beginning of the level, and an ordered queue of events. In your game update loop, peek at the head of the queue. If the trigger time of the item at the head of the queue is less than the current elapsed time, pop the item off the queue and trigger the event.
Timed events would be more generically useful because it would also support non-scrolling level, or non-scrolling portions of levels.
Combination of both
You could also do some sort of combination of these to get the benefits of both styles: Easier visualization/level editing, and supporting non-scrolling sections or time-based events.
Each physical trigger will have its own script queue. When the trigger is hit, a timer is started and an event queue is created. That timer and queue is added to a list of currently running timers and queues.
In your update function, you check all items on the list, and trigger events the same way you did with the timed event queue above. Once a queue is emptied, you remove it from the list of timers/queues.
How to detect that a trigger is on-screen
You should implement scrolling first.
One you have scrolling, calculate the rectangle that matches where the screen is located in your pixel/world coordinate system. This will give you the "bounding box" of the screen.
From here, do an intersection test between your event trigger's "bounding box" and the screen.
Here is a test to see if there is any overlap between two rectangles. It isn't order-specific:
rect1.left < rect2.right && rect1.right > rect2.left
&& rect1.top < rect2.bottom && rect1.bottom > rect2.top
If the rects are touching at all, it will return true.
Here is a test to make sure rect1 contains rect2. Order is important:
rect1.left <= rect2.left && rect1.right >= rect2.right
&& rect1.top <= rect2.top && rect1.bottom >= rect2.bottom
If rect2 is completely contained by rect1 (it is completely on-screen), it will return true.
How to implement simple timers
Simply get some sort of clock value (could be SDL_GetTicks), and store that value.
To see how long has elapsed since that timer was started, call the function again and subtract. Compare the values with < to see if the difference is greater than the target time.
Unfortunately, this is where you should use pointers. Something along the lines of:
vector<BadGuy*> Listofbaddies;
//Place enemy just off screen
newYposition = SCREEN_HEIGHT + 20;
//an infinite (almost) amount of badguys can be created with this code:
Listofbaddies.push_back(new Badguy(newXposition,
newYposition,
EnemyType,
blahblah);
Which means that the badguy will need a constructor like:
Badguy::Badguy(float newX, float newY, string Type, whateverelseyouwant){
actualSpritePartOfBadguyClass.setPosition(newX, newY);
}
Does that make sense? I'll elaborate if you ask :D
I'm making a game now that uses something similar :)