Як створити перерву таймера з Arduino?


9

Я намагаюся створити перерву в часі з Ардуїно. Я хотів би використовувати функцію переривання (), оскільки це внутрішнє переривання.

Приклад: Скажімо, я хотів би зробити легке миготіння увімкненням і вимкненням, лише час переривання.

Існує зразок коду, але він використовує зовнішні переривання (attachInterrupt ()). Я хотів би продовжувати використовувати внутрішні переривання.


2
Я думаю, що справа, яку також показав Кортук, полягає в тому, що attachInterrupt - це абстрактна річ, ти не прив’язуєш жодної зовнішньої складової :)
clabacchio

Ця стаття може вам допомогти. engblaze.com/…
Сет Арчер Браун

Відповіді:


10

У блозі Ноя Штала є приклад блимання світлодіода за допомогою таймера2 . За допомогою цього та інформаційного аркуша ви маєте змогу адаптувати його до того, який перерив ви хочете використовувати, тобто переривання, нормальну функцію якого ви найбільше можете дозволити відмовитись або готові змінити. Timer2 зазвичай використовується для деяких функцій ШІМ.

Його приклад наводить ATmega2560; Я можу підтвердити, що він також працює з ATmega328p. Перегляньте його сайт для більш корисних прикладів переривання Arduino.

Редагувати:

Ось моя трохи відредагована - переважно в коментарях - версія коду Ноя. Зателефонуйте Timer2init () за допомогою функції Arduino setup () після ініціалізації будь-яких пов'язаних структур даних або апаратних засобів, тому що час і час переривання почнуться, як тільки ви це зробите.

F / ex, я використовував його для мультиплексування 3-значного 7-сегментного дисплея, тому я, перш ніж ініціалізувати таймер, ініціалізував регістри вводу / виводу дисплея та списав дані дисплея в тому місці, де ISR буде шукати його.

У коментарях є таблиця деяких корисних даних про хронологію з опису та мої власні розрахунки для посилання для створення іншої схеми хронометражу.

Макрос ISR () піклується про створення коду введення та виходу переривання для ISR замість нормального входу та виходу функції та пов'язування її з належним вектором переривання. Решта цієї функції - 1) код, який потрібно запустити при кожному перериванні, і 2) код коду для скидання таймера для наступного переривання.

Як було написано, цей параметр повинен потрапляти до ескізу .pde або .ino (або файлу .cpp, якщо ви використовуєте eclipse, f / ex). Ескіз повинен #define LEDPIN, а setup () повинен викликати Timer2init (). Функція циклу може бути порожньою чи ні; світлодіод повинен почати блимати при завантаженні (ну буквально після виклику Timer2init ()).

/*
 * From sample interrupt code published by Noah Stahl on his blog, at:
 * http://arduinomega.blogspot.com/p/arduino-code.html
 * 
 */


/*** FUNC

Name:           Timer2init

Function:       Init timer 2 to interrupt periodically. Call this from 
                the Arduino setup() function.

Description:    The pre-scaler and the timer count divide the timer-counter
                clock frequency to give a timer overflow interrupt rate:

                Interrupt rate =  16MHz / (prescaler * (255 - TCNT2))

        TCCR2B[b2:0]   Prescaler    Freq [KHz], Period [usec] after prescale
          0x0            (TC stopped)     0         0
          0x1                1        16000.        0.0625
          0x2                8         2000.        0.500
          0x3               32          500.        2.000
          0x4               64          250.        4.000
          0x5              128          125.        8.000
          0x6              256           62.5      16.000
          0x7             1024           15.625    64.000


Parameters: void

Returns:    void

FUNC ***/

void Timer2init() {

    // Setup Timer2 overflow to fire every 8ms (125Hz)
    //   period [sec] = (1 / f_clock [sec]) * prescale * (255-count)
    //                  (1/16000000)  * 1024 * (255-130) = .008 sec


    TCCR2B = 0x00;        // Disable Timer2 while we set it up

    TCNT2  = 130;         // Reset Timer Count  (255-130) = execute ev 125-th T/C clock
    TIFR2  = 0x00;        // Timer2 INT Flag Reg: Clear Timer Overflow Flag
    TIMSK2 = 0x01;        // Timer2 INT Reg: Timer2 Overflow Interrupt Enable
    TCCR2A = 0x00;        // Timer2 Control Reg A: Wave Gen Mode normal
    TCCR2B = 0x07;        // Timer2 Control Reg B: Timer Prescaler set to 1024
}



/*** FUNC

Name:       Timer2 ISR

Function:   Handles the Timer2-overflow interrupt

Description:    Maintains the 7-segment display

Parameters: void

Returns:    void

FUNC ***/

ISR(TIMER2_OVF_vect) {
    static unsigned int led_state = 0; // LED state

    led_state = !led_state;         // toggles the LED state
    digitalWrite(TOGGLE_PIN, led_state);

    TCNT2 = 130;     // reset timer ct to 130 out of 255
    TIFR2 = 0x00;    // timer2 int flag reg: clear timer overflow flag
};

