Прерывания arduino с помощью attachinterrupt
Содержание:
- Базовые вызовы
- Радиоуправление на ардуино
- Step 3: Example 1: Bike Speedometer
- Настройка программы Arduino IDE
- Собираем таймер
- Минимальные частоты и разрядность таймеров
- Шаг третий. Датчик приближения
- Методы библиотек TimerOne и TimerThree
- Результат
- Готовим программное обеспечение
- Step 5: Example 3: DAC
- Код проекта
- Примеры использования attachInterrupt
Базовые вызовы
/** * Init ISR (Interrupt service routine) for the timer and start timer. * * General algorithm * http://www.robotshop.com/letsmakerobots/arduino-101-timers-and-interrupts * 1. CPU frequency 16Mhz for Arduino * 2. maximum timer counter value (256 for 8bit, 65536 for 16bit timer) * 3. Divide CPU frequency through the choosen prescaler (16000000 / 256 = 62500) * 4. Divide result through the desired frequency (62500 / 2Hz = 31250) * 5. Verify the result against the maximum timer counter value (31250 < 65536 success). * If fail, choose bigger prescaler. * * Example: to set timer clock period to 20ms (50 operations per second == 50Hz) * * 1) on 16MHz CPU (AVR Arduino) * use prescaler 1:8 (TIMER_PRESCALER_1_8) and adjustment=40000-1: * 16000000/8/50=40000, minus 1 cause count from zero. * * 2) on 80MHz CPU (PIC32MX ChipKIT) * use prescaler 1:64 (TIMER_PRESCALER_1_64) and adjustment=25000-1: * 80000000/64/50=25000, minus 1 cause count from zero. * * 3) on 84MHz CPU (SAM Arduino Due) * use prescaler 1:128 (TIMER_PRESCALER_1_128) and adjustment=13125-1: * 80000000/128/50=13125, minus 1 cause count from zero. * * Timer interrupt handler timer_handle_interrupts would be called every 20ms * (50 times per second == 50Hz freq) in this case. * * @param timer * system timer id: use TIMER_DEFAULT for default timer * or _TIMER1...TIMER9, _TIMER1_32BIT..._TIMER9_32BIT for specific timer. * note: availability of specific timer depends on the platform. * @param prescaler * timer prescaler (1, 2, 4, 8, 16, 32, 64, 128, 256, 1024), * use constants: PRESCALER_1_1, PRESCALER_1_2, PRESCALER_1_8, * PRESCALER_1_16, PRESCALER_1_32, PRESCALER_1_64, PRESCALER_1_128 * PRESCALER_1_256, PRESCALER_1_1024 * note: availability of specific prescaler depends on the platform. * @param adjustment * adjustment divider after timer prescaled - timer compare match value. */ void timer_init_ISR(int timer, int prescaler, int adjustment); /** * Stop ISR (Interrupt service routine) for the timer. * * @param timer * system timer id for started ISR */ void timer_stop_ISR(int timer); /** * Timer ISR (Interrupt service routine) handler. * Implementation must be provided in module with user code. * * @param timer * system timer id for started ISR */ void timer_handle_interrupts(int timer);
Радиоуправление на ардуино
Используя arduino можно самостоятельно изготовить сложную систему радиоуправления не затрачивая, при этом, много усилий. Для популярной, на данный момент, платформы arduino существует огромное количество модулей расширяющих возможности данной платформы. Например модули nrf24l01 для радиосвязи.
Существует некоторое колличество разновидностей данного модуля. Есть модули для связи на расстояниях до 100м они небольшие и недорогиеРадиомодули рассчитанные на дальность до 100м можно запитать от вывода 3.3В с Arduino uno а радиомодули на дальность до 1100м от этого вывода запитать нельзя т.к.
данный вывод не способен выдать достаточный для нормальной работы модуля ток, поэтому если необходимо использовать модуль с дальностью радиосвязи до 1100м то необходимо использовать внешний стабилизатор на 3.3В для питания радиомодуля. О том как самостоятельно изготовить стабилизатор постоянного напряжения написано в статье http://electe.blogspot.
ru/2015/10/lm317.html там же есть программа для рассчёта. Этот стабилизатор просто надо сделать на 3.3В для того чтобы можно было им запитать радиомодуль. Ещё для того чтобы сделать систему радиоуправления на ардуино нужно само ардуино. Можно использовать почти любое (если не любое) ардуино.
Если необходима компактность то можно использовать другие ардуины например:
2) Arduino nano http://got.by/23nhej
Также можно использовать любое другое ардуино но эти два (описанных выше) проще всего. Есть например
3) Arduino pro mini http://got.by/23ni7b для программирования Arduino pro mini нужен usb-uart переходник или другое ардуино.
Теперь давайте рассмотрим схему передатчика:
Рисунок 1 – Передатчик на ардуино
У данного передатчика имеется 10 кнопок и 5 потенциометров. Допустим нам надо управлять дистанционно двумя серврмрторами, 3мя ШИМами, одним пьезодинамиком и 8ю цифровыми выходами для каких либо целей (напр.
сделать 8 фонарей на радиоуправлямый автомобиль или 1 фонарь а 7 выводов оставить для чего нибудь на будущее).
Рисунок 2 – Приемник на Ардуино
Напрямую к выводам ардуино можно подключать только маломощный пьезодинамик иначе слишком большой нагрузкой можно ардуино сломать. То же самое относится и ко всем остальным выводам на приёмнике.
К ним нельзя подключать слишком большую нагрузку для того чтобы Ардуино не испортилось. Для питания сервомоторов можно использовать отдельный источник питания. Если сервомоторы мощные то их вывод питания нельзя подключать к выводу питания ардуино.
Теперь давайте рассмотрим скетчь передатчика:
В начале скетча подключаются заголовочные файлы для связи с радиомодулем потом назначаются пины для связи с радиомодулем по SPI, указывается идентификатор трубы который должен совпадать с идентификатором трубы указанном в скетче приемника (см.
ниже), создаётся массив для передачи данных на приемник. Далее идёт функция инициализации в которой инициализируется и настраивается радиомодуль после чего он устанавливается на передачу данных, инициализируются входы ардуино и делается небольшая задержка на всякий случай.
В основном цикле считываются значения с потенциометров для сервомоторов и преобразуются в градусы функцией map. Далее, в следующую ячейку массива, запихиваются состояния входов ардуино побитно. После чего считываются значения с потенциометров для управления ШИМами, делятс на 4 т.к. аппаратный ШИМ ардуино принимает 1 байт.
Теперь скетчь приемника:
В приемнике помимо заголовочных файлов для связи с радиомодулем есть ещё заголовочный файл для работы с сервомоторами. Радиомодуль теперь настраивается на прием. В основном цикле происходит прием и раздача информации на периферию микроконтроллера ардуины.
Посмотреть видео по данной теме с испытаниями системы радиоуправления на ардуино:
Step 3: Example 1: Bike Speedometer
In this example I made an arduino powered bike speedometer. It works by attaching a magnet to the wheel and measuring the amount of time it takes to pass by a magnetic switch mounted on the frame- the time for one complete rotation of the wheel.
I set timer 1 to interrupt every ms (frequency of 1kHz) to measure the magnetic switch. If the magnet is passing by the switch, the signal from the switch is high and the variable «time» gets set to zero. If the magnet is not near the switch «time» gets incremented by 1. This way «time» is actually just a measurement of the amount of time in milliseconds that has passed since the magnet last passed by the magnetic switch. This info is used later in the code to calculate rpm and mph of the bike.
Here’s the bit of code that sets up timer1 for 1kHz interrupts
cli();//stop interrupts
//set timer1 interrupt at 1kHz
TCCR1A = 0;// set entire TCCR1A register to 0
TCCR1B = 0;// same for TCCR1B
TCNT1 = 0;//initialize counter value to 0
// set timer count for 1khz increments
OCR1A = 1999;// = (16*10^6) / (1000*8) — 1
//had to use 16 bit timer1 for this bc 1999>255, but could switch to timers 0 or 2 with larger prescaler
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS11 bit for 8 prescaler
TCCR1B |= (1 << CS11);
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
sei();//allow interrupts
Here’s the complete code if you want to take a look:
//bike speedometer //by Amanda Ghassaei 2012 //https://www.instructables.com/id/Arduino-Timer-Interrupts/ //https://www.instructables.com/id/Arduino-Timer-Interrupts/ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * */ //sample calculations //tire radius ~ 13.5 inches //circumference = pi*2*r =~85 inches //max speed of 35mph =~ 616inches/second //max rps =~7.25 #define reed A0//pin connected to read switch //storage variables float radius = 13.5;// tire radius (in inches)- CHANGE THIS FOR YOUR OWN BIKE int reedVal; long time = 0;// time between one full rotation (in ms) float mph = 0.00; float circumference; boolean backlight; int maxReedCounter = 100;//min time (in ms) of one rotation (for debouncing) int reedCounter; void setup(){ reedCounter = maxReedCounter; circumference = 2*3.14*radius; pinMode(1,OUTPUT);//tx pinMode(2,OUTPUT);//backlight switch pinMode(reed,INPUT);//redd switch checkBacklight(); Serial.write(12);//clear // TIMER SETUP- the timer interrupt allows preceise timed measurements of the reed switch //for mor info about configuration of arduino timers see http://arduino.cc/playground/Code/Timer1 cli();//stop interrupts //set timer1 interrupt at 1kHz TCCR1A = 0;// set entire TCCR1A register to 0 TCCR1B = 0;// same for TCCR1B TCNT1 = 0;//initialize counter value to 0; // set timer count for 1khz increments OCR1A = 1999;// = (16*10^6) / (1000*8) - 1 // turn on CTC mode TCCR1B |= (1 << WGM12); // Set CS11 bit for 8 prescaler TCCR1B |= (1 << CS11); // enable timer compare interrupt TIMSK1 |= (1 << OCIE1A); sei();//allow interrupts //END TIMER SETUP Serial.begin(9600); } void checkBacklight(){ backlight = digitalRead(2); if (backlight){ Serial.write(17);//turn backlight on } else{ Serial.write(18);//turn backlight off } } ISR(TIMER1_COMPA_vect) {//Interrupt at freq of 1kHz to measure reed switch reedVal = digitalRead(reed);//get val of A0 if (reedVal){//if reed switch is closed if (reedCounter == 0){//min time between pulses has passed mph = (56.8*float(circumference))/float(time);//calculate miles per hour time = 0;//reset timer reedCounter = maxReedCounter;//reset reedCounter } else{ if (reedCounter > 0){//don't let reedCounter go negative reedCounter -= 1;//decrement reedCounter } } } else{//if reed switch is open if (reedCounter > 0){//don't let reedCounter go negative reedCounter -= 1;//decrement reedCounter } } if (time > 2000){ mph = 0;//if no new pulses from reed switch- tire is still, set mph to 0 } else{ time += 1;//increment timer } } void displayMPH(){ Serial.write(12);//clear Serial.write("Speed ="); Serial.write(13);//start a new line Serial.print(mph); Serial.write(" MPH "); //Serial.write("0.00 MPH "); } void loop(){ //print mph once a second displayMPH(); delay(1000); checkBacklight(); }
Настройка программы Arduino IDE
После того как все детали соединены мы готовы снова вернуться к нашей Arduino IDE и создать блок кода для управления платой. Такой блок кода называют скетчем. Но для начала мы должны немного настроить нашу программу.
Сначала выбираем правильную плату с которой будем работать. Переходим в нужное меню и выбираем из списка нашу плату:
Tools → Board → Arduino Nano
Дальше мы обязательно должны выбрать на каком чипе сделана наша плата, т.к. Arduino Nano может идти в двух вариантах — с чипом ATmega168 и ATmega 328 (в нашем случае).
Tools → Processor → ATmega328
После мы убеждаемся, что правильно выбран серийный порт (Serial Port).
Tools → Port → COM8
И последнее — проверяем наш программер:
Собираем таймер
Как только электронные соединения собраны, можно собрать все вместе, т.е. к нашей схеме мы добавим еще и сам таймер в виде циферблата.
Возьмите лист бумаги или тонкого картона и вырежьте прямоугольное отверстие под сервопривод, как на фото выше. На этой бумаге мы должны нарисовать что-тор вроде циферблата, чтобы наблюдать сколько времени еще осталось.
Также мы прикрепляем стрелку из бумаги на поворотное плечо сервопривода. При установке стрелки нужно, чтобы сервопривод был направлен в крайнее левое положение.
Последний шаг для создания таймера — собрать все вместе и разместить уже в том месте, где вы хотите его применять. Для начала мы используем его в ванной комнате, чтобы отслеживать как тщательно мы моем руки.
Но таймер можно применять и для чистки зубов и для других целей, например, выполнения физических упражнений.
Позиционирование датчика HC-SR04 здесь является ключевым, т.к. нужно найти баланс. Датчик должен быть достаточно далеко от воды, но в то же время он должен без ложных срабатываний фиксировать движение ваших рук.
Ультразвуковой датчик работает, посылая ультразвуковые звуковые волны и измеряя время, необходимое для их возвращения. Если датчик получает отражения от предметов, которые не являются руками в раковине, он может без необходимости активировать таймер.
Внимание. Воды для электронных устройств очень опасна! Размещайте Arduino и другие детали дальше от влаги и воды.. Как только датчик вы разместили там, где нужно, — подключите Arduino к питанию, например, через USB-адаптер
Как только датчик вы разместили там, где нужно, — подключите Arduino к питанию, например, через USB-адаптер.
Сервопривод должен переместиться вперед и назад, демонстрируя активность таймера.
Минимальные частоты и разрядность таймеров
Варианты вызовов timer_init_ISR_2Hz (2Гц, период 500мс) и timer_init_ISR_1Hz (1Гц, период 1с) на PIC32MX 80МГц будут работать только с 32-битными таймерами (_TIMER2_32BIT и _TIMER4_32BIT; TIMER_DEFAULT — по умолчанию = _TIMER4_32BIT), т.к. при 16-битных режимах таймеров PIC32MX 80МГц комбинация «делитель частоты» (prescaler — максимальный вариант 1/256) + «поправка периода» (adjustment — максимальный вариант 2^16=65536-1) дают минимальную частоту 5Гц (период — 200мс):
80000000/256/65536 = 4.8Гц
На PIC32 32-битные таймеры создаются комбинацией 2х 16-битных таймеров:
- Timer4(32бит) = Timer4(16бит)+Timer5(16бит)
- Timer2(32бит) = Timer2(16бит)+Timer3(16бит)
поэтому при использовании таймера _TIMER2_32BIT, обычные таймеры _TIMER2 и _TIMER3 будут заняты, при использовании _TIMER4_32BIT — заняты будут _TIMER4 и _TIMER5.
На AVR/Arduino можно получить частоту 1Гц стандартными делителями на 16-битном таймере.
На SAM/Arduino Due все таймеры 32-битные.
Тип данных для параметра adjustment — unsigned int.
- На PIC32 разрядность int — 32 бит, этого хватит и для 16-тибитного режима таймера (если не закладывать значение более 2^16=65536-1) и для 32-битного (пойдет любое значение до 2^32=4294967296-1).
- На SAM разрядность int — 32 бит, все таймеры 32-битные.
- На AVR разрядность int — 16 бит, это опять же, как раз достаточно для 16-битных таймеров.
Таким образом, хотя разрядность параметра adjustment с типом int будет разной на разных платформах, во всех случаях значение будет соответствовать аппаратным свойствам таймеров.
Шаг третий. Датчик приближения
Инфракрасный датчик препятствий работает как кнопка, только не нужно ничего нажимать — достаточно просто поднести руки.
Подключу датчик напрямую к плате, как делал это в предыдущем проекте. Отличие одно: 4 контакт уже занят светодиодом, поэтому подключу сигнальную линию к 7 контакту.
Изменится и код.
Теперь плата постоянно находится в режиме ожидания, об этом сообщает зажённый красный светодиод. Когда сенсор обнаружит препятствие, плата запустит обратный отсчёт и начнёт мигать синим светодиодом. Когда пройдут 20 секунд, светодиод загорится зелёным, а потом плата вернётся в режим ожидания.
Методы библиотек TimerOne и TimerThree
Настройка
Вы должны вызвать этот метод первым, перед использованием любых других методов библиотеки. При желании можно задать период таймера (в микросекундах), по умолчанию период устанавливается равным 1 секунде
Обратите внимание, что это нарушает работу на цифровых выводах 9 и 10 на Arduino.
Устанавливает период в микросекундах. Минимальный период и максимальная частота, поддерживаемые данной библиотекой, равны 1 микросекунде и 1 МГц, соответственно
Максимальный период равен 8388480 микросекунд, или примерно 8,3 секунды. Обратите внимание, что установка периода изменит частоту срабатывания прикрепленного прерывания и частоту, и коэффициент заполнения на обоих ШИМ выходах.
Управление запуском
- Запускает таймер, начиная новый период.
- Останавливает таймер.
- Перезапускает таймер, обнуляя счетчик и начиная новый период.
Управление выходным ШИМ сигналом
Генерирует ШИМ сигнал на заданном выводе . Выходными выводами таймера Timer1 являются выводы 1 и 2, поэтому вы должны выбрать один из них, всё остальное игнорируется. На Arduino это цифровые выводы 9 и 10, эти псевдонимы также работают. Выходными выводами таймера Timer3 являются выводы , соответствующие выводам 2, 3 и 5 на Arduino Mega. Коэффициент заполнения задается, как 10-битное значение в диапазоне от 0 до 1023 (0 соответствует постоянному логическому нулю на выходе, а 1023 – постоянной логической единице)
Обратите внимание, что при необходимости в этой функции можно установить и период, добавив значение в микросекундах в качестве последнего аргумента.
Быстрый способ для настройки коэффициента заполнения ШИМ сигнала, если вы уже настроили его, вызвав ранее метод. Этот метод позволяет избежать лишних действий по включению режима ШИМ для вывода, изменению состояния регистра, управляющего направлением движения данных, проверки необязательного значения периода и прочих действий, которые являются обязательными при вызове .
Выключает ШИМ на заданном выводе, после чего вы можете использовать этот вывод для чего-либо другого.
Прерывания
Вызывает функцию через заданный в микросекундах интервал. Будьте осторожны при попытке выполнить слишком сложный обработчик прерывания при слишком большой тактовой частоте, так как CPU может никогда не вернуться в основной цикл программы, и ваша программа будет «заперта»
Обратите внимание, что при необходимости в этой функции можно установить и период, добавив значение в микросекундах в качестве последнего аргумента.
Отключает прикрепленное прерывание.
Результат
Вы можете заметить, что есть две кнопки на левой стороне, нижняя — для секундомера, а как насчет верхней?
Для ночных прогулок!
Верхняя кнопка используется для управления четырьмя 5-миллиметровыми светодиодами (мы заполнили трещину между отверстием и переключателем с помощью клея uv в соответствующем цвете, чтобы сделать браслет более изысканным).
Положение четырех светодиодов соответствует углу размахивания руки во время прогулки. Земля всегда будет подсвечиваться независимо от того, как движется рука.
Этот шагомер для запястья не только помогает рассчитать физическую силу, но и делает прогулки более безопасными ночью.
На этом мы заканчиваем создание браслета шагомера на основе модуля BMI160.
Готовим программное обеспечение
После того как вы купили нужные детали и их вам доставили — самое время подготовить программное обеспечение для того, чтобы мы могли взаимодействовать с нашим микроконтроллером. Нам нужно на наш компьютер установить Arduino IDE.
Как мы писали в обзорной статье про эту среду — используя программную среду Arduino IDE, можно, основываясь лишь на минимальных знаниях C++, решать самые разные творческие задачи, связанные с программированием и моделированием. Arduino IDE — это программная среда разработки, предназначенная для программирования одноимённой платы.
3.1 Скачиваем и устанавливаем ПО
Выбираем нужную версию, жмем «Just Download» и скачиваем:
После того как скачали ПО — запускам установку, открыв скачанный .EXE файл:
Дальше мы проходим все обычные шаги установки, как при установке любого другого приложения — соглашаемся с «лицензионным соглашением», ставим галочки, выбираем папку для установки и жмем ОК:
3.2 Запускам ПО и включаем русский язык
После того как мы прошли процесс установки мы увидим на рабочем столе иконку нашей Arduino IDE:
Нажимаем на иконку и видим процесс загрузки программы:
В итоге мы увидим такое окно:
Включаем русский язык.
Для включения русскоязычного интерфейса Arduino IDE нам нужно перейти в нужную вкладку и выбрать русский язык в списке:
File → Preferences → Language
Да, теперь, на этом шаге, у нас уже есть все комплектующие и установлено нужное программное обеспечение.
Step 5: Example 3: DAC
In this project I used a timer interrupt to output a sine wave of a specific frequency from the Arduino. I soldered a simple 8 bit R2R DAC to digital pins 0-7. This DAC was constructed from 10k and 20k resistors arranged in a multi-leveled voltage divider. I’ll be posting more about the construction of the DAC in another instructable, for now I’ve included the photo’s above.
I connected the output from the DAC up to an oscilloscope. If you need help understanding how to use/read the oscilloscope check out this tutorial. I loaded the following code onto the Arduino:
//63Hz sine wave //by Amanda Ghassaei 2012 //https://www.instructables.com/id/Arduino-Timer-Interrupts/ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * */ //sends 63Hz sine wave to arduino PORTD DAC float t = 0; void setup() { //set port/pin mode. see http://www.arduino.cc/en/Reference/PortManipulation for more info DDRD = 0xFF;//port d (digital pins 0-7) all outputs cli();//stop interrupts //set timer2 interrupt at 40kHz TCCR2A = 0;// set entire TCCR2A register to 0 TCCR2B = 0;// same for TCCR2B TCNT2 = 0;//initialize counter value to 0 // set compare match register for 40khz increments OCR2A = 49;// = (16*10^6) / (8*40000)-1 // turn on CTC mode TCCR2A |= (1 << WGM21); // Set CS21 bit for 8 prescaler TCCR2B |= (1 << CS21); // enable timer compare interrupt TIMSK2 |= (1 << OCIE2A); sei();//allow interrupts } ISR(TIMER2_COMPA_vect) { //increment t t+=1; if (t==628){//40kHz/628 =~ 63Hz t=0; } } void loop(){ //sine wave of frequency ~63Hz //send sine values to PORTD between 0 and 255 PORTD=byte(127+127*sin(t/100)); }
I set up a timer interrupt that increments the variable t at a frequency of 40kHz. Once t reaches 627 it resets back to zero (this happens with a frequency of 40,000/628 = 63Hz). Meanwhile, in the main loop the Arduino sends a value between 0 (00000000 in binary) and 255 (11111111 in binary) to digital pins 0 through 7 (PORTD). It calculates this value with the following equation:PORTD=byte(127+127*sin(t/100));
So as t increments from 0 to 627 the sine function moves through one complete cycle. The value sent to PORTD is a sine wave with frequency 63Hz and amplitude 127, oscillating around 127. When this is sent through the 8 bit resistor ladder DAC it outputs an oscillating signal around 2.5V with an amplitude of 2.5V and frequency of 63Hz.
The frequency of the sine wave can be doubled by multiplying the (t/100) term by 2, quadrupled by multiplying by 4, and so on…
Also notice that if you increase the frequency of the timer interrupt too much by decreasing the prescaler or OCR2A the sine wave will not output correctly. This is because the sin() function is computationally expensive, and at high interrupt frequencies it does not have enough time to execute. If you are using high frequency interrupts, instead of performing a computation during the interrupt routine, considering storing values in an array and simply calling these values using some kind of index. You can find an example of that in my arduino waveform generator- by storing 20,000 values of sin in an array, I was able to output sine waves with a sampling frequency of 100kHz.
Код проекта
Мы пересмотрели программу шагомера в библиотеке BMI160. Добавьте функцию millis(), чтобы преобразовать время безотказной работы системы в секундомер.
Добавьте код отображения библиотеки символов u8g. Попробовав шрифт в файле заголовка u8g.h один за другим, мы обнаружили, что шрифт freedoomr отлично подходит.
Код преобразования времени безотказной работы системы в секундомер ниже:
unsigned int ss=1000; unsigned int mi=ss*60; long minute=t0/mi; long second=(t0-minute*mi)/ss; long milliSecond=sysTime-minute*mi-second*ss; strTime=(minute%60)/10+'0'; strTime=minute%60%10+'0'; strTime=(second%60)/10+'0'; strTime=second%60%10+'0'; strTime=milliSecond/100+'0'; strTime=(milliSecond%100)/10+'0';
Примеры использования attachInterrupt
Давайте приступим к практике и рассмотрим простейший пример использования прерываний. В примере мы определяем функцию-обработчик, которая при изменении сигнала на 2 пине Arduino Uno переключит состояние пина 13, к которому мы традиционно подключим светодиод.
#define PIN_LED 13
volatile boolean actionState = LOW;
void setup() {
pinMode(PIN_LED, OUTPUT);
// Устанавливаем прерывание
// Функция myEventListener вызовется тогда, когда
// на 2 пине (прерываниие 0 связано с пином 2)
// изменится сигнал (не важно, в какую сторону)
attachInterrupt(0, myEventListener, CHANGE);
}
void loop() {
// В функции loop мы ничего не делаем, т.к. весь код обработки событий будет в функции myEventListener
}
void myEventListener() {
actionState != actionState; //
// Выполняем другие действия, например, включаем или выключаем светодиод
digitalWrite(PIN_LED, actionState);
}. Давайте рассмотрим несколько примеров более сложных прерываний и их обработчиков: для таймера и кнопок
Давайте рассмотрим несколько примеров более сложных прерываний и их обработчиков: для таймера и кнопок.
Прерывания по нажатию кнопки с антидребезгом
При прерывании по нажатию кнопки возникает проблема дребезга – перед тем, как контакты плотно соприкоснутся при нажатии кнопки, они будут колебаться, порождая несколько срабатываний. Бороться с дребезгом можно двумя способами – аппаратно, то есть, припаивая к кнопке конденсатора, и программно.
Избавиться от дребезга можно при помощи функции millis – она позволяет засечь время, прошедшее от первого срабатывания кнопки.
if(digitalRead(2)==HIGH) { //при нажатии кнопки //Если от предыдущего нажатия прошло больше 100 миллисекунд if (millis() - previousMillis >= 100) { //Запоминается время первого срабатывания previousMillis = millis(); if (led==oldled) { //происходит проверка того, что состояние кнопки не изменилось led=!led; }
Этот код позволяет удалить дребезг и не блокирует исполнение программы, как в случае с функцией delay, которая недопустима в прерываниях.
Прерывания по таймеру
Таймером называется счетчик, который производит счет с некоторой частотой, получаемой из процессорных 16 МГц. Можно произвести конфигурацию делителя частоты для получения нужного режима счета. Также можно настроить счетчик для генерации прерываний при достижении заданного значения.
Таймер и прерывание по таймеру позволяет выполнять прерывание один раз в миллисекунду. В Ардуино имеется 3 таймера – Timer0, Timer1 и Timer2. Timer0 используется для генерации прерываний один раз в миллисекунду, при этом происходит обновление счетчика, который передается в функцию millis (). Этот таймер является восьмибитным и считает от 0 до 255. Прерывание генерируется при достижении значения 255. По умолчанию используется тактовый делитель на 65, чтобы получить частоту, близкую к 1 кГц.
Для сравнения состояния на таймере и сохраненных данных используются регистры сравнения. В данном примере код будет генерировать прерывание при достижении значения 0xAF на счетчике.
OCR0A = 0xAF;
TIMSK0 |= _BV(OCIE0A);
Требуется определить обработчик прерывания для вектора прерывания по таймеру. Вектором прерывания называется указатель на адрес расположения команды, которая будет выполняться при вызове прерывания. Несколько векторов прерывания объединяются в таблицу векторов прерываний. Таймер в данном случае будет иметь название TIMER0_COMPA_vect. В этом обработчике будут производиться те же действия, что и в loop ().
SIGNAL(TIMER0_COMPA_vect) { unsigned long currentMillis = millis(); sweeper1.Update(currentMillis); if(digitalRead(2) == HIGH) { sweeper2.Update(currentMillis); led1.Update(currentMillis); } led2.Update(currentMillis); led3.Update(currentMillis); } //Функция loop () останется пустой. void loop() { }
Подведение итогов
Прерывание в Ардуино – довольно сложная тема, потому что приходится думать сразу обо всей архитектуре проекта, представлять как выполняется код, какие возможны события, что происходит, когда основной код прерывается. Мы не ставили задачу раскрыть все особенности работы с этой конструкцией языка, главная цель была познакомить с основными вариантами использования. В следующих статьях мы продолжим разговор о прерываниях более подробне.