Прерывание, LowPower - не могу понять в чем проблема

Sakolua
Offline
Зарегистрирован: 13.08.2019

По таймеру хочу уходить в сон
https://github.com/rocketscream/Low-Power
 

Moderator : пожалуйста, вставьте код правильно (возможно, новым сообщением в тему), 

 

Вроде все правильно. WakeUp отменяет прерывание и включает диоды. Потом они тухнут. И все работает.

Но к 2 пину прерывания WakeUpPin привязана сенсорная кнопка, которая будит. И по идее она должна не только запускать, но и засыпать устройство раньше таймера если надо.

Moderator : пожалуйста, вставьте код правильно (возможно, новым сообщением в тему), 

 

Кнопка просто ускоряет таймер для ReadyToPowerSafe и там еще 2 секунды запаса. Но когда время истекает устройство зависает. Все индикаторы включаются, словно прерывание сработало, но больше не реагирует вообще. Хотя кнопка WakeUpPin выключена в момент attachInterrupt и LowPower.powerDown.

Почему работает по разному с ускорения кнопки и с полного таймера? Ведь это же один и тот же код. Откуда прерывание берется если кнопка не нажата? И почему может все зависать?
Почему не выходит из powerDown? Или выходит, ведь индикаторы загораются?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Кода никто не видел, а потому, Бог его знает, что Вы там навертели.

только КОД НУЖЕН ВАШ (для особо непонятливых - ВАШ - ЭТО ВЗЯТЫЙ ИЗ ВАШЕГО ИДЕ, А НЕ ЧУЖОГО САЙТА, даже, если Вы там ну, совсем ничего не меняли).

Sakolua
Offline
Зарегистрирован: 13.08.2019

Хорошо, вот простая версия кода.

#define WakeUpPin 2

#include "LowPower.h"
#include "ButtonKing.h"

ButtonKing button(2, LOW);
bool segOn = true;
unsigned long SegOffTiming, timing2;

void setup() {
	pinMode(A1, OUTPUT);
	pinMode(A2, OUTPUT);
	pinMode(WakeUpPin, INPUT);
	pinMode(LED_BUILTIN, OUTPUT);

	button.setClick(button_click);
}

void loop() {
	button.isClick();
	if (segOn) {
		if (millis() - SegOffTiming > 5000) {
			segOn = false;
			ReadyToPowerSafe();
		}
	}
	if (millis() - timing2 > 500) {
		digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
		timing2 = millis();
	}
}

void ReadyToPowerSafe() {
	attachInterrupt(digitalPinToInterrupt(WakeUpPin), WakeUp, RISING );
	LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
	detachInterrupt(digitalPinToInterrupt(WakeUpPin));
	digitalWrite(A1, LOW);
	digitalWrite(A2, LOW);
}

void WakeUp()
{
	digitalWrite(A1, HIGH);
	digitalWrite(A2, LOW);
}

void button_click () {
	segOn = !segOn;
	if (segOn) {
		SegOffTiming = millis();
	}
	else {
		SegOffTiming = millis() - 3000;
		segOn = true; //ускорение сработки таймера выключения
	}
}

Спустя 5 секунд устройство засыпает (не мигает LED_BUILTIN), просыпается кнопкой (мигает LED_BUILTIN), мгновенно загорается в ISR WakeUp и гаснет на выходе дополнительный диод в ReadyToPowerSafe.

Но при включенном устройстве щелчок на кнопке загоняет устройство в постоянно горящий доп. диод. Значит программа не выходит из ReadyToPowerSafe.

Я так понимаю - после кнопки attachInterrupt сразу ловит прерывание чтоли... Но в чем разница КОД ЖЕ ОДИНАКОВЫЙ? А кнопка отжата, т.е и условия такие же.

Sakolua
Offline
Зарегистрирован: 13.08.2019

Я добавил мигалку после назначения IRQ
 

void ReadyToPowerSafe() {
	attachInterrupt(digitalPinToInterrupt(WakeUpPin), WakeUp, RISING );

	digitalWrite(LED_BUILTIN, LOW);
	delay(200);
	digitalWrite(LED_BUILTIN, HIGH);
	delay(300);
	digitalWrite(LED_BUILTIN, LOW);
	delay(100);
	digitalWrite(LED_BUILTIN, HIGH);
	delay(200);
	digitalWrite(LED_BUILTIN, LOW);
	
	LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);

И получается словно прерывание тут же срабатывает, потом мигает LED_BUILTIN и потом удачно засыпает. Так откуда оно берется то? нет же никаких RISING!

Sakolua
Offline
Зарегистрирован: 13.08.2019

