首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >AVR C在延迟按下按钮上的两种功能

AVR C在延迟按下按钮上的两种功能
EN

Stack Overflow用户
提问于 2014-10-12 13:35:29
回答 1查看 8.1K关注 0票数 0

我对AVR编程非常陌生。我有一个ATMEGA8,想做这样的东西:

如果你按按钮,一个LED应该打开和关闭10次。很管用。但只要你按下按钮,压音器就会发出声音。问题是我不能同时完成这两个功能。

闪烁LED功能

代码语言:javascript
复制
 int i;
 void led(void) 
 {
     for (i = 0; i < 10; i++)
     {
         PORTB |= (1 << PB0);  //LED on
         _delay_ms(250);       //wait 250ms

         PORTB &= ~(1 << PB0); //LED off
         _delay_ms(250);       //wait 250ms
     }
 }

主要守则:

代码语言:javascript
复制
while (1)
{
    if (!(PINB & (1<<PB7)) )
    {
        PORTB |= (1 << PB1); // Piezo on
        led();
    }
    else
    {
        PORTB &= ~(1 << PB1); // Piezo off
    }
}

即使我只按了一小段时间,压电键也会继续工作,直到眨眼的引导功能结束为止。

很抱歉英语能力不好。我希望你能理解我的问题也许你能帮我。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-10-12 14:48:21

实现您的目标的最简单的方法也许是轮询LED循环中的按钮,就像您已经在按钮循环中一样。然而,作为一种通用的解决方案,它的内聚性较差,不能扩展到更复杂的应用程序。

实现并发的一种通用方法是使用状态机进行LED控制,而不需要中断或多任务调度程序。

与其调用led()并要求它在返回之前完成整个闪存序列,状态机将简单地确定按钮是否被按下,以及是否是时候更改发光二极管的状态,然后立即返回。它会跟踪时间和状态,但不会在一次调用中执行完整的LED序列。

这是在下面实现的,但是请注意,时间是粗糙的,并且使用您已经使用过的延迟函数来实现--因为我不能告诉您还有哪些其他服务可用。如果任何处理需要花费大量时间,这可能会影响闪存时间。它依赖于每10毫秒调用一次LED状态机,而且它只对呼叫进行计数。如果状态机使用独立的时钟源(例如标准库clock()函数),那么它是否被不定期地调用并不重要--而不是计算调用的次数,它将根据实际传递的时间切换状态。

注意使用static变量来维护状态。static在对函数的调用之间维护其值。

代码语言:javascript
复制
#define TICK 10            // milliseconds 
#define FLASH_ON_TICKS 25  // 250ms
#define FLASH_OFF_TICKS 25 // 250ms
#define FLASH_COUNT 10

static void ledUpdate( int start_flashing ) ;

int main( void )
{
  for(;;)
  {
    // Perform loop on each tick (10ms)
    // Assumes loop processing time is not significant! 
    _delay_ms( TICK ) ;

    if (!(PINB & (1<<PB7)) )
    {
      PORTB |= (1 << PB1); // Piezo on
      ledUpdate( 1 ) ;  
    }
    else
    {
      PORTB &= ~(1 << PB1); // Piezo off
      ledUpdate( 0 ) ;  
    }
  }

  return 0 ;
}

void ledUpdate( int start_flashing )
{
  static enum
  {
    LED_IDLE,
    LED_FLASH_ON,
    LED_FLASH_OFF

  } led_state = LED_IDLE ;

  static int led_tick = 0 ;
  static int flash_count = 0 ;

  switch( led_state )
  {
    case LED_IDLE :
    {
      if( start_flashing )
      {
        led_state = LED_FLASH_ON ;
        PORTB |= (1 << PB0);  //LED on
      }
    }
    break ;

    case LED_FLASH_ON :
    {
      led_tick++ ;
      flash_count++ ;
      if( led_tick >= FLASH_ON_TICKS )
      {
        led_state = LED_FLASH_OFF ;
        led_tick = 0 ;
        PORTB &= ~(1 << PB0); //LED off
      }
    }
    break ;

    case LED_FLASH_OFF :
    {
      if( flash_count >= FLASH_COUNT )
      {
        led_state = LED_IDLE ;
      }
      else
      {
        led_tick++ ;
        if( led_tick >= FLASH_ON_TICKS )
        {
          led_state = LED_FLASH_ON ;
          led_tick = 0 ;
          PORTB |= (1 << PB0);  //LED on
        }
    }
    break ;
  }
}

请注意,按钮状态仅影响LED,如果它还没有闪烁,并且十个周期完成,即使按钮被释放。如果您希望在释放按钮时停止闪烁,那么start_flashing必须在LED_FLASH_OFF和可能的LED_FLASH_ON状态中进行测试,并导致早期返回到LED IDLE。例如:

该方法可以很容易地适应于在定时中断上运行LED状态机.与以按钮状态作为参数的ledUpdate()不同,它可以通过共享变量传递给中断处理程序。其余的状态机代码将保持不变。然后,主循环将在按钮关闭时简单地设置共享变量。

就我个人而言,我主张分离和封装压电控制、按钮轮询和LED控制,这样主循环看起来就像:

代码语言:javascript
复制
int main()
{
    for(;;)
    {
        int button_state = getButtonState() ;
        upodatePiezo( button_state ) ;
        updateLed( button_state ) ;
    }
}

这将产生更紧密的内聚力和更松散的耦合。在软件设计中,两个有用的目标是实现代码的可维护性和可重用性。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26325687

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档