Использование прерываний PCINT микроконтроллера AVR на примере микроконтроллера ATtiny88 в среде программирования Arduino IDE.
Микроконтроллеры AVR имеют несколько источников внешних прерываний. В микроконтроллере ATtiny88 прерывания INT0 и INT1 могут быть вызваны передним или задним фронтом импульса или низким уровнем на соответствующей ножке. Таких прерываний всего 2. Прерывания PCINT0 ... PCINT27 могут быть вызваны сменой уровня цифрового сигнала на соответствующей ножке. У микроконтроллера ATtiny88 в корпусе TQFP32 таких ножек 28! А событий, которые мы можем контролировать с помощью этих ножек 56!
Смена уровня сигнала на ножках
- PCINT[0:7] вызывает прерывание по вектору PCINT0_vect,
- PCINT[8:15] вызывает прерывание по вектору PCINT1_vect,
- PCINT[16:23] вызывает прерывание по вектору PCINT2_vect,
- PCINT[24:27] вызывает прерывание по вектору PCINT3_vect.
Итого, для обслуживания 28 прерываний необходимы 4 подпрограммы прерываний. Следовательно, в любой из этих подпрограмм, возможно, потребуется писать процедуру уточнения источника прерывания.
Для экспериментов мы собрали не сложную схему см. рис. 1. К шестнадцатой ножке микроконтроллера ATtiny88 мы подключили подтягивающий на плюс источника питания резистор 1 кОм и кнопку, замыкающую на минус источника питания. Источник питания 5 Вольт. К 17-й ножке микроконтроллера ATtiny88 мы подключили через резистор 2 кОм синий светодиод, катодом на минус источника питания.
Рис. 1. Принципиальная электрическая схема с микроконтроллером ATtiny88.
На 16-й ножке микроконтроллера ATtiny88 находится порт PB4 совмещённый с источником внешних прерываний PCINT4. В Arduino этот порт называют pin. D12.
На 17-й ножке микроконтроллера ATtiny88 находится порт PB5. В Arduino этот порт называют pin. D13. В Arduino UNO и NANO к D13 подключён светодиод. В среде Arduino IDE имеется константа LED_BUILTIN, указывающая на этот порт и её значение равно 13.
/* В ATtiny88
* PCINT4 находится на ножке порта PB4 (в Arduino обозначается pin. D12)
* PCINT[7:0] вызывают прерывание по вектору PCINT0_vect
* при смене уровня сигнала на соответствующей ножке.
*/
int pinPCINT4 = 12;
ISR(PCINT0_vect) { // Функция обработчик прерывания
if (!digitalRead(pinPCINT4)) { // Выбор прерывания PCINT4
while (!digitalRead(pinPCINT4)) {} // Ожидание отпускания кнопки
delay(10); // Против дребезга контактов
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); // Переключатель
}
}
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
// Инициализация прерывания
PCICR |= 1 << PCIE0; // Разрешение прерываний PCINT[7:0]
PCMSK0 |= 1 << PCINT4; // Разрешение прерывания PCINT4
// Подготовка режима энергосбережения
SMCR = 0b00000101; // CPU Power-down Mode
ADCSRA &= ~(1 << ADEN); // ADC switch off
sei(); // Глобальное разрешение прерываний
}
void loop() {
register byte temp = MCUCR | 1 << BODS; // Для повышения скорости в строке MCUCR = temp;
MCUCR |= 1 << BODSE; // Разрешение записи в BODS
MCUCR = temp; // Разрешение спящего режима BOD
__asm__ volatile ("sleep\n\t"); // 0,000мА sleep CPU + BOD + ADC switch off
}
Скетч 1. Программа демонстрирующая обслуживание прерываний PCINT в микроконтроллерах AVR.
Демонстрационную программу скетч 1 мы немного усложнили, дополнив обслуживание прерывания PCINT переводом микроконтроллера в глубокий энергосберегающий режим. Пока светодиод не горит, вся схема с микроконтроллером потребляет ток менее 1 мкА.
В функции loop() запускается переход микроконтроллера и модуля BOD в энергосберегающий режим. Кроме того, в функции setup() имеются настройки для режима энергосбережения.
В функции setup() устанавливаются в 1 некоторые биты в регистрах портов/ввода вывода PCICR и PCMSK0 для разрешения прерывания на ножке PCINT4.
Функция ISR(PCINT0_vect) настраивает вектор на подпрограмму обработки прерываний вызванных источниками PCINT[0:7].
Мы хотели чтобы кнопка, подключённая к PCINT4 работала как триггер - нажатие на кнопку включает светодиод, следующее нажатие выключает и т. д. Создавая обработчик прерывания, следует учитывать, что прерывание PCINT4 вызывает функцию обработчик прерывания по нажатию кнопки и по отпусканию кнопки.
В нашей программе (скетч 1), в обработчике прерывания ISR(PCINT0_vect), в случае возникновения прерывания, вызванного событием "смена уровня с 1 на 0 на ножке PCINT4", оператор if обнаруживает это событие. Цикл while выполняется до тех пор, пока логический уровень на ножке микроконтроллера PCINT4 (pin. 16), не изменится с 0 на 1. Тем самым, предотвращается выход из прерывания и возникновение следующего прерывания до отпускания кнопки, а так же надёжно предотвращается влияние дребезга контактов кнопки. После выхода из цикла while состояние светодиода меняется на противоположное.