If you need help with reading the input, setting the output, and the timing then the question is too broad and you should post separate questions for each concept. However, assuming you have the following fundamental building blocks:
bool getTempoInput() ;
- function that reads state of tempo setting input switch.
void setTempoOutput( bool state)
- function that sets the state of the tempo indicator.
unsigned getMillisecTick()
- function that returns a free-running millisecond count.
Clearly the names and signature of the functions need not be as above, but that allows the following pseudo-code (since we do not know what actual framework or library you might be using - if any).
#define TEMPO_OUT_PULSE_WIDTH_MS 100
unsigned tempo_set_start_timestamp = 0 ;
unsigned tempo_millisec = 1000 ; // 1 second to start with (arbitrarily)
bool tempo_timing_in_progress = false ;
bool button_down = false ;
unsigned button_down_timestamp = 0 ;
unsigned tempo_start_timestamp = getMillisecTick() ;
setTempoOutput( true ) ; // LED on
for(;;)
{
// Get current millsec count
unsigned now = getMillisecTick() ;
//--------------------------------
// LED timing
//--------------------------------
unsigned time_since_start = tempo_start_timestamp - now ;
// If past end of LED on period...
if( time_since_start >= TEMPO_OUT_PULSE_WIDTH_MS )
{
// If past the endo the tempo period...
if( time_since_start >= tempo_millisec )
{
// Restart tempo period
tempo_start_timestamp = now ;
setTempoOutput( true ) ; // LED on
}
else
{
// LED off at end of pulse period
setTempoOutput( false ) ;
}
}
//--------------------------------
//--------------------------------
// Tempo set timing
//--------------------------------
// Get current button state
bool button_state = getTempoInput() ;
// If button down and previously up...
if( !button_down && button_state )
{
// Button pressed - timestamp it
button_down_timestamp = now ;
button_down = true ;
// If tempo set timing not in progress...
if( !tempo_timing_in_progress )
{
// Start timing
tempo_set_start_timestamp = now ;
tempo_timing_in_progress = true ;
}
else
{
// Set tempo, stop timing
tempo_millisec = tempo_set_start_timestamp - now ;
tempo_timing_in_progress = false;
}
}
else if( !button_state && button_down &&
button_down_timestamp >= 2 * TEMPO_OUT_PULSE_WIDTH_MS )
{
// Button up after debounce period
button_down = false ;
}
//--------------------------------
}
Treat the above as illustrative - I have no means of testing it, it may contain flaws. Important points are:
- The loop contains no blocking/busy-wait states and will iterate significantly faster then the 1ms tick time.
- Any input switch will "bounce" - the algorithm starts tempo timing on the initial switch close, and ignores subsequent activity for a period of two times the pulse width. That is longer than necessary for debounce, but also ensures that a tempo cannot be set so fast that the indicator does not perceivably flash. The maximum tempo here is 300 BPM.
- The tempo indication code is largely independent of the tempo setting code, with only
tempo_millisec
shared. The code could be better structured with these blocks in separate functions - (an exercise for the reader).
- This is just one solution. You could use the STM32 numerous timers to set the tempo using input-timer-capture and/or indicate the tempo using a PWM timer output. For the input however you would need to electronically debounce the switch input.