2014-10-12 69 views
0

我真的很新AVR编程。 我有一个ATMEGA8,想要做这样的事情:AVR C编程延时按钮上的两个功能

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

闪烁LED功能

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 
    } 
} 

主要代码:

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

压电停留,直到闪烁LED功能是过,即使我只是按下按钮的时间很短。

不好的英语技能。我希望你能理解我的问题,也许你能帮助我。

+0

简单但破坏组织,您可以在led功能内添加按钮状态的检查,并在那里只用四分之一秒延迟关闭压电,或者如果您将延迟分成较小的时间段并在两者之间检查,则更少。或者为了更有组织的解决方案,使用有状态事件驱动的设计并将领先的时间移至中断。或者保持原样并将压电元件移动到引脚电平变化中断。 – 2014-10-12 14:02:36

回答

3

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

a 通用实现并发性的方法,不借助中断或多任务调度程序就是使用状态机进行LED控制。

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

statemachine

这将在下面执行,但是请注意,时机是原油和使用你已经使用了延时功能实现的 - 因为我不能告诉其他的服务提供给您。如果任何处理需要很长时间,这可能会影响闪光时间。它依靠每10ms调用一次LED状态机,并且它只是对通话进行计数。如果状态机使用独立的时钟源(例如标准函数库clock())会更好,那么它是否被称为非周期性并不重要 - 而不是计算调用次数,它会切换状态实际时间已过。

注意使用static变量来维护状态。 A static在调用该函数之间保持其值。

#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如果尚未闪烁,完成十个周期,即使松开按钮。如果您希望释放按钮时闪烁停止,则必须在LED_FLASH_OFF和可能的LED_FLASH_ON状态中测试start_flashing,并且会导致提早返回到LED IDLE。例如:

statemachine2

的方法,可以很容易地适合于在一个定时器中断运行LED状态机。可以将按钮状态作为参数而不是ledUpdate(),这可以通过共享变量传递给中断处理程序。状态机代码的其余部分将保持不变。然后主循环会在按钮关闭时简单地设置共享变量。

个人身份证主张分离和封装所述压电控制,按钮轮询和LED控制,使得主回路看起来像:

int main() 
{ 
    for(;;) 
    { 
     int button_state = getButtonState() ; 
     upodatePiezo(button_state) ; 
     updateLed(button_state) ; 
    } 
} 

这将对桁条的凝聚力和更松散的耦合。软件设计中两个有用的目标是实现代码的可维护性和可重用性。

+0

非常感谢。 – 2014-10-12 18:15:48