Как контролировать мощность attiny13a через прерывание смены контакта?

Я пытаюсь контролировать мощность attity13a и включать/выключать светодиод.
Я иду к целям:

  • После нажатия кнопки0 светодиод будет мигать 5 секунд, а затем attiny13a перейдет в спящий режим.
  • После того, как вы нажмете кнопку1, разбудите attiny13a, после чего загорится светодиод.

Кнопка0 для сна и мигания светодиода. button1, чтобы проснуться и включить светодиод.
Не могли бы вы объяснить, что не так в этом скетче, пожалуйста? спасибо за ваши ответы.


код:

    #define F_CPU   1200000UL
    #define LED     PB2 // PB2
    #define BUTTON1 PB1 // PCINT1
    #define BUTTON0 PB0 // PCINT0

    #define HIGH         1
    #define LOW          0
    #define INPUT        0
    #define OUTPUT       1
    #define INPUT_PULLUP 2
    #define FALSE        0
    #define TRUE         1
    #define _BV(bit)    (1 << (bit))

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

    void pinMode(uint8_t pin, uint8_t mode)
    {
        if(mode == OUTPUT) // Закрепить как вывод
            DDRB |= _BV(pin);
        else // Пин как ввод или подтягивание ввода
        {
            DDRB &= ~_BV(pin); // Устанавливаем пин как вход
            if(mode == INPUT_PULLUP)
                PORTB |= _BV(pin); // Включить подтягивающие резисторы
        }
    }

    void digitalWrite(uint8_t pin, uint8_t val)
    {
      if(val)
        PORTB |= _BV(pin);  // Установить вывод на высокий уровень
      else
        PORTB &= ~_BV(pin); // Устанавливаем низкий уровень вывода
    }

    uint8_t digitalRead(uint8_t pin)
    {
      return !!(PINB & _BV(pin));
    }

    // идти спать
    ISR(PCINT0_vect)
    {
       if(digitalRead(BUTTON0)){
            int i=0;
            while(i<10){
                blink();i=i+1;
            }
            set_sleep_mode(SLEEP_MODE_PWR_DOWN);
            sleep_enable();
            sleep_cpu();
        }
    }

    //проснуться
    ISR(PCINT1_vect){
       if(digitalRead(BUTTON1)){
        digitalWrite(LED, HIGH);
       }
    }

    void blink(){
        digitalWrite(LED, LOW);
        _delay_ms(500);
        digitalWrite(LED, HIGH);
        _delay_ms(500);
    }

    int main(void)
    {
        pinMode(BUTTON0, INPUT_PULLUP);
        pinMode(BUTTON1, INPUT_PULLUP);

        pinMode(LED, OUTPUT);
        digitalWrite(LED, LOW);

        // Устанавливает маску прерывания смены контакта PB0, PB1
        PCMSK |= _BV(PCINT0)|_BV(PCINT1);   

        // Включает прерывания глобально после установки
        //сей();
        SREG |= _BV(SREG_I); 

        while(TRUE){}
    }

, 👍1

Обсуждение

Программа работает? Если нет, то каково его поведение?, @Edgar Bonet

Светодиод горит и ничего не происходит при нажатии на кнопки, @Kvartu

Как подключен светодиод?, @Majenko

Обратите внимание, что у blink() отсутствует задержка в состоянии HIGH, а у tiny13 нет PCINT1_vect., @Edgar Bonet

Короткая ножка светодиода подключена к GND. Длинная ножка светодиода подключена к резистору (1кОм) и к PB2, @Kvartu

Обновлена функция мерцания., @Kvartu

Объясните, пожалуйста, как правильно перейти в режим энергосбережения и вывести attiny из режима энергосбережения?, @Kvartu

Вам необходимо включить PCIE в GIMSK для распознавания прерываний PCINT. Также все прерывания проходят через PCINT0_vect, и вы должны различать контакты внутри него., @Majenko

Помимо проблем, указанных выше, ваш код также не учитывает отказ от переключения., @Gerben

действительно ли программа загружается в attiny13a? ... вы можете запустить простую программу, которая мигает светодиодом?, @jsotola


1 ответ


Лучший ответ:

1
#define F_CPU   1200000UL

#define LED     PB2 // PB2
#define BUTTON1 PB1 // INT0
#define BUTTON0 PB0 // PCINT0

#define HIGH         1
#define LOW          0
#define INPUT        0
#define OUTPUT       1
#define INPUT_PULLUP 2
#define FALSE        0
#define TRUE         1
#define _BV(bit)    (1 << (bit))

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

void pinMode(uint8_t pin, uint8_t mode){
    if(mode == OUTPUT) // Закрепить как вывод
        DDRB |= _BV(pin);
    else // Пин как ввод или подтягивание ввода
    {
        DDRB &= ~_BV(pin); // Устанавливаем пин как вход
        if(mode == INPUT_PULLUP)
            PORTB |= _BV(pin); // Включить подтягивающие резисторы
    }
}

void digitalWrite(uint8_t pin, uint8_t val){
  if(val)
    PORTB |= _BV(pin);  // Установить вывод на высокий уровень
  else
    PORTB &= ~_BV(pin); // Устанавливаем низкий уровень вывода
}

uint8_t digitalRead(uint8_t pin){
  return !!(PINB & _BV(pin));
}

//проснуться
ISR(INT0_vect){
   sleep_disable();
   //кли(); // Отключаем глобальные прерывания
   digitalWrite(LED, HIGH);
}

void blink(){
    digitalWrite(LED, LOW);
    _delay_ms(1000);
    digitalWrite(LED, HIGH);
    _delay_ms(1000);
}

// идти спать
ISR(PCINT0_vect)
{
   //кли(); // Отключаем глобальные прерывания
   if(!digitalRead(BUTTON0)){
        cli(); // Отключаем глобальные прерывания

        blink();

        digitalWrite(LED, LOW);

        sei(); // Включаем глобальные прерывания
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);
        sleep_enable();
        sleep_cpu();
    }
}

int main(void)
{
    // разрешено внешнее прерывание
    MCUCR=0;
    //MCUCR=0b00000000;
    GIMSK|=_BV(INT0); // разрешено внешнее прерывание INT0 - PB1

    // Устанавливает маску прерывания смены вывода
    GIMSK|=_BV(PCIE);
    PCMSK|=_BV(PCINT0);//PB0

    pinMode(LED, OUTPUT);       
    digitalWrite(LED, LOW);

    pinMode(BUTTON1, INPUT_PULLUP);//INT0 - PB1
    pinMode(BUTTON0, INPUT_PULLUP);//PCINT0 - PB0

    // Включает прерывания глобально после установки
    //SREG |= _BV(SREG_I);
    sei(); // Включаем глобальные прерывания
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_enable();
    sleep_cpu();

    while(TRUE){}

    return 0;
}
,