2015-10-11 2 views
0

Я работаю над личным проектом, взламываю мультиметр и добавляю подсветку к нему. Я использую Attiny13.Почему работает только первое прерывание?

У меня есть следующий код:

/* IR_Switch.c 
* 
* Created: 30/11/2014 23:52:15 
* Author: keenox 
*/ 

#define F_CPU 128000UL // 128kHz osc, no prescaling 
#define SEC(VAL) ((unsigned int)(VAL) * F_CPU/256) 
#define INV_SEC(VAL) (F_CPU/256/(unsigned int)(VAL)) 

#include <avr/io.h> 
#include <avr/interrupt.h> 
#include <util/delay.h> 
#include <avr/sleep.h> 

#define FORCE_INLINE //__attribute__((always_inline)) 
#define PWM_ON() do { TCCR0A |= _BV(COM0A1); } while (0) 
#define PWM_OFF() do { TCCR0A &= ~_BV(COM0A1); } while (0) 
#define COUNTER_ON() do { counter = 0; TIMSK0 = _BV(TOIE0); } while (0) 
#define COUNTER_OFF() do { TIMSK0 = 0; } while (0) 

#define LED_ON() ((TCCR0A & _BV(COM0A1)) || (PORTB & _BV(PINB0))) 
#define BUTTON_DOWN() ((~PINB) & _BV(PINB3)) 
#define BUTTON_UP() (PINB & _BV(PINB3)) 

#define TIMEOUT 15 
char step = 50; 
unsigned long counter = 0; 

void ledFull(unsigned char _val) 
{ 
    PWM_OFF(); 
    if (_val) 
     PORTB |= _BV(PINB0); 
    else 
     PORTB &= ~_BV(PINB0); 
} 

void setLed() 
{ 
    if (OCR0A > 249) 
     ledFull(1); 
    else if (OCR0A < 6) 
     ledFull(0); 
    else 
     PWM_ON(); 
} 

ISR(TIM0_OVF_vect) 
{ 
    counter++; 

    if (BUTTON_UP()) 
    { 
     if (counter >= INV_SEC(4)) 
     { 
      PORTB |= _BV(PINB4); 
      if (!LED_ON()) 
      { 
       COUNTER_OFF(); 
      } 
      else if (counter >= SEC(TIMEOUT)) 
      { 
       ledFull(0); 
       COUNTER_OFF(); 
      } 
     } 
    } 
    else if (counter > SEC(3)) 
    { 
     // Change intensity every one sec while button down 
     counter -= SEC(1); 
     if (OCR0A > 249 || OCR0A < 6) 
     step = -step; 

     OCR0A += step; 
     setLed(); 
    } 
} 

ISR(PCINT0_vect) 
{ 
    cli(); 

    PCMSK = 0x0; 

    if (BUTTON_DOWN()) 
    { 
     MCUCR |= _BV(ISC00); // Switch to rising edge 
     COUNTER_ON(); 
    } 
    else 
    { 
     MCUCR &= ~_BV(ISC00); // Switch to falling edge 

     if (counter <= INV_SEC(2)) // Normal push 
     { 
      PORTB &= ~_BV(PINB4); 
     } 
     else if (counter <= SEC(2)) 
     { 
      if (LED_ON()) 
      { 
       ledFull(0); 
       COUNTER_OFF(); 
      } 
      else 
      { 
       setLed(); 
      } 
     } 
    } 

    PCMSK = _BV(PCINT3); 

    sei(); 
} 

int main(void) 
{ 
    DDRB = _BV(PINB4) | _BV(PINB0);    // All inputs, but PB4 output 
    PORTB = 0xFF & ~_BV(PINB0);  // All 1, except PINB0 
    MCUCR |= _BV(ISC01);   // Falling edge interrupt 
    GIMSK = _BV(PCIE);    // Activate only pin change interrupt 
    PCMSK = _BV(PCINT3);   // PB3 interrupt mask 

    TCCR0A = _BV(WGM01) | _BV(WGM00); // Set OC0A at TOP, Fast PWM 
    TCCR0B = _BV(CS00); // Timer on, No prescaling 
    OCR0A = 255; // Max bright 

    set_sleep_mode(SLEEP_MODE_PWR_DOWN); 
    COUNTER_OFF(); 

    while (1) 
    { 
     sleep_enable(); 
#if defined(sleep_bod_disable) 
     sleep_bod_disable(); 
#endif 
     sei(); 
     sleep_cpu(); 
     sleep_disable(); 
    } 
} 

Проблема заключается в том, что просыпается только на первом прерывания (кнопочный), выполняет его, а потом ничего. Если я не использую сон (оставьте только пока (1);) программа работает так, как ожидалось. Знаете ли вы, что может быть проблемой?

LE: Добавлен полный код. Если у меня есть:

sei(); 
while (1) {} 

Тогда все работает нормально. Я просто хочу использовать сон, чтобы уменьшить потребление.

+1

Возможно, есть что-то присутствующее в ISR, вызывающее эту проблему. – Jasen

+2

Или, возможно, в ISR что-то отсутствует. Обычно вам необходимо очистить прерывание (путем записи в регистр контроллера прерываний), чтобы разрешить повторное прерывание. – kkrambo

+0

@RaduC, пожалуйста, отправьте код прерывания, как указано выше, отметите, что это актуально. –

ответ

2

Ваш сон режим «Режим Power-вниз» , как описано в 7.1.3 of the reference manual

«только внешний сброс, сторожевой пес Reset, коричнево-из сброса, прерывания внешнего уровня на INT0 или контактный изменение прерывания может разбудить MCU. Этот спящий режим останавливает все созданные часы »

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

Вы хотите «спящий» режим ожидания.

+0

Спасибо! Вот и все. Извините за то, что вы выбрали ответ так поздно, у него не было много времени для этого проекта. –

Смежные вопросы