1

我正在使用 STM32F411RE Nucleo 板为数字吉他效果踏板开发一些代码,并且我需要能够实现节拍速度。

一般来说,我对编码相当缺乏经验。有谁知道简单地按两次 GPIO 按钮、测量两次按下之间的间隔并将该值分配给参数的最简单方法?或者至少只是在那个延迟时间间隔并让 LED 闪烁?假设这将使用某种中断。

谢谢!

编辑:我将 STM32CubeIDE 与 HAL(硬件抽象层)库一起使用。通过使用这个库,我能够轻松读取输入并将输出发送到各种 GPIO 引脚。我也在使用一个外部 8MHz 时钟。

4

1 回答 1

1

如果您在阅读输入、设置输出和时间安排方面需要帮助,那么问题就太宽泛了,您应该针对每个概念发布单独的问题。但是,假设您具有以下基本构建块:

  • 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 定时器输出指示速度。但是,对于输入,您需要对开关输入进行电子去抖动。
于 2021-10-31T16:02:52.933 回答