Kode di bawah ini mencapai apa yang Anda tanyakan:
#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
Saya menggunakan interupsi pin-perubahan pada pin Rx untuk melihat kapan data serial tiba. Dalam tes ini, papan akan tidur jika tidak ada aktivitas setelah 5 detik (LED "bangun" padam). Data serial yang masuk menyebabkan pin-change mengganggu untuk membangunkan board. Ini mencari nomor dan mem-flash LED "hijau" beberapa kali.
Diukur saat ini
Berjalan pada 5 V, saya mengukur sekitar 120 nA arus saat tertidur (0,120 μA).
Pesan kebangkitan
Namun masalah adalah bahwa byte pertama yang tiba hilang karena fakta bahwa perangkat keras serial mengharapkan tingkat penurunan pada Rx (bit mulai) yang telah tiba pada saat itu sepenuhnya terjaga.
Saya menyarankan (seperti dalam jawaban geometrikal) bahwa Anda pertama kali mengirim pesan "terjaga", dan kemudian berhenti sebentar. Jeda adalah untuk memastikan perangkat keras tidak mengartikan byte berikutnya sebagai bagian dari pesan terjaga. Setelah itu harus bekerja dengan baik.
Karena ini menggunakan interupsi pin-perubahan tidak diperlukan perangkat keras lain.
Versi yang diubah menggunakan SoftwareSerial
Versi di bawah ini berhasil memproses byte pertama yang diterima secara serial. Ini dilakukan dengan:
Menggunakan SoftwareSerial yang menggunakan interupsi pin-perubahan. Interupsi yang disebabkan oleh bit mulai dari byte seri pertama juga membangunkan prosesor.
Mengatur sekering sehingga kami gunakan:
- Osilator RC internal
- BOD dinonaktifkan
- Sekeringnya adalah: Rendah: 0xD2, Tinggi: 0xDF, Diperpanjang: 0xFF
Terinspirasi oleh FarO dalam komentar, ini membuat prosesor bangun dalam 6 siklus clock (750 ns). Pada 9600 baud setiap bit adalah 1/9600 (104,2 µs) sehingga penundaan tambahan tidak signifikan.
#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
Konsumsi daya saat tidur diukur 260 nA (0,260 μA) sehingga konsumsi sangat rendah saat tidak diperlukan.
Perhatikan bahwa dengan sekering yang diatur seperti itu, prosesor berjalan pada 8 MHz. Jadi, Anda perlu memberi tahu IDE tentang itu (mis. Pilih "Lilypad" sebagai jenis papan). Dengan begitu penundaan dan SoftwareSerial akan bekerja pada kecepatan yang benar.