Внешнее прерывание не работает на 3,3 В atmega168
Я сделал плату на 3,3 В и установил как atmega328p (которую я снял с 3,3 В pro mini), так и atmega168, которую я загрузил (используя USBtinyISP, выбрав плату "Arduino Pro или Pro Mini" и "atmega168 (3,3 В, 8 МГц") .
Все отлично работает с atmega328 — код работает и прерывания тоже — какая функция выводит Arduino из спящего режима при повышении INT0.
Однако на Atmega168 прерывание не работает. Весь нормальный код работает как положено (связь, инструкции и т.д.), только не прерывание. Когда Arduino переходит в спящий режим, я не могу его разбудить, так как прерывание не работает.
Основной код ниже:
#include <avr/sleep.h>//эта библиотека AVR содержит методы, управляющие спящими режимами
byte interruptPin = 2; // Включаем/выключаем плату
unsigned long shutDownTimer = 0; // Таймер для выключения
void setup() {
Serial.begin(57600);
pinMode(interruptPin, INPUT); // Установите вывод d2 на вход, используя встроенный подтягивающий резистор
Serial.println("Starting");
}
void loop() {
Serial.println("Awake");
delay(1000);
// Управление отключением
if (digitalRead(interruptPin) == LOW ) {
Serial.println("Shutdown detected");
shutDownTimer = millis();
while (digitalRead(interruptPin) == LOW ) {
if (millis() - shutDownTimer > 1000) {
Serial.println("sleep mode triggered");
Going_To_Sleep();
}
}
}
}
void Going_To_Sleep() {
sleep_enable();//Включение спящего режима
delay(1000);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);//Установка спящего режима, в нашем случае полного сна
delay(1000); // подождите секунду, чтобы светодиод погас перед тем, как перейти в спящий режим
attachInterrupt(0, wakeUp, RISING);//присоединение прерывания к контакту d2
Serial.println("Interrrupt attached");//Печать сообщения на последовательный монитор
sleep_cpu();//активация спящего режима
Serial.println("just woke up!");//следующая строка кода, выполняемая после прерывания
}
void wakeUp() {
sleep_disable();//Отключаем спящий режим
detachInterrupt(0); //Удаляет прерывание от контакта 2;
Serial.println("Interrrupt Fired - wakeup");//Печать сообщения на последовательный монитор
}
Вместо использования "attachInterrupt(0, wakeUp, RISING);" Я также пробовал следующее, которое также не работает:
attachInterrupt(INT0, wakeUp, RISING);
attachInterrupt(digitalPinToInterrupt(interruptPin), wakeUp, RISING);
attachInterrupt(32, wakeUp, RISING); // так как это контакт чипа? Радуйся, Мария
attachInterrupt(2, wakeUp, RISING); //очевидно, это не сработает, Радуйся, Мария 2
Понятия не имею, почему прерывания не работают. У меня есть подозрение, что это может быть связано с чем-то, связанным с предохранителем в загрузчике, но я действительно не понимаю вещи на этом уровне (хотя я рад погрузиться в него с некоторыми указаниями). Будем признательны за любые рекомендации!
@Troy Cados, 👍0
Обсуждение2 ответа
Лучший ответ:
Согласно техническому описанию Atmega168 :
Обратите внимание, что распознавание падения или роста прерывания по фронту на INT0 или INT1 требуют наличия тактового генератора ввода-вывода, описанного в Раздел 6.1 «Системы тактирования и их распределение» на стр. 23. Обнаружено прерывание низкого уровня на INT0 и INT1 асинхронно. Это означает, что это прерывание можно использовать для пробуждения части также из режимов сна, отличных от режима ожидания. Часы ввода-вывода останавливаются во всех спящих режимах, кроме режима ожидания
Другими словами, только прерывание LOW выводит его из спящего режима.
Сказав это, Atmega328P действительно выходит из спящего режима с прерыванием нарастания или спада, как я ранее подтвердил Atmel, однако я не могу с уверенностью сказать, применимо ли это улучшение (по сравнению с тем, что указано в техническом описании). до 168.
Вы можете попробовать провести небольшое тестирование, чтобы убедиться в этом. Может быть, перенастройте так, чтобы прерывание возникало, когда сигнал становится низким, а не высоким, а затем используйте прерывание LOW, а не RISING.
Кроме того, не выполняйте последовательную печать внутри ISR. Современные версии библиотеки справляются с этим лучше, чем в прошлом, но это все еще может быть проблемой. Как предложено в комментарии, попробуйте мигать светодиодом, а не печатать что-то. Или ничего не печатать, ведь вы что-то печатаете, когда оно просыпается. Зачем печатать что-то лишнее внутри ISR? Это просто напрашивается на неприятности.
Я не видел в техпаспорте Atmega328P информации о том, что он работает с подъемом, а Atmega168 не работает с подъемом. Однако он действительно работает в соответствии с тем, что вы говорите. Мне просто нужно использовать Atmega328 для этого приложения. Спасибо., @Troy Cados
В зависимости от того, какой сигнал вы используете для пробуждения Arduino, вы также можете обнаружить, что прерывания по изменению контакта являются альтернативой прерываниям, инициируемым фронтом, которые вы используете в настоящее время. Обычно они более предсказуемы в своем поведении и менее подвержены нюансам интерпретации таблиц данных. См. https://playground.arduino.cc/Main/PinChangeInterrupt/ примеры их использования.
- Как сгенерировать аппаратное прерывание в mpu6050 для пробуждения Arduino из режима SLEEP_MODE_PWR_DOWN?
- Датчик PIR и сон (прерывание) на Mega2560
- POWER_MODE_IDLE пробуждается при любом изменении ввода?
- Как разбудить Arduino с помощью rtc?
- attiny85 сбрасывает себя вместо процедуры пробуждения
- Как одной кнопкой с прерыванием включать и отключать спящий режим?
- ATtiny85 со сном и последовательным портом
- Порог сигнала пробуждения
Ваш
Serial.println
внутри ISR подвергает вас опасности заблокироваться там. Попробуйте вместо этого использовать светодиод или что-то в этом роде., @timemage