我对AVR编程非常陌生。我有一个ATMEGA8,想做这样的东西:
如果你按按钮,一个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
}
}即使我只按了一小段时间,压电键也会继续工作,直到眨眼的引导功能结束为止。
很抱歉英语能力不好。我希望你能理解我的问题也许你能帮我。
发布于 2014-10-12 14:48:21
实现您的目标的最简单的方法也许是轮询LED循环中的按钮,就像您已经在按钮循环中一样。然而,作为一种通用的解决方案,它的内聚性较差,不能扩展到更复杂的应用程序。
实现并发的一种通用方法是使用状态机进行LED控制,而不需要中断或多任务调度程序。
与其调用led()并要求它在返回之前完成整个闪存序列,状态机将简单地确定按钮是否被按下,以及是否是时候更改发光二极管的状态,然后立即返回。它会跟踪时间和状态,但不会在一次调用中执行完整的LED序列。

这是在下面实现的,但是请注意,时间是粗糙的,并且使用您已经使用过的延迟函数来实现--因为我不能告诉您还有哪些其他服务可用。如果任何处理需要花费大量时间,这可能会影响闪存时间。它依赖于每10毫秒调用一次LED状态机,而且它只对呼叫进行计数。如果状态机使用独立的时钟源(例如标准库clock()函数),那么它是否被不定期地调用并不重要--而不是计算调用的次数,它将根据实际传递的时间切换状态。
注意使用static变量来维护状态。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,如果它还没有闪烁,并且十个周期完成,即使按钮被释放。如果您希望在释放按钮时停止闪烁,那么start_flashing必须在LED_FLASH_OFF和可能的LED_FLASH_ON状态中进行测试,并导致早期返回到LED IDLE。例如:

该方法可以很容易地适应于在定时中断上运行LED状态机.与以按钮状态作为参数的ledUpdate()不同,它可以通过共享变量传递给中断处理程序。其余的状态机代码将保持不变。然后,主循环将在按钮关闭时简单地设置共享变量。
就我个人而言,我主张分离和封装压电控制、按钮轮询和LED控制,这样主循环看起来就像:
int main()
{
for(;;)
{
int button_state = getButtonState() ;
upodatePiezo( button_state ) ;
updateLed( button_state ) ;
}
}这将产生更紧密的内聚力和更松散的耦合。在软件设计中,两个有用的目标是实现代码的可维护性和可重用性。
https://stackoverflow.com/questions/26325687
复制相似问题