-
-
Notifications
You must be signed in to change notification settings - Fork 82
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Is there a way to run the button.loop function in the background using an interrupt timer ? #43
Comments
Hey Rene-Jean, well, sure, you could – in theory. I used callbacks and the |
Hello Lennard,
Thank you for your reply and your open mind.
I use your library with 100% success in the design I am working on (a power
supply controller). My request is probably a quirk on my part. I designed
such a library, a few years ago, but it is rudimentary. Yours is a jewel
and that is why I could not resist using it !!!
I am very old school. I am 75 years old and I design hardware (with Kicad)
and software (C++ on PlatformIO) just to keep my brain up and vigilant :-).
I spent most of my life in management, but never lost the taste of
electronics and computer software. Now that I am retired, I enjoy every
moment, programming and designing (...besides gardening of course:-)). In
those days (the late 70's and early 80's), I programmed 8080/Z80 processors
(2 MHz) and interrupts were a key to successful design. Still today, it is
the most efficient way to run my program ( some of my functions) in the
background ...governed by interrupts; ...specially with today's powerful
processor it is a pleasure of the mind!
If, as per you email, there is a need to shut off interrupts for critical
parts, STM32duino provides functionality for that (pause() and resume() :
https://github.com/frankpolte/stm32duino/blob/master/hardware/Arduino_STM32/STM32F4/cores/maple/HardwareTimer.h.
Here is an example of timer interrupt at :
https://github.com/frankpolte/stm32duino/blob/master/hardware/Arduino_STM32/examples/Maple/TimerInterrupts/TimerInterrupts.ino
.
If you decide to tackle and produce a first draft of if, It would be a
pleasure to be your first client to experiment with it.
My main loop() looks like this :
```
void loop(void) {
fp.button.loop();
if (myButtonState == ds.ButtonState::longClick) {
myButtonState = ds.ButtonState::noClick;
fp.normalModeSelectParameter(); // Select which parameter ("System Voltage Set" or "System Current Set") we want to modify
fp.normalModeModifyParameter(); // Modify the selected parameter
}
else if (myButtonState == ds.ButtonState::doubleclick) {
myButtonState = ds.ButtonState::noClick;
fp.presetModeSelectPreset();
fp.displayUpdatedConstantCurrentAndVoltageStatus(true); // Force update of Constant Voltage / Constant Current display update
fp.calculateAndDisplayOutputImpedance(true); // Force update of Impedance display
fp.calculateAndDisplayOutputPower(true); // Force update of Power Display
}
if(ds.variousData.displayModeOfOperation == ds.DisplayModeOfOperation::operationMode) {
fp.displayDataInVoltageOutputSetWindow(); // Display Set voltage on the screen
fp.displayDataInCurrentOutputSetWindow(); // Display Set Current on the screen
fp.getINA219Data(); // Get input voltage, circuit current, shunt voltage, ...
fp.adjustINA219Gain(); // Adjust INA219 gain to get maximum sensitivity of the device
fp.displayUpdatedOutputVoltage();
fp.displayUpdatedOutputCurrent();
fp.calculateAndDisplayOutputImpedance(false);
fp.calculateAndDisplayOutputPower(false);
fp.getVoltageOutputFeedback();
fp.getCurrentLimitFeedback();
fp.displayUpdatedConstantCurrentAndVoltageStatus(false); // Toggle between CC and CV windows
fp.displayUpdatedInputVoltage();
fp.displayUpdatedShuntVoltage();
fp.setPowerSupplyOutputVoltage(); // Send voltage data to MCP4922 DAC
fp.setPowerSupplyOutputCurrent(); // Send current data to MCP4922 DAC
}
}
```
=======================================
I added a flag setting in the handlers. This is what you see in main loop().
```
/*************************************************************************************************************************/
/* BUTTON SWITCH HANDLER SECTION */
/*************************************************************************************************************************/
/***************************************************************************************************************/
void handler(Button2& btn) {
int buttonType = btn.getType();
if (buttonType == single_click) {
myButtonState = ds.ButtonState::click;
Serial.print("---single ");
}
else if (buttonType == double_click) {
myButtonState = ds.ButtonState::doubleclick;
Serial.print("---double ");
}
else if (buttonType == triple_click) {
myButtonState = ds.ButtonState::tripleClick;
Serial.print("---triple ");
}
else if (buttonType == long_click) {
myButtonState = ds.ButtonState::longClick;
Serial.print("---long ");
}
Serial.print("click");
Serial.print(" (");
Serial.print(btn.getNumberOfClicks());
Serial.println(")");
}
'''
My best regards, Lennard,
René-Jean
|
Hello René-Jean, |
Hi Lennart!
This is great news!!!
Let me know when done. I will try it on STM32F401, the one I have been
using in the last design I refer to in my previous emails.
Regards,
Rene-Jean
=========================
Le dim. 30 oct. 2022, à 12 h 47, Lennart Hennigs ***@***.***>
a écrit :
… Hello René-Jean,
I will try to use an ESP32 and its interrupt timer with my class. Let's
see...
—
Reply to this email directly, view it on GitHub
<#43 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AGFVP32CKUYG2PY2IR4Y5L3WF2KCFANCNFSM6AAAAAAQ6CY4VI>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
Hey @renejeanmercier, I looked at your code above, you actually check button events in your main loop.
But I will still check out interrupt handlers regardless. |
Hello Lennart,
Thank you for your suggestion and your support.
Best regards,
Rene-Jean
Le lun. 31 oct. 2022, à 02 h 38, Lennart Hennigs ***@***.***>
a écrit :
… Hey @renejeanmercier <https://github.com/renejeanmercier>,
I looked at your code above, you actually check button events in your main
loop.
An alternative would be to use different handlers for your clicks and
handle it here.
This would declutter your main loop:
void longClickHandler(Button2& btn) {
myButtonState = ds.ButtonState::noClick;
fp.normalModeSelectParameter();
fp.normalModeModifyParameter();
}
void doubleClickHandler(Button2& btn) {
fp.presetModeSelectPreset();
fp.displayUpdatedConstantCurrentAndVoltageStatus(true);
.calculateAndDisplayOutputImpedance(true);
fp.calculateAndDisplayOutputPower(true);
}
But I will still check out interrupt handlers regardless.
—
Reply to this email directly, view it on GitHub
<#43 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AGFVP36GU6Q77I3S73VIZBDWF5SOZANCNFSM6AAAAAAQ6CY4VI>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Hey @renejeanmercier, Here is the sample code:
Most of the code is based on this example. I adjusted the interval to get a decent reading. Something in the 100ms to 10ms range is a good idea. So in general, it works fine. |
Hi Lennart,
I will get back to you with the loop() function driven by interrupt,
probably tomorrow. Thank you very much!
But in the meantime I tried to replace the setLongClickHandler(handler)
...which works fine (but you don't know if your press was long enough until
you release the button), by setLongClickDetectedHandler(handler) and I
noticed a side effect. Look at the log below and my comments in *bold*.
And this side effect is consistent.
You might want to look into it
…--- Terminal on /dev/ttyACM0 | 115200 8-N-1
--- Available filters and text transformations: colorize, debug, default,
direct, hexlify, log2file, nocontrol, printable, send_on_enter, time
--- More details at https://bit.ly/pio-monitor-filters
--- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H
Starting MMT Power Supply Interface !!!
PG set to PG40
EEPROM Beginning : 0
EEPROM End : 16384
System Voltage Set Value : 10.000
Corresponding DAC Voltage Output : 1.65
Corresponding DAC Binary Voltage Output : 2047
System Current Set Value : 0.500
Corresponding DAC Current Output : 0.82
Corresponding DAC Binary Current Output : 1023
System Input Voltage : 4.7820001
Output Voltage : 7.4822955
System Output Current : 0.0019200
Z Output : 3897.03
System Power W : 0.0090394
(1) *<------------------------------------------------------------- this
was a long click (not ok) ... it happens only once after boot-up, as if no
case in the function (see function below) was satisfied.*
---long click (1)
*<-------------------------------------------------------------
this was a long click (ok)*
ENTERING SELECTION MODE NORMAL OPERATION
---long click (1)
*<-------------------------------------------------------------
this was a long click (ok)*
Getting out of the Parameter Selection function
ENTERING MODIFICATION MODE
---long click (1)
*<-------------------------------------------------------------
this was a long click (ok)*
System Voltage Set Value : 10.000
Corresponding DAC Voltage Output : 1.65
Corresponding DAC Binary Voltage Output : 2047
Getting out of the Parameter Modificaton function
---double click (2)
*<-------------------------------------------------------------
this was a long click (ok)*
ENTERING PRESET SELECTION MODE
----Set pointer to the selected window
Set Coordinates To Preset Window
SetCoordinatesToPresetWindow preset3V3
*****Highlight Preset Window
*****Initialize Preset Window
CW Direction -- Encoder Value : 1
*******1----Set pointer to the selected window
++++Give Preset Colors To Window : preset5V0
Set Coordinates To Preset Window
SetCoordinatesToPresetWindow preset5V0
*****Highlight Preset Window
*****Initialize Preset Window
---double click (1)
*<-------------------------------------------------------------
this was a long click (not ok) ... it appens consistently.*
---long click (1)
*<-------------------------------------------------------------
this was a long click (ok)*
Preset Value Selected saved to EEPROM
System Voltage Set : 5.000
System Current Set : 0.500
System Input Voltage : 4.7900000
Output Voltage : 7.4725275
System Output Current : 0.0019200
Z Output : 3891.94
System Power W : 0.0095182
/*************************************************************************************************************************/
/* BUTTON SWITCH HANDLER SECTION */
/*************************************************************************************************************************/
/***************************************************************************************************************/
void handler(Button2& btn) {
switch (btn.getType()) {
case long_click:
myButtonState = ds.ButtonState::longClick;
Serial.print("---long click ");
//Serial.print(bf.buttonStatus.buttonState); Serial.print("\t");
break;
case double_click:
myButtonState = ds.ButtonState::doubleclick;
Serial.print("---double click ");
//Serial.print(bf.buttonStatus.buttonState); Serial.print("\t");
break;
case triple_click:
myButtonState = ds.ButtonState::tripleClick;
Serial.print("---triple click");
//Serial.print(bf.buttonStatus.buttonState); Serial.print("\t");
break;
case single_click:
myButtonState = ds.ButtonState::click;
Serial.print("---single click");
//Serial.print(bf.buttonStatus.buttonState); Serial.print("\t");
break;
}
Serial.print(" (");
Serial.print(btn.getNumberOfClicks());
Serial.println(")");
}
======================================================================
/***************************************************************************************************************/
void FunctionProcessing::buttonSetup() {
button.begin(ENCODER_SWITCH_PORT,INPUT_PULLUP,false,true); // byte
attachTo, byte buttonMode /* = INPUT_PULLUP */, boolean isCapacitive /* =
false */, boolean activeLow /* = true */
button.setDebounceTime(50); //
button.setLongClickTime(500);
button.setDoubleClickTime(700);
button.setClickHandler(handler);
button.setLongClickDetectedHandler(handler); //setLongClickHandler(handler);
button.setDoubleClickHandler(handler);
button.setTripleClickHandler(handler);
}
Regards,
Rene-Jean
=================================================
Le lun. 31 oct. 2022, à 13 h 16, Lennart Hennigs ***@***.***>
a écrit :
Closed #43 <#43> as
completed.
—
Reply to this email directly, view it on GitHub
<#43 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AGFVP37LUWES6RYFYWW4MNDWF75HVANCNFSM6AAAAAAQ6CY4VI>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Hello Lennart,
Sorry for the delay to get back to you. I had a knee operation and the pain
was such that concentration was not great.
Here is my hardware interrupt driven version (used in a multi-file
project), for an STM32F401 processor, with framework-arduinoststm32
package, with vs code under platformIO. It works gracefully! ...and is
immuned to function length, a problem I had detected with the button.loop()
call.
Here it is. You might want to publish it (be my guest), modified or as-is.
If you modify it and want me to test it, send me your version.
Also, I was wondering if you had time to look at the problem with
setLongClickDetectedHandler(handler).
It would be great not to have to figure out how long to press for a long
press :-).
Again Lennart, it is a GREAT library !!!
Thank you Lennart.
Regards,
Rene-Jean
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Hardware_Timer.h
#ifndef HARDWARETIMER_H
#define HARDWARETIMER_H
/* Various library header files */
#include "Arduino.h"
#include "HardwareTimer.h"
#include "DataStructure.h"
#include "Button2.h"
#include <stdint.h> // Documentation : AVR_2.0.0_Reference Manual
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <math.h>
#include <float.h> // DO NOT FORGET : pio.ini : build_flags =
-Wl,--undefined,_printf_float !!!!!!!!!!!!!
#include <dtostrf.h> // https://www.programmingelectronics.com/dtostrf/
/**************************************************************************************************************************/
/* Function declarations */
void handler(Button2& btn);
void button2ServiceIsr();
/* External variables */
extern int myButtonState;
/**************************************************************************************************************************/
class Hardware_Timer {
private:
/* Declaration of constants */
#define ENCODER_SWITCH_PORT PB14 // I/O port for the switch of the encoder
#define CLOCK_SAMPLE_PORT PB10
#define TIMER_INTERRUPT_FREQUENCY 10 // Timer period is 100 millisecond
public:
void initializeTimerInterrupt();
void buttonSetup();
}; // End of HardwareTimer class
static class Hardware_Timer ht;
#endif
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Hardware_Timer.cpp
#include "Hardware_Timer.h"
/**************************************************************************************************************************/
static Button2 button; // Instantiate a Button2 object
/**************************************************************************************************************************/
/* TO USE STM32DUINO FRAMEWORK TIMER, SEE :
https://github.com/stm32duino/STM32Examples/blob/main/examples/Peripherals/HardwareTimer/Timebase_callback_with_parameter/Timebase_callback_with_parameter.ino
*/
HardwareTimer Timer(TIM2);
/**************************************************************************************************************************/
void Hardware_Timer::initializeTimerInterrupt() {
Timer.pause(); // Pause the timer during the configuration
Timer.setOverflow(TIMER_INTERRUPT_FREQUENCY, HERTZ_FORMAT); // Desired
period
Timer.attachInterrupt(button2ServiceIsr); // Point to the interrupt routine
to be called
Timer.refresh(); // Update the parameters
Timer.resume(); // Start the timer
}
/**************************************************************************************************************************/
void button2ServiceIsr() { // Timer interrupt routine (called every
millisecond)
// Serial.print("."); // For timer testing purpose
// digitalWrite(CLOCK_SAMPLE_PORT, !digitalRead(CLOCK_SAMPLE_PORT)); //
Alternative For timer testing purpose
button.loop();
}
/***************************************************************************************************************/
void Hardware_Timer::buttonSetup() {
button.begin(ENCODER_SWITCH_PORT,INPUT_PULLUP,false,true); // byte
attachTo, byte buttonMode /* = INPUT_PULLUP */, boolean isCapacitive /* =
false */, boolean activeLow /* = true */
button.setDebounceTime(40); //
button.setLongClickTime(700);
button.setDoubleClickTime(500);
button.setClickHandler(handler);
button.setLongClickHandler(handler);
button.setDoubleClickHandler(handler);
button.setTripleClickHandler(handler);
}
/***************************************************************************************************************/
void handler(Button2& btn) {
int buttonType = btn.getType();
switch(buttonType) {
case single_click:
myButtonState = ds.ButtonState::click;
Serial.print("---single ");
//Serial.print(bf.buttonStatus.buttonState); Serial.print("\t");
break;
case double_click:
myButtonState = ds.ButtonState::doubleclick;
Serial.print("---double ");
//Serial.print(bf.buttonStatus.buttonState); Serial.print("\t");
break;
case triple_click:
myButtonState = ds.ButtonState::tripleClick;
Serial.print("---triple ");
//Serial.print(bf.buttonStatus.buttonState); Serial.print("\t");
break;
case long_click:
myButtonState = ds.ButtonState::longClick;
Serial.print("---long ");
//Serial.print(bf.buttonStatus.buttonState); Serial.print("\t");
break;
}
Serial.print("click");
Serial.print(" (");
Serial.print(btn.getNumberOfClicks());
Serial.println(")");
}
Le lun. 31 oct. 2022, à 13 h 16, Lennart Hennigs ***@***.***>
a écrit :
… Hey @renejeanmercier <https://github.com/renejeanmercier>,
I used an ESP32 (a M5Stack Core Gray
<https://docs.m5stack.com/en/core/gray>) to tie the loop() function to an
interrupt. And it works fine.
Here is the sample code:
#include "Button2.h"
#define BUTTON_PIN 39
hw_timer_t *timer = NULL;
Button2 btn;
void IRAM_ATTR onTimer() {
btn.loop();
}
void click(Button2 &b) {
Serial.println("click");
}
void setup() {
Serial.begin(9600);
btn.begin(BUTTON_PIN);
btn.setTapHandler(click);
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &onTimer, true);
timerAlarmWrite(timer, 100000, true); // every 0.1 seconds
timerAlarmEnable(timer);
}
void loop() {
}
Most of the code is based on this example
<https://circuitdigest.com/microcontroller-projects/esp32-timers-and-timer-interrupts>.
I adjusted the interval to get a decent reading. Something in the 100ms to
10ms range is a good idea.
So in general, it works fine.
Hope this proves helpful to you.
Cheers
l.
—
Reply to this email directly, view it on GitHub
<#43 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AGFVP3ZVCFJNAYLW5VBI4VDWF75HXANCNFSM6AAAAAAQ6CY4VI>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Hey Rene-Jean, I moved the LongClick to and will answer it there to have proper tracking: #46 Regardless, get well soon. |
Hi Lennart,
Yes I do feel much better now. Thank you !
Lot of sports at younger age to stay in shape (hockey, tennis, squask,
racketball) all knee related sports have an impact at holder age. :-(
Regards,
Rene-Jean
===============================
Le mar. 13 déc. 2022, à 14 h 50, Lennart Hennigs ***@***.***>
a écrit :
… Hey Rene-Sean,
I hope you are feeling better now.
Thank you for your code.
I will surely take a look at it.
In 2.1.0 I added an ESP32 interrupt example, as this is a common
controller.
I moved the LongClick to and will answer it there to have proper tracking:
#46 <#46>
Regardless, get well soon.
—
Reply to this email directly, view it on GitHub
<#43 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AGFVP35J4JUPENO63AOBYBDWNDHQXANCNFSM6AAAAAAQ6CY4VI>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Hello Mr. Hennings,
First thank you for your very useful library, Button2.
I would like the button.loop() function to run in the background, from a timer interrupt (like one of the timers on STM32F4xx) so that it would be independent of the aleas of other function execution lengths, and also avoid to periodically call the button.loop() function completely. The long click, single, double and triple click would simply set a flag that can be reset at any time after reading the status of the flag(s).
I have to say that I tried to call the button.loop() function from a timer interrupt function but without success.
Thank you for your help.
Regards,
Rene-Jean Mercier
renejeanmercier@gmail.com
The text was updated successfully, but these errors were encountered: