По ее мотивам переписал код для вас. Проверить не на чем пока, должно работать:
#include <avr/sleep.h>
int wakePin = 2; // Пин используемый для просыпания (прерывания)
int sleepStatus = 0; // Переменная для хранения статуса (спим, проснулись) - не используется в коде
int count = 0; // Счетчик
int LedPin=13; // Светодиод
void wakeUpNow() // Прерывание сработает после пробуждения
{
if (sleepStatus) // Если мы спали,
{
sleep_disable(); // то первое, что нужно сделать после просыпания - выключить спящий режим
digitalWrite(LedPin, HIGH); // Включаем светодиод
sleepStatus = 0; // В переменную заносим статус бодрствования
}
else
{
Serial.println("Timer: Entering Sleep mode");
delay(100); // Этот делэй необходим, чтоб функция sleep не вызывала ошибку по Serial
sleepNow(); // Вызов функции sleep() для засыпания
}
// Код, который здесь выполнится перед возвращением в цикл loop()
// Таймеы и код, использующий таймеры (serial.print и др...) здесь не будет работать
// Также мы не должны выполнять какие-то спец. функции здесь,
// Т.к. здесь мы просто просыпаемся
}
void setup()
{
pinMode(LedPin, OUTPUT);
digitalWrite(LedPin, HIGH); // Включаем светодиод
pinMode(wakePin, INPUT);
digitalWrite(wakePin, HIGH); // Подтягивем ногу к 5.
Serial.begin(9600);
attachInterrupt(0, wakeUpNow, FALLING); // Используем прерывание 0 (pin 2) для выполнения функции wakeUpNow (прерывание вызывается только при смене значения на порту с HIGH на LOW - подтянуть ногу 2 на 5в.)
}
void sleepNow() // Функция увода ардуины в спячку.
{
digitalWrite(LedPin, LOW); // Выключаем светодиод
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Здесь устанавливается режим сна
sleep_enable(); // Включаем sleep-бит в регистре mcucr. Теперь возможен слип
//attachInterrupt(0,wakeUpNow, LOW); // Используем прерывание 0 (pin 2) для выполнения функции wakeUpNow при появлении низкого уровня на пине 2
count = 0; // Обнуляем счетчик прошедших секунд
sleepStatus = 1; // В переменную заносим статус сна
sleep_mode(); // Здесь устройство перейдет в режим сна!!!
// -----------------------------------------------ПОСЛЕ ПРОСЫПАНИЯ ВЫПОЛНЕНИЕ КОДА ПРОДОЛЖИТСЯ ОТСЮДА!!!
//sleep_disable(); // Первое, что нужно сделать после просыпания - выключить спящий режим
//detachInterrupt(0); // Выключаем прерывание - при нормальном режиме wakeUpNow() не будет вызываться
}
void loop()
{
// Отображаем информацию о счетчике
Serial.print("Awake for ");
Serial.print(count);
Serial.println("sec");
count++;
delay(1000); // Ждем секунду
// Проверяем - если прошло 10 секунд - засыпаем
if (count >= 10)
{
Serial.println("Timer: Entering Sleep mode");
delay(100); // Этот делэй необходим, чтоб функция sleep не вызывала ошибку по Serial
count = 0;
sleepNow(); // Вызов функции sleep() для засыпания
}
}
У меня этот код не заработал. Засыпает как надо, просыпается и..... зависает. Может из-за более новой версии IDE.
Для меня проще свой код написать, чем разбираться почему чужой не работает. Почитал статью, все понятно.
Проц Atmega328P, при подключении питания - работает, не засыпает, при нажатии и удержании кнопки 2 сек - засыпает. При очередном нажатии и удержании - просыпается. Может кому пригодится. Критика приветствуется.
Кнопка, разумеется, со второго пина на землю.
#include <avr/sleep.h>
#define THRESHOLD 2000//порог срабатывания в мсек
const byte LED = 13;
bool flagWokeUp = 1;//начальное состояние - не спим
bool data = 1;
void wakeUp (){ //функция просыпания
sleep_disable();
detachInterrupt (0);
}
void setup ()
{
Serial.begin(9600);
pinMode (2, INPUT_PULLUP);
pinMode (LED, OUTPUT);
}
void loop () {
unsigned long time = 0;
if (!(PIND & (1 << 2))) time = millis();//если кнопка нажата
while (!(PIND & (1 << 2))); //ждем пока кнопку отпустят
if (time) {
if ((millis() - time) > THRESHOLD) {
flagWokeUp = !flagWokeUp;
time = 0;
}
}
if (flagWokeUp) {
// В этом блоке выполняем то, что нужно выполнять
// во включеном состоянии
//например мигаем диодом
delay (50);
digitalWrite (LED, data);
delay (50);
data = !data;
digitalWrite (LED, data);
}
if (!flagWokeUp)goSleep();
}
void goSleep() {//функция ухода в сон
delay(100);
ADCSRA = 0;
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
sleep_enable();
noInterrupts ();
attachInterrupt (0, wakeUp, FALLING);
EIFR = bit (INTF0);
MCUCR = bit (BODS) | bit (BODSE);
MCUCR = bit (BODS);
interrupts ();
sleep_cpu ();
}
Прошу прощения, совсем запутался, пробовал разные варианты засыпает и не просыпается. Что надо, есть небольшой проект для автомобиля, наобходимо по наличию напряжения с замка зажигания пробуждать ардуинку и при отсутствии засыпать. Как выполнено в железе статус провод с замка зажигания подключен на аналоговый вход A(1), а также при появлении напряжения полевик(IFR 520N ноги G и S шунтированны резистором 10 к ) замыкает на землю контакт D2.
Пока реализовано только выключение дисплея. Сосбственно сам код. Немогу сообразить как сюда прикрутить алгоритм засыпания чтоб работало корректно.
#include <LiquidCrystal_I2C.h>
#include <avr/sleep.h>
#define THRESHOLD 2000//порог срабатывания в мсек
#define PIN_RELAY 5 // Определяем пин, используемый для подключения реле(вкл компрессора)
#define PIN_RELAY2 6 // Определяем пин, используемый для подключения реле(вкл пер блок)
#define PIN_RELAY3 7 // Определяем пин, используемый для подключения реле(вкл зад блок)
#define PIN_RELAY4 8 // Определяем пин, используемый для подключения реле(вкл зад блок)
LiquidCrystal_I2C lcd(0x27, 16, 2); // Устанавливаем дисплей
bool flagWokeUp = 1;//начальное состояние - не спим
bool data = 1;
void wakeUp (){ //функция просыпания
sleep_disable();
detachInterrupt (0);
}
void setup()
{
Serial.begin(9600);
pinMode (2, INPUT);
pinMode(PIN_RELAY, OUTPUT); // Объявляем пин реле как выход
pinMode(PIN_RELAY2, OUTPUT);
pinMode(PIN_RELAY3, OUTPUT);
pinMode(PIN_RELAY4, OUTPUT);
digitalWrite(PIN_RELAY, HIGH); // Выключаем реле - посылаем высокий сигнал
digitalWrite(PIN_RELAY2, HIGH);
digitalWrite(PIN_RELAY3, HIGH);
digitalWrite(PIN_RELAY4, HIGH);
lcd.init();
}
void loop()
{
if (digitalRead(2) == LOW) {
flagWokeUp;
}
if (digitalRead(2) != LOW){
!flagWokeUp;
}
if (flagWokeUp) {
// label :
float z = analogRead(A1); // Вход наличия включения зажигания.
z = z * 5. / 1024. / 6.8 * (20 + 6.8);
// if ( z > 10) {
lcd.backlight(); // Включаем подсветку дисплея
lcd.display(); //Включаем дисплей.
// } else {
// lcd.noDisplay(); // выключаем дисплей
// lcd.noBacklight();
// delay(1000);
// goto label;
// }
float val = analogRead(A0); // Вход датчика давления
val = val * 5. / 1024.;
val = 3 * val - 1.5;
float v = analogRead(A2); // вход измерения напряжения
v = v * 5. / 1024. / 6.8 * (20 + 6.8);
float kk = analogRead(A3); // вход кнопки компрессора
kk = kk * 5. / 1024. / 6.8 * (20 + 6.8);
float kvpb = analogRead(A6); // вход кнопки включения передней блокировки
kvpb = kvpb * 5. / 1024. / 6.8 * (20 + 6.8);
float kvzb = analogRead(A7); // вход кнопки включения задней блокировки.
kvzb = kvzb * 5. / 1024. / 6.8 * (20 + 6.8);
// delay(1000);
if (val < 0 ){
val = 0.0; // Убираем значения лежащие ниже предела измерения
}
if (val > 12){
val = 12; // Убираем значения лежащие выше предела измерения
}
if (kk > 10 and val <= 8 and z > 10){
lcd.setCursor(8, 1);
lcd.print("COMP ON ");
digitalWrite(PIN_RELAY, LOW); // Включаем реле - посылаем низкий уровень сигнала
}
if (kk < 10 || val >= 10 || z < 10){
lcd.setCursor(8, 1);
lcd.print("COMP OFF");
digitalWrite(PIN_RELAY, HIGH); // Отключаем реле - посылаем высокий уровень сигнала
}
if (kvpb > 10){
digitalWrite(PIN_RELAY2, LOW); // Включаем реле - посылаем низкий уровень сигнала
} else {
digitalWrite(PIN_RELAY2, HIGH); // Отключаем реле - посылаем высокий уровень сигнала
}
if (kvzb > 10){
digitalWrite(PIN_RELAY3, LOW); // Включаем реле - посылаем низкий уровень сигнала
} else {
digitalWrite(PIN_RELAY3, HIGH); // Отключаем реле - посылаем высокий уровень сигнала
}
// digitalWrite(PIN_RELAY2, LOW);
lcd.setCursor(0, 0);
lcd.print("P");
lcd.setCursor(2, 0);
lcd.print(val,1);
lcd.setCursor(9, 0);
lcd.print("V");
lcd.setCursor(11, 0);
lcd.print(v,1);
// Устанавливаем курсор на вторую строку и нулевой символ.
lcd.setCursor(0, 1);
// Выводим на экран количество секунд с момента запуска ардуины
lcd.print(millis() / 1000);
}
if (!flagWokeUp)goSleep();
}
void goSleep() {//функция ухода в сон
delay(100);
ADCSRA = 0;
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
sleep_enable();
noInterrupts ();
attachInterrupt (0, wakeUp, FALLING);
EIFR = bit (INTF0);
MCUCR = bit (BODS) | bit (BODSE);
MCUCR = bit (BODS);
interrupts ();
sleep_cpu ();
}
ruslan_rachinsk, ADCSRA=(1<<ADPS0)|(1<<ADPS1)|(1<<ADPS2)|(1<<ADEN)|(1<<ADSC);
Я сделал так, вроде все зароботала, это куски кода.
byte old_ADCSRA; // для включения процесора (Глобальная переменная )
Потом когда проснулся,
Теперь буду знать как активировать процесор вашим способом!!!!
По ее мотивам переписал код для вас. Проверить не на чем пока, должно работать:
#include <avr/sleep.h> int wakePin = 2; // Пин используемый для просыпания (прерывания) int sleepStatus = 0; // Переменная для хранения статуса (спим, проснулись) - не используется в коде int count = 0; // Счетчик int LedPin=13; // Светодиод void wakeUpNow() // Прерывание сработает после пробуждения { if (sleepStatus) // Если мы спали, { sleep_disable(); // то первое, что нужно сделать после просыпания - выключить спящий режим digitalWrite(LedPin, HIGH); // Включаем светодиод sleepStatus = 0; // В переменную заносим статус бодрствования } else { Serial.println("Timer: Entering Sleep mode"); delay(100); // Этот делэй необходим, чтоб функция sleep не вызывала ошибку по Serial sleepNow(); // Вызов функции sleep() для засыпания } // Код, который здесь выполнится перед возвращением в цикл loop() // Таймеы и код, использующий таймеры (serial.print и др...) здесь не будет работать // Также мы не должны выполнять какие-то спец. функции здесь, // Т.к. здесь мы просто просыпаемся } void setup() { pinMode(LedPin, OUTPUT); digitalWrite(LedPin, HIGH); // Включаем светодиод pinMode(wakePin, INPUT); digitalWrite(wakePin, HIGH); // Подтягивем ногу к 5. Serial.begin(9600); attachInterrupt(0, wakeUpNow, FALLING); // Используем прерывание 0 (pin 2) для выполнения функции wakeUpNow (прерывание вызывается только при смене значения на порту с HIGH на LOW - подтянуть ногу 2 на 5в.) } void sleepNow() // Функция увода ардуины в спячку. { digitalWrite(LedPin, LOW); // Выключаем светодиод set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Здесь устанавливается режим сна sleep_enable(); // Включаем sleep-бит в регистре mcucr. Теперь возможен слип //attachInterrupt(0,wakeUpNow, LOW); // Используем прерывание 0 (pin 2) для выполнения функции wakeUpNow при появлении низкого уровня на пине 2 count = 0; // Обнуляем счетчик прошедших секунд sleepStatus = 1; // В переменную заносим статус сна sleep_mode(); // Здесь устройство перейдет в режим сна!!! // -----------------------------------------------ПОСЛЕ ПРОСЫПАНИЯ ВЫПОЛНЕНИЕ КОДА ПРОДОЛЖИТСЯ ОТСЮДА!!! //sleep_disable(); // Первое, что нужно сделать после просыпания - выключить спящий режим //detachInterrupt(0); // Выключаем прерывание - при нормальном режиме wakeUpNow() не будет вызываться } void loop() { // Отображаем информацию о счетчике Serial.print("Awake for "); Serial.print(count); Serial.println("sec"); count++; delay(1000); // Ждем секунду // Проверяем - если прошло 10 секунд - засыпаем if (count >= 10) { Serial.println("Timer: Entering Sleep mode"); delay(100); // Этот делэй необходим, чтоб функция sleep не вызывала ошибку по Serial count = 0; sleepNow(); // Вызов функции sleep() для засыпания } }У меня этот код не заработал. Засыпает как надо, просыпается и..... зависает. Может из-за более новой версии IDE.
Для меня проще свой код написать, чем разбираться почему чужой не работает. Почитал статью, все понятно.
Проц Atmega328P, при подключении питания - работает, не засыпает, при нажатии и удержании кнопки 2 сек - засыпает. При очередном нажатии и удержании - просыпается. Может кому пригодится. Критика приветствуется.
Кнопка, разумеется, со второго пина на землю.
#include <avr/sleep.h> #define THRESHOLD 2000//порог срабатывания в мсек const byte LED = 13; bool flagWokeUp = 1;//начальное состояние - не спим bool data = 1; void wakeUp (){ //функция просыпания sleep_disable(); detachInterrupt (0); } void setup () { Serial.begin(9600); pinMode (2, INPUT_PULLUP); pinMode (LED, OUTPUT); } void loop () { unsigned long time = 0; if (!(PIND & (1 << 2))) time = millis();//если кнопка нажата while (!(PIND & (1 << 2))); //ждем пока кнопку отпустят if (time) { if ((millis() - time) > THRESHOLD) { flagWokeUp = !flagWokeUp; time = 0; } } if (flagWokeUp) { // В этом блоке выполняем то, что нужно выполнять // во включеном состоянии //например мигаем диодом delay (50); digitalWrite (LED, data); delay (50); data = !data; digitalWrite (LED, data); } if (!flagWokeUp)goSleep(); } void goSleep() {//функция ухода в сон delay(100); ADCSRA = 0; set_sleep_mode (SLEEP_MODE_PWR_DOWN); sleep_enable(); noInterrupts (); attachInterrupt (0, wakeUp, FALLING); EIFR = bit (INTF0); MCUCR = bit (BODS) | bit (BODSE); MCUCR = bit (BODS); interrupts (); sleep_cpu (); }Прошу прощения, совсем запутался, пробовал разные варианты засыпает и не просыпается. Что надо, есть небольшой проект для автомобиля, наобходимо по наличию напряжения с замка зажигания пробуждать ардуинку и при отсутствии засыпать. Как выполнено в железе статус провод с замка зажигания подключен на аналоговый вход A(1), а также при появлении напряжения полевик(IFR 520N ноги G и S шунтированны резистором 10 к ) замыкает на землю контакт D2.
Пока реализовано только выключение дисплея. Сосбственно сам код. Немогу сообразить как сюда прикрутить алгоритм засыпания чтоб работало корректно.
#include <LiquidCrystal_I2C.h> #include <avr/sleep.h> #define THRESHOLD 2000//порог срабатывания в мсек #define PIN_RELAY 5 // Определяем пин, используемый для подключения реле(вкл компрессора) #define PIN_RELAY2 6 // Определяем пин, используемый для подключения реле(вкл пер блок) #define PIN_RELAY3 7 // Определяем пин, используемый для подключения реле(вкл зад блок) #define PIN_RELAY4 8 // Определяем пин, используемый для подключения реле(вкл зад блок) LiquidCrystal_I2C lcd(0x27, 16, 2); // Устанавливаем дисплей bool flagWokeUp = 1;//начальное состояние - не спим bool data = 1; void wakeUp (){ //функция просыпания sleep_disable(); detachInterrupt (0); } void setup() { Serial.begin(9600); pinMode (2, INPUT); pinMode(PIN_RELAY, OUTPUT); // Объявляем пин реле как выход pinMode(PIN_RELAY2, OUTPUT); pinMode(PIN_RELAY3, OUTPUT); pinMode(PIN_RELAY4, OUTPUT); digitalWrite(PIN_RELAY, HIGH); // Выключаем реле - посылаем высокий сигнал digitalWrite(PIN_RELAY2, HIGH); digitalWrite(PIN_RELAY3, HIGH); digitalWrite(PIN_RELAY4, HIGH); lcd.init(); } void loop() { if (digitalRead(2) == LOW) { flagWokeUp; } if (digitalRead(2) != LOW){ !flagWokeUp; } if (flagWokeUp) { // label : float z = analogRead(A1); // Вход наличия включения зажигания. z = z * 5. / 1024. / 6.8 * (20 + 6.8); // if ( z > 10) { lcd.backlight(); // Включаем подсветку дисплея lcd.display(); //Включаем дисплей. // } else { // lcd.noDisplay(); // выключаем дисплей // lcd.noBacklight(); // delay(1000); // goto label; // } float val = analogRead(A0); // Вход датчика давления val = val * 5. / 1024.; val = 3 * val - 1.5; float v = analogRead(A2); // вход измерения напряжения v = v * 5. / 1024. / 6.8 * (20 + 6.8); float kk = analogRead(A3); // вход кнопки компрессора kk = kk * 5. / 1024. / 6.8 * (20 + 6.8); float kvpb = analogRead(A6); // вход кнопки включения передней блокировки kvpb = kvpb * 5. / 1024. / 6.8 * (20 + 6.8); float kvzb = analogRead(A7); // вход кнопки включения задней блокировки. kvzb = kvzb * 5. / 1024. / 6.8 * (20 + 6.8); // delay(1000); if (val < 0 ){ val = 0.0; // Убираем значения лежащие ниже предела измерения } if (val > 12){ val = 12; // Убираем значения лежащие выше предела измерения } if (kk > 10 and val <= 8 and z > 10){ lcd.setCursor(8, 1); lcd.print("COMP ON "); digitalWrite(PIN_RELAY, LOW); // Включаем реле - посылаем низкий уровень сигнала } if (kk < 10 || val >= 10 || z < 10){ lcd.setCursor(8, 1); lcd.print("COMP OFF"); digitalWrite(PIN_RELAY, HIGH); // Отключаем реле - посылаем высокий уровень сигнала } if (kvpb > 10){ digitalWrite(PIN_RELAY2, LOW); // Включаем реле - посылаем низкий уровень сигнала } else { digitalWrite(PIN_RELAY2, HIGH); // Отключаем реле - посылаем высокий уровень сигнала } if (kvzb > 10){ digitalWrite(PIN_RELAY3, LOW); // Включаем реле - посылаем низкий уровень сигнала } else { digitalWrite(PIN_RELAY3, HIGH); // Отключаем реле - посылаем высокий уровень сигнала } // digitalWrite(PIN_RELAY2, LOW); lcd.setCursor(0, 0); lcd.print("P"); lcd.setCursor(2, 0); lcd.print(val,1); lcd.setCursor(9, 0); lcd.print("V"); lcd.setCursor(11, 0); lcd.print(v,1); // Устанавливаем курсор на вторую строку и нулевой символ. lcd.setCursor(0, 1); // Выводим на экран количество секунд с момента запуска ардуины lcd.print(millis() / 1000); } if (!flagWokeUp)goSleep(); } void goSleep() {//функция ухода в сон delay(100); ADCSRA = 0; set_sleep_mode (SLEEP_MODE_PWR_DOWN); sleep_enable(); noInterrupts (); attachInterrupt (0, wakeUp, FALLING); EIFR = bit (INTF0); MCUCR = bit (BODS) | bit (BODSE); MCUCR = bit (BODS); interrupts (); sleep_cpu (); }