ATtiny85 дает многократное пробуждение от простоя, если INT0 удерживается на низком уровне
Желаемое поведение:
- Перейдите в спящий режим ожидания.
- Когда PB2 (синий след) становится низким, просыпайтесь и дайте 10 мс на PB1, потянув за низкий уровень (желтый след на рисунке 1).
- Перейдите к 1.
Что я получаю:
Рис. 1. (1) Входные триггеры, (2) процессор выходит из спящего режима, (3) процессор снова переходит в спящий режим и снова просыпается, пока (9) вход снова не увеличится.
Я хочу, чтобы один низкий импульс длительностью 10 мс, а затем снова заснул до следующего отрицательного значения PB2, независимо от того, как долго PB2 удерживается на низком уровне.
Несмотря на то, что я установил MCUCR на понижающийся край INT0, устройство, похоже, постоянно просыпается, когда PB2 удерживается на низком уровне. Мой код ниже пытается решить эту проблему, переключившись на прерывание с восходящим краем, если входной сигнал низкий, и прерывание с падающим краем, если входной сигнал высокий. Результат показан на рисунке 1.
void setup(){
ADCSRA &= ~_BV(ADEN); // ADC off. ADC not used.
pinMode(reedPin, INPUT);
}
void loop(){
system_sleep(); // Go straigth to sleep.
// ---- System woken up by interrupt. ---------
if (!digitalRead(reedPin)) { // Check that input is low.
pinMode(outPin, OUTPUT); // Enable output.
digitalWrite(outPin, HIGH); // Pull motor sensor input low by MOSFET.
delay(pulseTime); // Pulse time.
digitalWrite(outPin, LOW); // Pulse off.
}
}
// From http://interface.khm.de/index.php/lab/experiments/sleep_watchdog_battery/
void system_sleep() {
MCUCR |= _BV(ISC01); // Required for both rising and falling edge interrupt.
if(digitalRead(reedPin)) { // Input is high so set interrupt for detecting low.
MCUCR &= ~_BV(ISC00); // Clear MCUCR bit 0 for falling edge interrupt.
} else { // Input is low so set interrupt for detecting high.
MCUCR |= _BV(ISC00); // Set MCUCR bit 0 for rising edge interrupt.
}
GIMSK |= _BV(INT0); // Enable Pin Change Interrupts
set_sleep_mode(SLEEP_MODE_IDLE); // Leaves the clock running for elapsedMillis.
sleep_enable(); // Sets the Sleep Enable bit in the MCUCR Register (SE BIT)
sei(); // Enable interrupts
sleep_cpu(); // sleep
// ZZZZZZZZZZZzzzzzzzzzzz .......
// ------- CPU is now asleep and awaiting interrupt. ----------------------
cli(); // Disable interrupts on wake up.
sleep_disable(); // Clear SE bit.
}
ISR(INT0_vect){ // Wake up.
GIMSK = 0; // Disable external interrupts. (Only need one to wake up.)
}
Кто-нибудь может провести меня через это?
Большое спасибо.
@Transistor, 👍2
Обсуждение1 ответ
Ядро Arduino настраивает таймер для периодического прерывания.
Это прерывание используется для реализации millis()
, delay () и т.д.
Ваш
код предполагает, что внешнее прерывание является единственным
, которое может получить микроконтроллер. Я предполагаю, что прерывания таймера могут быть причиной
наблюдаемого поведения.
Я предлагаю настроить прерывание для выпадающих ребер и оставить его всегда включенным. ISR может позаботиться о запуске импульса и установке флага, чтобы основной цикл знал, что импульс активен. Основной контур может затем остановить импульс, когда он был включен достаточно долго:
volatile bool pulse_active; // whether the pulse is on
volatile uint32_t pulse_start; // time when it started
ISR(INT0_vect) {
// Start the pulse.
digitalWrite(outPin, HIGH);
pulse_active = true;
pulse_start = millis();
}
void loop() {
// End the pulse if it's time to do so.
if (pulse_active && millis() - pulse_start >= pulseTime) {
digitalWrite(outPin, LOW);
pulse_active = false;
}
// Take a little nap.
sleep_mode();
}
Обратите внимание, что небольшой сон в приведенном выше коде может быть прерван либо внешним прерыванием, либо прерыванием таймера.
- Arduino IDE с ошибкой ATtiny85 «множественное определение `__vector_5»
- attiny85 сбрасывает себя вместо процедуры пробуждения
- Attiny85 простая проблема с аналоговым и цифровым выходом
- ATtiny85 не выходит из сна
- ATtiny85 со сном и последовательным портом
- Связь последовательного порта Digispark
- Почему необходимо использовать ключевое слово volatile для глобальных переменных при обработке прерываний в ардуино?
- Как сгенерировать аппаратное прерывание в mpu6050 для пробуждения Arduino из режима SLEEP_MODE_PWR_DOWN?
@jsotola, никакой радости. Все то же самое., @Transistor
вот некоторый код сна, который вы могли бы попробовать ... понятия не имею, действительно ли это работает (у меня нет возможности проверить) ... https://github.com/DaveCalaway/ATtiny/blob/master/Examples/AT85_sleep_interrupt/AT85_sleep_interrupt.ino, @jsotola
Библиотека в этом коде многое упрощает. Теперь у меня это срабатывает на грани падения и снова на подъеме. Я буду продолжать копать. Спасибо., @Transistor
раздел 9.2 может помочь (стр. 49) ... https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-2586-AVR-8-bit-Microcontroller-ATtiny25-ATtiny45-ATtiny85_Datasheet.pdf, @jsotola