如果您在阅读输入、设置输出和时间安排方面需要帮助,那么问题就太宽泛了,您应该针对每个概念发布单独的问题。但是,假设您具有以下基本构建块:
bool getTempoInput() ;
- 读取速度设置输入开关状态的功能。
void setTempoOutput( bool state)
- 设置速度指示器状态的功能。
unsigned getMillisecTick()
- 返回自由运行的毫秒计数的函数。
显然,函数的名称和签名不必如上,但允许以下伪代码(因为我们不知道您可能使用的实际框架或库 - 如果有的话)。
#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 ;
}
//--------------------------------
}
将上述内容视为说明性的-我无法对其进行测试,它可能包含缺陷。重点是:
- 该循环不包含阻塞/忙等待状态,并且将比 1ms 滴答时间快得多。
- 任何输入开关都会“反弹”——算法在初始开关闭合时开始节拍计时,并在两倍脉冲宽度的时间段内忽略后续活动。这比去抖动所需的时间要长,但也确保不能将速度设置得太快以至于指示器不会明显闪烁。这里的最大速度是 300 BPM。
- 速度指示代码很大程度上独立于速度设置代码,只有
tempo_millisec
共享。使用这些块在单独的函数中可以更好地构建代码 - (读者练习)。
- 这只是一种解决方案。您可以使用 STM32 众多定时器来使用输入定时器捕获设置速度和/或使用 PWM 定时器输出指示速度。但是,对于输入,您需要对开关输入进行电子去抖动。