Я даже осциллографом посмотрел! Нажатие кнопки вижу, а больше ничего там нет - ни шума ни помех!

По поводу "дребезга", наводок, антен и прочего. У этих модулей дребезга быть не должно. Но я все равно проверил! Нет ложных срабатываний.

#include "ButtonKing.h"
ButtonKing button(2, LOW);
unsigned long timing2;

void setup() {
	pinMode(A1, OUTPUT);
	pinMode(A2, OUTPUT);
	pinMode(LED_BUILTIN, OUTPUT);
	button.setClick(button_click);
}

void loop() {
	button.isClick();
	if (millis() - timing2 > 750) {
		digitalWrite(A1, LOW);
		digitalWrite(A2, LOW);
		digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
		timing2 = millis();
	}
}

void button_click () {
	digitalWrite(A1, HIGH);
	digitalWrite(A2, LOW);
}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Давайте не будем плодить сущности и оснавимся на коде из #2

Вы постоянно забываете, что пишете для людей, которые не в курсе Ваших мыслей и прочих наработок. Вы написали как оно себя ведёт, правда не очень понятно (например, что такое "дополнительный диод" - называйте номера пинов, если уж схемы нет - откуда кому знать какой диод у Вас основной, а какой - дополнительный).

Но Вы не написали, что Вы хотели сделать.

Описание должно быть таким

1. Что хотел получить
2. Что получил 
3. Чем конкретно №1 отличается от №2.

Sakolua
Offline
Зарегистрирован: 13.08.2019

Да писал я все это еще в первом посте. Короче, я разобрался. Дело в отложенных pending прерываниях, которые запоминаются где-то в регистрах МК и срабатывают сразу при назначении.

Кто-нибудь знает правильный способ сброса такого прерывания?

Пока я просто ограничился таким.
    attachInterrupt(digitalPinToInterrupt(WakeUpPin), WakeUpDummy, RISING );
    detachInterrupt(digitalPinToInterrupt(WakeUpPin));
    attachInterrupt(digitalPinToInterrupt(WakeUpPin), WakeUp, RISING );

void WakeUpDummy() {}

Сначала срабатывает пустая функция WakeUpDummy, она просто снимает флаг пропущенного прерывания с пина самим фактом своего запуска. А потом уже назначаю нормальную.

sadman41
Offline
Зарегистрирован: 19.10.2016
Sakolua
Offline
Зарегистрирован: 13.08.2019

Я не знаю, это ж песочница для новичков. А что с ним делать? В инете ничего не найти, везде только аттач и детач обсуждают либо помехи 220. Только одну статью про pending и удалось найти. Хорошо хоть там сказали, что прервания так в "буфере" висят.

Как то это тупо - назначаешь прерывание и оно ловится тем, что было пару секунд назад... Разве аттач не должен делать сброс старого для актуальность?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Sakolua пишет:

Я не знаю, это ж песочница для новичков.

А работа с прерываниями, увы - не для новичков и не для песочницы :(

Sakolua пишет:

Разве аттач не должен делать сброс старого для актуальность?

В его описании это прописано? Если нет, то непонятно, кому и за что он мог так задолжать :-)

Sakolua
Offline
Зарегистрирован: 13.08.2019

EIFR |= (1 << INTF0);

Вот команда для сброса. Подробное описание почему именно так:

https://forum.arduino.cc/index.php?topic=59217.msg426522#msg426522

или по русски:
Что-то в программе должно знать, что эти флаги должны быть установлены до того, как вы подключите обработчик прерывания.  Например, для прерывания по фронту или спаду на выводе D2 можно установить соответствующий флаг и, как только, вы вызовете функцию attachInterrupt прерывание возникает немедленно, даже если событие произошло час назад. Чтобы избежать этого, вы можете вручную сбросить флаг.

http://robotosha.ru/arduino/arduino-interrupts.html

 

ВН
Offline
Зарегистрирован: 25.02.2016

так понял, что дело в том, что void WakeUp() не обрабатывает дребезг кнопки.

Sakolua
Offline
Зарегистрирован: 13.08.2019

Вообще не о том. Я уже писал - 1 у них нет дребезга. И даже если бы он был: 2 в момент срабатывания кнопка вообще не трогается.

ВН
Offline
Зарегистрирован: 25.02.2016

я вот про это 

Sakolua пишет:

Но при включенном устройстве щелчок на кнопке загоняет устройство в постоянно горящий доп. диод. Значит программа не выходит из ReadyToPowerSafe.

доп диод этот?  digitalWrite(A1, HIGH);

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Про EIFR на нашем форуме уже были дискуссии на тему как правильно сбросить.