Прошу помочь разобраться с прерываниями. Как их загрузить на Attiny13 через Arduino IDE?

Тема в разделе "Arduino & Shields", создана пользователем Unicname, 6 окт 2016.

  1. Unicname

    Unicname Нуб

    Я хочу чтобы по сигналу на первом прерывании на выход 9 подавалась "1" на две секунды, после чего на выходе 9 устанавливался бы нуль до следующего сигнала прерывания. Код ниже, и я не могу понять, почему после однократного нажатия, когда проходит цикл "loop", переменной state присваивается "1"? Ведь в конце этого цикла я присваиваю "0", "1" же должна быть только по прерыванию. В итоге у меня после первого сигнала прерывания происходит бесконечное мигание сигнального диода.


    int button = 1;
    int lazer = 9;
    volatile int state = LOW;

    void setup()
    {
    pinMode(lazer, OUTPUT);
    attachInterrupt (button, swap, RISING);
    }

    void loop()
    {
    digitalWrite(lazer, state);
    delay(2000);
    digitalWrite(state,LOW);
    digitalWrite(lazer,LOW);
    delay(1000);
    }
    void swap()
    {
    state = HIGH;
    }
     
  2. rkit

    rkit Гуру

    state это не пин, а переменная
     
  3. Unicname

    Unicname Нуб

    Спасибо, я по простоте душевной, думал, что можно и таким образом значения присваивать. У меня есть еще один вопрос. Я заменил:

    digitalWrite(state,LOW);
    digitalWrite(lazer,LOW);

    на

    state = 0;

    Почему у меня без приличного delay (в 0,5 - 1 с) нет четкого срабатывания? Дребезг контактов?
     
  4. rkit

    rkit Гуру

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

    rkit Гуру

    Если таймеры сильно сложно, то можно системным временем воспользоваться
    Код (C++):
    int button = 1;
    int lazer = 9;
    volatile unsigned long lastPress = 0L;

    void setup()
    {
      pinMode(lazer, OUTPUT);
      attachInterrupt (button, swap, RISING);
    }

    void loop()
    {
      digitalWrite(lazer, lastPress > millis());
    }

    void swap()
    {
      lastPress = millis() + 2000L;
    }
     
    Последнее редактирование: 6 окт 2016
  6. Unicname

    Unicname Нуб

    Не очень мне понятно, как оно работает...Почему оно горит 2 секунды, а не millis + 2 секунды? А гаснет потому что: "lastPress > millis()" - это выражение становится ложным? Еще вопрос про использование L на конце значения времени, просто раньше не сталкивался с этим. Может есть чего почитать про системное время, где я смогу найти ответы на эти вопросы?
     
  7. rkit

    rkit Гуру

    millis() возвращает время в миллисекундах с момента старта микроконтроллера. Я это назвал системным временем.
    При нажатии кнопки, в переменную устанавливается значение "время в момент нажатия + 2 секунды". Соответственно, пока записанное число больше текущего времени, светодиод горит. Когда проходит две секунды с нажатия, "время в момент нажатия + 2 секунды" становится меньше текущего времени, и светодиод гаснет.

    L на конце указывает, что введенное число имеет тип long. В данном случае это не очень важно, но иногда возникают проблемы из-за того, что не указал. Поэтому хорошей привычкой является указывать это всегда.
    https://www.arduino.cc/en/Reference/IntegerConstants
     
  8. Unicname

    Unicname Нуб

    Спасибо.
    Прочитал по ссылке. Там пишут что буква на конце указывает тип данных. А что главнее буква в конце или обозначение перед переменной? Т.е. в "unsignedlong lastPress =0L" переменная будет long или unsigned long?
     
  9. rkit

    rkit Гуру

    Вообще да. я ошибся немного. Надо было писать UL в скетче.
    В этой строчке 0L будет иметь тип long, но при присвоении этого значения в переменную lastPress она будет переведена в тип unsigned long.
     
  10. Unicname

    Unicname Нуб

    И снова здравствуйте!
    Решил я перенести данную программку на контроллер поменьше. Сначала залил на Attiny84, для этого пришлось привести скетч к виду:

    int button = 0;
    int lazer = 9;
    volatile int state = LOW;

    void setup()
    {
    pinMode(lazer, OUTPUT);
    attachInterrupt (button, swap, RISING);
    }

    void loop()
    {
    digitalWrite(lazer, state);
    state = 0;
    delay(100);
    }
    void swap()
    {
    state = 1;
    }

    видимо millis не проходит на Attiny, либо ее надо использовать каким-то хитрым способом.
    После решил перенести на Attiny13A. При компиляции выдается ошибка:

    ______________.ino: In function 'void setup()':
    ______________:8: error: 'attachInterrupt' was not declared in this scope

    Стандартные скетчи из библиотеки arduino заливаются и работают. А прерывание ему не нравится. В чем дело? Я уж думаю, что в ATtiny13 через Arduino IDE прерывания не записываются...
     
  11. rkit

    rkit Гуру

    У разных контроллеров разный набор периферии и функционал. Надо читать даташиты и разбираться.
     
  12. ZAZ-965

    ZAZ-965 Гуру

    @Unicname, из любопытства глянул в файл wiring.h из библиотеки Core13 - функции attachInterrupt() и detachInterrupt() закомментированы. Попробуйте раскомментировать.
     
  13. Unicname

    Unicname Нуб

    А что значит раскомментировать? У меня например файл wiring.h имеет такой вид. А каким он должен быть даже не догадываюсь.

    Код (C++):
    /*
    *** Core13 ***
    Arduino core designed for Attiny13 and similar devices.
    NO WARRANTEE OR GUARANTEES!
    Written by John "smeezekitty"
    You are free to use, redistribute and modify at will EXCEPT IF MARKED OTHERWISE IN A PARTICULAR SOURCE FILE!
    Version 0.19
    */

    #ifndef Wiring_h
    #define Wiring_h
    #include <avr/io.h>
    #include <stdlib.h>
    #ifdef __cplusplus
    extern "C"{
    #endif
    #define HIGH 1
    #define LOW 0
    #define INPUT 0
    #define OUTPUT 1
    #define false 0
    #define FALSE 0
    #define TRUE 1
    #define true 1
    #define PI 3.1416
    #define HALF_PI 1.57
    #define TWO_PI 6.283
    #define DEG_TO_RAD 0.0174533
    #define RAD_TO_DEG 57.2958
    #define SERIAL 0
    #define DISPLAY 1 //WTF are these?
    #define LSBFIRST 0
    #define MSBFIRST 1
    #define CHANGE 1
    #define FALLING 2
    #define RISING 3
    #define INTERNAL 1
    #define EXTERNAL 0
    #define DEFAULT 0
    #ifdef abs
    #undef abs
    #endif
    #define min(a,b) ((a)<(b)?(a):(b))
    #define max(a,b) ((a)>(b)?(a):(b))
    #define abs(x) ((x)>0?(x):-(x))
    #define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
    #define round(x)     ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
    #define radians(deg) ((deg)*DEG_TO_RAD)
    #define degrees(rad) ((rad)*RAD_TO_DEG)
    #define sq(x) ((x)*(x))
    #define interrupts() sei()
    #define noInterrupts() cli()
    #define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
    #define clockCyclesToMicroseconds(a) ( ((a) * 1000L) / (F_CPU / 1000L) )
    #define microsecondsToClockCycles(a) ( ((a) * (F_CPU / 1000L)) / 1000L )
    #define lowByte(w) ((uint8_t) ((w) & 0xff))
    #define highByte(w) ((uint8_t) ((w) >> 8))
    #define bitRead(value, bit) (((value) >> (bit)) & 0x01)
    #define bitSet(value, bit) ((value) |= (1UL << (bit)))
    #define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
    #define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
    typedef unsigned int word;
    #define bit(b) (1UL << (b))
    typedef uint8_t boolean;
    typedef uint8_t byte;
    void init(void);
    void pinMode(uint8_t, uint8_t);
    void digitalWrite(uint8_t, uint8_t);
    uint8_t digitalRead(uint8_t);
    int analogRead(uint8_t);
    void analogReference(uint8_t mode);
    void analogWrite(uint8_t, uint8_t);
    unsigned long millis(void);
    unsigned long micros(void);
    void delay(unsigned ms);
    void delayMicroseconds(unsigned int us);
    void shiftOut(uint8_t, uint8_t, uint8_t, uint8_t);
    uint8_t shiftIn(uint8_t, uint8_t, uint8_t);
    unsigned long pulseIn(unsigned char pin, unsigned char stat, unsigned long timeout);
    //void attachInterrupt(uint8_t, void (*)(void), int mode);
    //void detachInterrupt(uint8_t);
    void setup(void);
    void loop(void);
    #ifdef __cplusplus
    } // extern "C"
    #endif
    #endif
     
  14. ZAZ-965

    ZAZ-965 Гуру

    Убрать символы комментирования в начале строк
    Код (C++):
    //Сейчас
    //void attachInterrupt(uint8_t, void (*)(void), int mode);
    //void detachInterrupt(uint8_t);

    //Должно стать
    void attachInterrupt(uint8_t, void (*)(void), int mode);
    void detachInterrupt(uint8_t);
     
  15. Unicname

    Unicname Нуб

    После того как я это сделал, компилятор стал писать:

    ______________.cpp.o: In function `setup':

    ______________.ino:8: undefined reference to `attachInterrupt'

    Попробовал добавить #define attachInterrupt(), снова пишет:

    ______________.ino: In function 'void setup()':
    ______________:8: error: 'attachInterrupt' was not declared in this scope
     
  16. ZAZ-965

    ZAZ-965 Гуру

    Автор этой библиотеки не написал функции attachInterrupt и detachInterrupt, одного килобайта флеша мало для ардуиновских "костылей". Вам программирование Attiny13 на Arduino для некоего проекта или для обучения?
     
  17. Unicname

    Unicname Нуб

    Как бы и то, и другое. Хочу в маленький дешевый контроллер программку поместить. Скетч сейчас такой:
    Код (C++):
    int button = 0;
    int lazer = 9;
    volatile int state = LOW;

    void setup()
    {
    pinMode(lazer, OUTPUT);
    attachInterrupt (button, swap, RISING);
    }

    void loop()
    {
    digitalWrite(lazer, state);
    state = 0;
    delay(100);
    }
    void swap()
    {
    state = 1;
    }
    Если расписать без прерывания, мне кажется не влезет он туда. Можно еще конечно другие библиотеки для Attiny13 попробовать.
     
  18. fogary

    fogary Гик

    Какая конкретно выгода от использования прерывания, в данном коде (по сравнению с чтением состояния пина, прописанного в "button")?
     
  19. ostrov

    ostrov Гуру

    Такого размера код влезет куда угодно и без прерывания. Просто гонять в loopе опрос кнопки с паузой в 40-100мс (с целью антидребезга) и выполнять действия по условию: старое состояние 0, новое 1.
     
  20. Unicname

    Unicname Нуб

    Хотелось получать сигнал определенной длительности после каждого нажатия, затем и прерывание было нужно. Допустим при задержке в 100 мс маловероятно двукратное и более срабатывание кнопки, а если захочу увеличить время сигнала на выходе, то такая вероятность возрастает. В итоге пока контроллер будет занят выполнением цикла с задержкой, на вход может прийти несколько неучтенных сигналов.
    Ну а вообще я уже написал код без прерывания, он вполне влезает на Attiny13, я думал, он будет объемнее.
    Спасибо откликнувшимся!