2014-10-12 2 views
0

Я действительно новичок в программировании AVR. У меня есть ATMEGA8 и вы хотите сделать что-то вроде этого:AVR C Программирование двух функций при нажатии кнопки с задержкой

Если вы нажмете кнопку, светодиод должен включаться и выключаться 10 раз. РАБОТАЕТ. Но пока вы нажимаете кнопку, пьезо должен издавать звук. Проблема в том, что я не могу выполнять эти две функции одновременно.

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

Пьезоэлемент остается включенным, пока мигание не привели функция закончилась, даже если я просто нажать на кнопку в течение короткого промежутка времени.

Извините за плохое знание английского языка. Надеюсь, вы понимаете мою проблему и, может быть, можете мне помочь.

+0

Просто, но нарушая организацию, вы можете добавить проверки состояния кнопки внутри светодиодной функции и выключить пьезометр с задержкой в ​​четверть секунды или меньше, если вы разделите задержку на меньшие периоды и проверите. Или для более организованного решения используйте конструкцию, ориентированную на состояние событий, и переместите время синхронизации на прерывание. Или держите светодиод как есть и переместите пьезо на прерывание смены выводов. –

ответ

3

Простейший способ достижения вашей цели - это, возможно, опрос кнопки в светодиодной петле, поскольку вы уже находитесь в петле кнопки. Однако, как общее решение, оно имеет плохую сплоченность и не является расширяемым для более сложных приложений.

A общего назначения метод достижения параллелизма, не прибегая к прерываниям или многозадачному планировщику, заключается в использовании государственной машины для управления светодиодами.

Для того, Он отслеживает время и состояние, но не выполняет полную последовательность светодиодов в одном вызове.

statemachine

Это реализуется ниже, однако обратите внимание, что время является сырым и реализуется с помощью функции задержки вы уже использовали - потому что я не могу сказать, что другие услуги доступны для вас. Если какая-либо обработка займет какое-то значительное время, это может повлиять на время вспышки. Он полагается на вызов светодиодного состояния машины каждые 10 мс, и он просто подсчитывает вызовы. Было бы лучше, если бы устройство состояния использовало независимый источник синхронизации (например, стандартная библиотека 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 ; 
    } 
} 

Обратите внимание, что состояние кнопка действует только светодиод, если он уже не мигает, а десять циклов полный, даже если кнопка отпущена. Если вы хотите, чтобы мигание остановилось, когда кнопка была отпущена, то start_flashing необходимо протестировать в состоянии LED_FLASH_OFF и, возможно, в состоянии LED_FLASH_ON и вызвать раннее возвращение до LED IDLE. Например:

statemachine2

Способ может быть легко адаптирована к управлению СИД состояния-машины на прерывание таймера.Вместо ledUpdate(), принимая состояние кнопки в качестве параметра, это может быть передано обработчику прерываний через общую переменную. Остальная часть кода конечного автомата останется прежней. Основной цикл затем просто установил общую переменную, пока кнопка не была нажата.

Лично я бы выступать разделения и герметизирующего элемента управления пьезо, кнопка опроса, и светодиод управления таким образом, что основной цикл был похож:

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

Это будет иметь стрингера сплоченность и рыхлую связь. Две полезные цели в разработке программного обеспечения для обеспечения ремонтопригодности и повторного использования кода.

+0

большое спасибо. –