【问题标题】:Issue with Button Toggle with STM8 BoardSTM8 板的按钮切换问题
【发布时间】:2021-09-16 10:28:38
【问题描述】:

我是微控制器的初学者。我正在使用定制的 STM8 板并使用板载按钮来计算按下的次数。我无法让它工作,这是我的代码,如果可以,请提供帮助 - 开关连接到 PA1。代码的相关部分-

void setup()
{
  GPIO_DeInit(GPIOA);
  GPIO_DeInit(GPIOB);
  GPIO_DeInit(GPIOC);
  GPIO_DeInit(GPIOD);

  GPIO_Init(GPIOA, GPIO_PIN_1, GPIO_MODE_IN_PU_IT); // **PA1 SWITCH**
}

void scan()
{

  if (GPIO_ReadInputPin(GPIOA, GPIO_PIN_1) == 0)
  {
    do 
    {
    }
    while(GPIO_ReadInputPin(GPIOA, GPIO_PIN_1) == 0);
    
    key_count++;
  }    
}    

【问题讨论】:

  • “不工作”不是问题描述。究竟是什么不工作?你期望什么行为,你会得到什么?
  • 话虽如此,您正在寻找的学习材料很可能是“开关去弹”。任何嵌入式系统初学者材料通常都会在第一章/课程中解决这个问题。
  • 你配置了外部中断吗?为什么 ISR 中的 key_count 变量没有增加?并且 key_count 被声明为 volatile 吗?按钮是高电平有效还是低电平有效?脑死的while循环又是怎么回事?
  • 它以何种方式“不起作用”。我们怎么知道你实际上是在打电话给setup() 或scan()? scan() 本身并没有尝试去抖动。它是否有效取决于调用scan() 的频率。您已将其标记为 [arduino],但不清楚这是 Arduino 代码 - 例如,没有 loop(),对 GPIO 函数的调用不是 Arduino 库调用。您还提到了 IAR - 工具链大多无关紧要,但这似乎与 Arduino 标签相矛盾。
  • @Sorenp - 很明显,正在轮询开关,while 循环在按下开关后等待开关释放。由于开关弹跳,它不太可能按预期运行并且很幼稚,但是,使用中断会引入其他问题 - 在这个阶段这可能是一个不必要的复杂化 - 当然是一个不同的问题。

标签: arduino embedded microcontroller iar stm8


【解决方案1】:

这里有很多要猜测的地方,但是由于您似乎是在轮询按钮而不是使用中断,所以您的初始化不正确:

GPIO_Init( GPIOA, GPIO_PIN_1, GPIO_MODE_IN_PU_NO_IT ) ; 
//                                            ^^^

感谢 cmets 中的 @Sorenp 发现这一点

即使使用正确的输入模式,scan() 函数也会阻塞(按住按钮时您的程序将停止执行任何有用的操作),并且不提供开关去抖动(开关很少干净地改变状态)。因此,我建议使用去抖动时间进行非阻塞轮询:

#define DEBOUNCE_MILLIS 20

void scan()
{
    // Button states
    typedef enum
    {
        BTN_DN = 0,
        BTN_UP = 1
    } tBtnState  ;

    static tBtnState  previous_button_state = (tBtnState)GPIO_ReadInputPin(GPIOA, GPIO_PIN_1) ;
    static unsigned long timestamp = 0 ;

    tBtnState  current_button_state = (tBtnState)GPIO_ReadInputPin(GPIOA, GPIO_PIN_1) ; 

    // If button down...
    if( current_button_state == BTN_DN )
    { 
        // ... and was previously up (transition event)...
        if( previous_button_state == BTN_UP )
        {
            timestamp = millis() ;
            previous_button_state = BTN_DN ;

            key_count++ ;
        }
    }
    // If button has been released for at least the debounce period...
    else if( millis() - timestamp > DEBOUNCE_MILLIS )
    {
        previous_button_state = BTN_UP ;
    }
}    

然后您可以简单地“频繁”调用scan(),同时执行您的代码需要执行的任何其他操作:

void main()
{
    // Initialise
    setup() ;

    // executive loop
    for(;;)
    {
        // Count button presses
        scan() ;

        // Do other stuff
    }
}

scan() 处理自己的时间,因此不需要以特定速率调用 - 速度足以捕捉任何按钮按下,因此您在循环中执行的任何其他操作都必须同样非阻塞,以便循环迭代并且永远不会超过 100 毫秒才能到达 scan()。

既然你标记了它 [arduino],我假设 Arduino millis() 函数可用,但不清楚这是否真的是 Arduino 代码。酌情替换自己的计时函数或标准库clock()。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-18
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 2021-03-10
    • 2012-12-09
    • 1970-01-01
    相关资源
    最近更新 更多