如何在按下并释放一次按钮时打开 LED,然后通过再次按下和释放将其关闭?

Posted

技术标签:

【中文标题】如何在按下并释放一次按钮时打开 LED,然后通过再次按下和释放将其关闭?【英文标题】:How do I turn on LED while pressing and releasing the push button once and then turn it off by pressing and releasing it again? 【发布时间】:2021-04-24 13:12:24 【问题描述】:

我试图通过按下并释放按钮一次来打开 LED,然后通过再次按下和释放按钮来关闭它,依此类推。我一起写了一堆代码,但我不确定它是否正确。我的意思是我不知道这是我的面包板还是连接松动,但不确定它是否按预期工作。我知道接线是正确的,只需在按下按钮时将其打开,然后通过释放按钮将其关闭即可。任何帮助深表感谢。谢谢。

代码如下:

//Reset and clock control - Advanced high-performance bus - Enabling GPIO Port C pin 6 and Port B pin 1
RCC -> AHBENR |= RCC_AHBENR_GPIOCEN;
RCC -> AHBENR |= RCC_AHBENR_GPIOBEN;

//Setup Control Registers for the LED output
//Mode register as Output
GPIOC -> MODER |= GPIO_MODER_MODER6_0;
GPIOC -> MODER &= ~(GPIO_MODER_MODER6_1);
//OtypeR - Push pull
GPIOC -> OTYPER &= ~(GPIO_OTYPER_OT_6);
//OspeedR - High
GPIOC -> OSPEEDR |= GPIO_OSPEEDER_OSPEEDR6;
//PUPDR
GPIOC -> PUPDR &= ~(GPIO_PUPDR_PUPDR6);

//Setup control registers for the push button input
//Mode register as input
GPIOB -> MODER &= ~(GPIO_MODER_MODER1);
//Pull up pull down register
GPIOB -> PUPDR &= ~(GPIO_PUPDR_PUPDR1); // Connected to ground externally (no need for internal pupdr
int counter = 0;

  while (1)  
  //If the button is pressed (IDR - input data register)
  if((GPIOB -> IDR & (GPIO_IDR_1)) && counter == 0) //If button is pressed
  
      GPIOC -> BSRR |= GPIO_BSRR_BS_6; //Turn ON the LED
      if(~(GPIOB->IDR &(GPIO_IDR_1))) // If the button is released
      
          GPIOC -> BSRR |= GPIO_BSRR_BS_6; //LED stays ON
      
  
  counter = 1;

  if((GPIOB -> IDR & (GPIO_IDR_1)) && counter == 1) //If button is pressed
  
      GPIOC -> BRR |= GPIO_BRR_BR_6; //Turn OFF the LED
      if(~(GPIOB -> IDR &(GPIO_IDR_1))) // If the button is released
      
          GPIOC -> BRR |= GPIO_BRR_BR_6; //LED stays OFF
      
  
  counter = 0;
  

【问题讨论】:

你应该在内部 if 条件中设置计数器。 为什么不根据if (B interrupt) if (counter) ... else ... counter = !counter if (C interrupt) /* same logic */ 做出相同的决定,这样您只会在中断准备好时做出响应,即使您实际上复制了每个内部的开启/关闭逻辑。您是否考虑过启用中断处理程序——如果他们在 stm32 上有它们? 我还没有在stm32上开始中断。如果没有中断,这段代码是否仍然有效? 当然,无论您如何触发条件,相同的逻辑都将起作用。您可以直接从引脚读取,而不是使用中断。 “开关去抖动”为关键词,请自行搜索。 【参考方案1】:

你有几个问题。

第一个可能与去抖动有关。当您按下按钮时,电信号实际上在两个值之间振荡,最后,您的代码将认为“第二次按下按钮”可能只是开关的弹跳。

此外,当您的代码检测到按钮按下时,它不会等待按钮被释放,它只是打开 LED 并立即检查按钮是否已被释放。它不会在所有情况下都有效(无论如何你的代码在if(~(GPIOB->IDR &(GPIO_IDR_1))) 中没有做任何新的事情......)。

那么它可能无论如何都无法工作,因为您编码它的方式,您将丢失许多“新闻”事件。改用中断。

【讨论】:

按钮中断是个大问题。如果您使用中断,则可以将它们与计时器一起使用,以定期对按钮进行采样……在学习时或在某些应用程序中,这种轮询也可以很好地发挥作用,并且成功的机会更大。如果你不能通过轮询来解决它,你也会因中断而失败,加上找出中断的风险。 你指的是去抖问题吗?我同意这很棘手,但还有其他问题吗? (在管理带有中断的按钮时)

以上是关于如何在按下并释放一次按钮时打开 LED,然后通过再次按下和释放将其关闭?的主要内容,如果未能解决你的问题,请参考以下文章

如何在按下按钮后每 10 分钟重复一次方法并在按下另一个按钮时结束它

Android:如何在按下按钮时关闭一个活动并在按下另一个按钮时关闭整个后台堆栈? [复制]

需要帮助在按下精灵节点按钮时为其提供动画

使 matplotlib 按钮小部件在按下时启动,而不是在释放时启动

如何在按下按钮时下载 Flutter Web 应用程序?

鼠标左键点击是啥意思?