[英]AVR C Programming two functions on button press with delay
我真的是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
}
}
即使我短按一下按鈕,壓電也會一直保持到閃爍LED功能結束。
對不起,英語能力很差。 希望您了解我的問題,也許您可以幫助我。
實現目標的最簡單方法可能是輪詢LED回路中的按鈕,就像您已經在按鈕回路中一樣。 但是,作為一般解決方案,它的內聚性很差,無法擴展到更復雜的應用程序。
在不求助於中斷或多任務調度程序的情況下,實現並發的通用方法是使用狀態機進行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 ) ;
}
}
那將具有更嚴格的凝聚力和更寬松的耦合。 在軟件設計中有兩個有用的目標,可以實現代碼的可維護性和可重用性。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.