Ардуино не может проснуться с помощью прерывания после отправки SMS
мой случай использования заключается в том, что я строю датчик расстояния с помощью Arduino Uno. Идея заключается в том, что когда расстояние находится между пороговым значением, с устройства отправляется SMS-сообщение.
Я использую DS3231, SIM800L и HCSR04 для своих нужд.
Я тоже хочу сэкономить энергопотребление, поэтому пытаюсь погрузить свой Arduino в глубокий сон, а затем проснуться с помощью прерывания RTC.
Приведенный ниже код отлично работает, когда расстояние НЕ находится в пороге. Это означает, что Arduino просыпается от прерывания, а затем делает то, что ему нужно. Однако если расстояние находится между порогом, то SMS отправляется и принимается, но после этого Arduino больше никогда не просыпается. Я проверил SQW pin DS3231 с помощью мультиметра, и сигнал действительно идет НИЗКО, но Arduino больше не просыпается.
Библиотеки, которые я использую , ds3231, Sim800l, NewPing
Вот код,который я использую,
#include <Arduino.h>
#include <avr/sleep.h>
#include <wire.h>
#include <ds3231.h>
#include <NewPing.h>
#include <Sim800L.h>
#define WAKEUP_PIN 2 // when low, makes 328P wake up, must be an interrupt pin (2 or 3 on ATMEGA328P)
#define LED_PIN 13 // выходной вывод для светодиода (чтобы показать, что он бодрствует)
#define TRIGGER_PIN 7
#define ECHO_PIN 6
#define MAX_DISTANCE 200 //максимальное расстояние, которое мы хотим измерить в см
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);
// DS3231 время будильника
uint8_t wake_HOUR;
uint8_t wake_MINUTE;
uint8_t wake_SECOND;
static boolean goToSleep = false; //для отслеживания того, когда нужно ложиться спать, а когда получать данные и делать что-то еще
#define SIM_MODULE_RX 10
#define SIM_MODULE_TX 11
Sim800L gsmModule(SIM_MODULE_RX, SIM_MODULE_TX);
///* Структура-это структура логических переменных, используемых в качестве полной единицы
// struct ts {
// uint8_t sec; /* секунды */
// uint8_t min; /* минуты */
// uint8_t hour; /* hours */
// uint8_t mday; /* день месяца */
// uint8_t пн; /* месяц */
// int16_t год; /* год */
// uint8_t wday; /* день недели */
// uint8_t yday; /* день в году */
// uint8_t isdst; /* переход на летнее время */
// uint8_t year_s; /* год в краткой нотации*/
//#ifdef CONFIG_UNIXTIME
// uint32_t unixtime; /* секунды с 01.01.1970 00:00:00 UTC*/
//#endif
//};
struct ts t;
// Когда WAKEUP_PIN понижается, это прерывание срабатывает ПЕРВЫМ (даже в режиме PWR_DOWN sleep)
void sleepISR()
{
// Предотвратить спящий режим, поэтому мы не входим в него снова, кроме как намеренно, с помощью кода
sleep_disable();
// Отсоединить прерывание, которое вывело нас из сна
detachInterrupt(digitalPinToInterrupt(WAKEUP_PIN));
// Теперь мы продолжаем запускать основной loop() сразу после того, как заснули
}
// Двойное моргание просто для того, чтобы показать, что мы бежим. Обратите внимание, что мы этого не делаем
// используйте задержку для окончательной задержки здесь, это делается путем проверки
// millis вместо этого (неблокирующий)
void doBlink()
{
static unsigned long lastMillis = 0;
if (millis() > lastMillis + 1000)
{
digitalWrite(LED_PIN, HIGH);
delay(10);
digitalWrite(LED_PIN, LOW);
delay(200);
digitalWrite(LED_PIN, HIGH);
delay(10);
digitalWrite(LED_PIN, LOW);
lastMillis = millis();
}
}
// Set the next alarm
void setNextAlarm(void)
{
// флаги определяют, какой компонент календаря должен быть проверен по текущему времени в порядке
// чтобы вызвать тревогу - см. таблицу данных
// A1M1 (секунды) (0 для включения, 1 для отключения)
// A1M2 (минуты) (0 для включения, 1 для отключения)
// A1M3 (час) (0 для включения, 1 для отключения)
// A1M4 (день) (0 для включения, 1 для отключения)
// DY/DT (dayofweek == 1/dayofmonth == 0)
uint8_t flags[5] = {0, 0, 0, 1, 1};
// получить текущее время, чтобы мы могли вычислить следующий сигнал тревоги
DS3231_get(&t);
wake_SECOND = t.sec;
wake_MINUTE = t.min;
wake_HOUR = t.hour;
// Добавить несколько секунд к текущему времени. Если переполнение инкремент минут и т.д.
wake_SECOND = wake_SECOND + 10;
if (wake_SECOND > 59)
{
wake_MINUTE++;
wake_SECOND = wake_SECOND - 60;
if (wake_MINUTE > 59)
{
wake_HOUR++;
wake_MINUTE -= 60;
}
}
// Установить время будильника (но еще не активирован)
DS3231_set_a1(wake_SECOND, wake_MINUTE, wake_HOUR, 0, flags);
// Включить будильник
DS3231_set_creg(DS3231_CONTROL_INTCN | DS3231_CONTROL_A1IE);
}
void getDistance(){
// Отправить пинг, получить расстояние в см
float distance = sonar.ping_cm();
// Отправка результатов на последовательный монитор
Serial.print("Distance = ");
Serial.print(distance);
Serial.println(" cm");
delay(500);
if (distance < 10.00)
{
//Настройка Sim800 для отправки sms
gsmModule.begin(9600);
bool err = gsmModule.sendSms("+91790xxxxxxx", "CLose");
Serial.println(err);
gsmModule.end();
delay(3000);
}
//sleep arduino после описанной выше операции
goToSleep = true;
}
// Standard setup( ) function
void setup()
{
Serial.begin(9600);
// Держите контакты высоко, пока мы не заземлим их
pinMode(WAKEUP_PIN, INPUT_PULLUP);
// Мигающий светодиод просто показывает, что микроконтроллер работает
digitalWrite(LED_PIN, LOW);
pinMode(LED_PIN, OUTPUT);
// Clear the current alarm (ставит DS3231 INT high)
Wire.begin();
DS3231_init(DS3231_CONTROL_INTCN);
DS3231_clear_a1f();
Serial.println("Setup completed.");
}
// Цикл мигает светодиод, когда он не находится в спящем режиме
void loop()
{
// Просто моргните дважды, чтобы показать, что мы бежим
doBlink();
// Теперь штифт "ложись спать", контакт НИЗКИЙ?
if (goToSleep == true)
{
// Установите будильник DS3231 так, чтобы он просыпался через X секунд
setNextAlarm();
// Отключить АЦП (аналого-цифровой преобразователь, контакты A0 [14] - A5 [19])
static byte prevADCSRA = ADCSRA;
ADCSRA = 0;
/* Установите тип спящего режима, который мы хотим. Может быть одним из (в порядке энергосбережения):
SLEEP_MODE_IDLE (таймер 0 будет просыпаться каждую миллисекунду, чтобы держать миллис работает)
SLEEP_MODE_ADC
SLEEP_MODE_PWR_SAVE (ТАЙМЕР 2 продолжает работать)
SLEEP_MODE_EXT_STANDBY
SLEEP_MODE_STANDBY (генератор продолжает работать, делает для более быстрого пробуждения)
SLEEP_MODE_PWR_DOWN (Глубокий сон)
*/
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
// Обнаружение поворота коричневого выхода (низкое напряжение)
// Спасибо Нику Гэммону за то, как сделать это (временно) в программном обеспечении, а не
// постоянно используя командную строку avrdude.
//
// Примечание: Состояние микрочипа: BODS и BODSE доступны только для устройств picoPower ATmega48PA/88PA/168PA/328P
//
// BODS должен быть установлен в один, а BODSE должен быть установлен в ноль в течение четырех тактов. Это устанавливает
// регистр управления MCU (MCUCR)
MCUCR = bit(BODS) | bit(BODSE);
// Бит BODS автоматически очищается после трех тактов, поэтому нам лучше продолжить с ним
MCUCR = bit(BODS);
// Убедитесь, что мы можем проснуться снова, сначала отключив interupts (временно), так что
// wakeISR не запускается до того, как мы спим, а затем предотвращает прерывания,
// а затем определяет ISR (Процедуру обслуживания прерываний) для запуска при пробуждении
noInterrupts();
attachInterrupt(digitalPinToInterrupt(WAKEUP_PIN), sleepISR, LOW);
// Отправить сообщение, чтобы показать, что мы собираемся спать
Serial.println("Deep Sleep");
Serial.flush();
// Разрешить прерывания сейчас
interrupts();
// И войти в спящий режим, как указано выше
sleep_cpu();
// --------------------------------------------------------
// µController теперь спит до тех пор, пока его не разбудит прерывание
// --------------------------------------------------------
// Просыпается в этот момент, когда WAKEUP_PIN вызывается НИЗКО - сначала выполняется процедура прерывания
Serial.println("Awake");
// Очистите существующий сигнал тревоги, чтобы int pin снова стал высоким
DS3231_clear_a1f();
// Повторно включить АЦП, если он ранее был запущен
ADCSRA = prevADCSRA;
goToSleep = false; //сброс так, что arduino делает то, что ему нужно
}
else
{
//проверьте, меньше ли расстояние
Serial.println("Checking");
getDistance();
}
}
@TechMky, 👍1
Обсуждение0
- Проблема с получением SMS - GSM-модуль Arduino Uno и SIM900A
- Мини-модем SIM900a, IMEI 0, помощь с контактами TX RX
- Как получить данные из базы данных моего сервера в переменную в моем Arduino?
- Как отправить команду AT на sim800l с помощью SoftwareSerial
- Как сгенерировать аппаратное прерывание в mpu6050 для пробуждения Arduino из режима SLEEP_MODE_PWR_DOWN?
- SIM800L не регистрируется в сети
- Arduino непрерывно считывает значение АЦП с помощью прерывания
- Как отправлять сообщения на несколько номеров с помощью модуля Arduino uno и SIM800?
Я бы сначала удалил весь этот просто-наверняка код, такой как обработчик прерываний, повторил присоединение и отсоединение, отключение прерываний, BOD, @Juraj
@Juraj Не уверен, как это поможет, потому что в тот момент, когда я удалю "если" (расстояние < 10.00) " заблокируйте все так, как ожидалось. (Arduino просыпается каждые 10 секунд, получает расстояние и спит, цикл продолжается), @TechMky