(@Kortuk: Коментар, до якого ви посилаєтесь, був моїм спостереженням за кількома коментаторами тут, і не був спрямований на вас особисто, і це було непотрібне. Прошу вибачення і я його зняв.) Я поширив свою відповідь, як ви запропонували, і сподіваюся, що це тепер не лише демонстративно, але й повчально. До неї входять коментарі, які я записав у код для власного використання (мається на увазі: Якщо я можу зрозуміти їх через 6 місяців, хтось ще зможе теж), а також кілька інструкцій "як користуватися" в розділі відповідь. Дякуємо за ваші пропозиції.
JRobert

Зауважте, що докадри 32 та 128 не доступні для таймера0 та таймера1 (принаймні, з atmega328).
тупополя

Це добре знати - дякую. Я використовую це для Timer2 (поки що), і це в основному випадання.
JRobert

5

Функція attachInterrupt () фактично приєднує переривання до зміни зовнішнього стану на штирі, інших параметрів вона не має.

На цій же сторінці параметри режиму вказані як:

режим визначає, коли має бути спровоковано переривання. Чотири константи визначені як дійсні значення:

  • НИСКО, щоб викликати переривання, коли штифт низький,
  • ЗМІНА, щоб викликати переривання кожного разу, коли штифт змінює значення
  • ВИСНУЙСЯ для запуску, коли штифт переходить від низького до високого,
  • ВІДКЛЮЄТЬСЯ, коли штифт переходить від високого до низького.

Вибачте, що є носієм поганих новин, це одна з перших речей, яку я також шукав.


Я думаю, що він означає, що він хоче використовувати внутрішній таймер, а не зовнішній пристрій ... але я не знаю Ардуїно дуже добре, тому не можу сказати, чи це можливо
clabacchio

@clabacchio, я кажу, що єдиним варіантом є використання зовнішнього тригера, немає внутрішньої функції таймера.
Кортук

Ах, добре :) але принаймні у дошках Arduino є таймери?
clabacchio

Так, саме вони виконують такі речі, як затримка.
Кортук

1
@ icarus74 ATMega328 дійсно має три таймери (один - 16b, а два - 8b), але всі вони використовуються Arduino. Один використовується для таких функцій, як затримка () та millis (), а всі три використовуються для ШІМ (додаткову інформацію можна знайти у функції 'init ()', файл 'wiring.c' в Arduino IDE).
vasco

2

Ця стаття про ШІМ очистить багато ваших сумнівів щодо використання таймерів Arduino. На Arduino є два 8-бітових таймерів та один 16-бітний таймер. Не існує API високого рівня, щоб підключити функцію ISR безпосередньо на таймери, що постачається разом з SDK Arduino (тобто як стандартна бібліотека), але дещо нижчий рівень встановлення регістрів спеціальних функцій та біт-арифметичних / операції над ними. Однак є бібліотека, внесена користувачем під назвою Timer one .


Насправді можливе кілька різних комбінацій таймерів, залежно від того, про який Arduino йдеться. Відповідь вводить в оману.
Здається, так,

@SeemngingSo, хочете допрацювати? Якщо ви говорите про обладнання Arduino, зауважте, що відповідь є в контексті запитання, а також часу, коли питання задається.
icarus74

Мега Arduino (заснована на ATmega1280) була випущена 26 березня 2009 року, а Mega 2560 (ATmega2560) була випущена 24 вересня 2010 року, і задовго до цього питання. Обидва мікроконтролери мають більше, ніж 2x 8 бітний та 1x 16 бітний таймер / лічильник, вказаний у відповіді.
Здається так,

Більшість взаємодій, які я бачив до цього часу, мають однозначну посилання на Arduino, щоб означати подібні Duemilanove або Uno, тобто дошки на основі серії 328. Інші дошки завжди були чітко кваліфіковані серії uP. або Mega, Nano, Micro тощо. Як би там не було, я покірно прийму виправлення. У цьому контексті краще уточнення.
icarus74

1

Arduino використовує всі три таймери в ATMega328. Timer1(16 біт) використовується для таких функцій, як delay()і millis()для виведення ШІМ на штифтах 5 і 6. Інші два таймери - Timer0і Timer2використовуються для виведення ШІМ на штифти 3, 9, 10, 11.

Отже, немає функції Arduino для переривання таймера. Але спосіб є. Ви можете використовувати цей код, щоб увімкнути перерву таймера на Timer2:

ISR(TIMER2_OVF_vect) {
  // Interrupt routine.
}

void setup() {
  // Enable Timer2 interrupt.
  TIMSK2 = (0<<OCIE2A) | (1<<TOIE2);
}

void loop() {
  // Your main loop.
}

Я написав цей код без тестування, тому, можливо, я допустив помилку. У цьому випадку перевірте таблицю даних, стор.156 .

Якщо ви хочете змінити частоту таймера (дошкольний), просто змініть регістр TCCR2A. Для отримання додаткової інформації дивіться на сторінці даних 153. Але якщо ви змінюєте частоту таймера, ви також змінюєте частоту ШІМ-сигналу на двох вихідних штифтах!


AFAIK на ATmega328 Timer0і Timer2є 8 бітним і лише Timer116 бітним.
tuupola

Ні, це не правильно. Для затримок () і milis () використовується Timer0, а не Timer1, а також для виведення ШІМ на штифтах 5 і 6. Timer0 - це 8-бітний таймер. Див. Наприклад Таймери та переривання Arduino .
Пітер Мортенсен
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.