Aşağıdaki kod sorduğunuz şeyi sağlar:
#include <avr/sleep.h>
#include <avr/power.h>
const byte AWAKE_LED = 8;
const byte GREEN_LED = 9;
const unsigned long WAIT_TIME = 5000;
ISR (PCINT2_vect)
{
// handle pin change interrupt for D0 to D7 here
} // end of PCINT2_vect
void setup()
{
pinMode (GREEN_LED, OUTPUT);
pinMode (AWAKE_LED, OUTPUT);
digitalWrite (AWAKE_LED, HIGH);
Serial.begin (9600);
} // end of setup
unsigned long lastSleep;
void loop()
{
if (millis () - lastSleep >= WAIT_TIME)
{
lastSleep = millis ();
noInterrupts ();
byte old_ADCSRA = ADCSRA;
// disable ADC
ADCSRA = 0;
// pin change interrupt (example for D0)
PCMSK2 |= bit (PCINT16); // want pin 0
PCIFR |= bit (PCIF2); // clear any outstanding interrupts
PCICR |= bit (PCIE2); // enable pin change interrupts for D0 to D7
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
power_adc_disable();
power_spi_disable();
power_timer0_disable();
power_timer1_disable();
power_timer2_disable();
power_twi_disable();
UCSR0B &= ~bit (RXEN0); // disable receiver
UCSR0B &= ~bit (TXEN0); // disable transmitter
sleep_enable();
digitalWrite (AWAKE_LED, LOW);
interrupts ();
sleep_cpu ();
digitalWrite (AWAKE_LED, HIGH);
sleep_disable();
power_all_enable();
ADCSRA = old_ADCSRA;
PCICR &= ~bit (PCIE2); // disable pin change interrupts for D0 to D7
UCSR0B |= bit (RXEN0); // enable receiver
UCSR0B |= bit (TXEN0); // enable transmitter
} // end of time to sleep
if (Serial.available () > 0)
{
byte flashes = Serial.read () - '0';
if (flashes > 0 && flashes < 10)
{
// flash LED x times
for (byte i = 0; i < flashes; i++)
{
digitalWrite (GREEN_LED, HIGH);
delay (200);
digitalWrite (GREEN_LED, LOW);
delay (200);
}
}
} // end of if
} // end of loop
Seri veri geldiğinde fark etmek için Rx pininde bir pin değiştirme kesintisi kullandım. Bu testte, 5 saniye sonra herhangi bir işlem yapılmazsa ("uyanık" LED'i söner) kart uyku moduna geçer. Gelen seri veriler, pin değiştirme kesintisinin kartı uyandırmasına neden olur. Bir sayı arar ve "yeşil" LED'i bu sayıda yanıp söner.
Ölçülen akım
5 V'da çalışırken, uyurken yaklaşık 120 nA akım ölçtüm (0,120 µA).
Uyanış mesajı
Ancak bir sorun, ilk gelen baytın, seri donanımın, tamamen uyanık olduğu zamana kadar gelmiş olan Rx (başlangıç biti) üzerinde düşme seviyesi beklemesi nedeniyle kaybolmasıdır.
(Geometrikal'ın cevabında olduğu gibi) önce bir "uyanık" mesajı göndermenizi ve sonra kısa bir süre duraklamanızı öneririm . Duraklatma, donanımın bir sonraki baytı uyanık mesajın bir parçası olarak yorumlamadığından emin olmaktır. Bundan sonra iyi çalışmalıdır.
Bu bir pin değiştirme kesintisi kullandığından başka bir donanım gerekmez.
SoftwareSerial kullanılarak değiştirilmiş sürüm
Aşağıdaki sürüm seri olarak alınan ilk baytı başarıyla işler. Bunu şu şekilde yapar:
FarO'dan bir yorumda esinlenerek, işlemcinin 6 saat döngüsünde (750 ns) uyanmasını sağlar. 9600 baud'da her bit süresi 1/9600'dür (104,2 µs), bu nedenle ekstra gecikme önemsizdir.
#include <avr/sleep.h>
#include <avr/power.h>
#include <SoftwareSerial.h>
const byte AWAKE_LED = 8;
const byte GREEN_LED = 9;
const unsigned long WAIT_TIME = 5000;
const byte RX_PIN = 4;
const byte TX_PIN = 5;
SoftwareSerial mySerial(RX_PIN, TX_PIN); // RX, TX
void setup()
{
pinMode (GREEN_LED, OUTPUT);
pinMode (AWAKE_LED, OUTPUT);
digitalWrite (AWAKE_LED, HIGH);
mySerial.begin(9600);
} // end of setup
unsigned long lastSleep;
void loop()
{
if (millis () - lastSleep >= WAIT_TIME)
{
lastSleep = millis ();
noInterrupts ();
byte old_ADCSRA = ADCSRA;
// disable ADC
ADCSRA = 0;
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
power_adc_disable();
power_spi_disable();
power_timer0_disable();
power_timer1_disable();
power_timer2_disable();
power_twi_disable();
sleep_enable();
digitalWrite (AWAKE_LED, LOW);
interrupts ();
sleep_cpu ();
digitalWrite (AWAKE_LED, HIGH);
sleep_disable();
power_all_enable();
ADCSRA = old_ADCSRA;
} // end of time to sleep
if (mySerial.available () > 0)
{
byte flashes = mySerial.read () - '0';
if (flashes > 0 && flashes < 10)
{
// flash LED x times
for (byte i = 0; i < flashes; i++)
{
digitalWrite (GREEN_LED, HIGH);
delay (200);
digitalWrite (GREEN_LED, LOW);
delay (200);
}
}
} // end of if
} // end of loop
Uykudayken güç tüketimi 260 nA (0.260 µA) olarak ölçüldü, bu yüzden ihtiyaç olmadığında çok düşük tüketimdir.
Sigortalar bu şekilde ayarlandığında, işlemcinin 8 MHz'de çalıştığını unutmayın. Bu nedenle IDE'ye bundan bahsetmeniz gerekir (örn. Tahta tipi olarak "Lilypad" i seçin). Bu şekilde gecikmeler ve SoftwareSerial doğru hızda çalışacaktır.