โค้ดด้านล่างนี้บรรลุสิ่งที่คุณต้องการ:
#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
ฉันใช้การขัดจังหวะการเปลี่ยนพินบนพิน Rx เพื่อแจ้งให้ทราบเมื่อมีข้อมูลซีเรียลมาถึง ในการทดสอบนี้บอร์ดจะเข้าสู่โหมดสลีปหากไม่มีกิจกรรมหลังจาก 5 วินาที (LED "ตื่น" ดับ) ข้อมูลอนุกรมที่เข้ามาทำให้การขัดจังหวะการเปลี่ยนพินเพื่อปลุกบอร์ด มันจะมองหาตัวเลขและกะพริบไฟ LED "สีเขียว" จำนวนครั้งนั้น
วัดกระแสไฟฟ้า
ทำงานที่ 5 V ฉันวัดกระแสประมาณ 120 nA เมื่อหลับ (0.120 µA)
ข้อความตื่นขึ้น
อย่างไรก็ตามปัญหาคือว่าไบต์แรกที่มาถึงจะหายไปเนื่องจากฮาร์ดแวร์อนุกรมคาดว่าระดับที่ลดลงของ Rx (บิตเริ่มต้น) ซึ่งมาถึงแล้วเมื่อถึงเวลาที่มันตื่นเต็มที่
ผมขอแนะนำให้ (ในขณะที่คำตอบของ geometrikal) ให้คุณส่งข้อความ "ตื่น" แล้วหยุดเป็นเวลาสั้น ๆ การหยุดชั่วคราวคือเพื่อให้แน่ใจว่าฮาร์ดแวร์ไม่ได้แปลไบต์ถัดไปเป็นส่วนหนึ่งของข้อความที่ปลุก หลังจากนั้นควรทำงานได้ดี
เนื่องจากสิ่งนี้ใช้การขัดจังหวะการเปลี่ยนขาโดยไม่ต้องใช้ฮาร์ดแวร์อื่น
รุ่นที่แก้ไขโดยใช้ SoftwareSerial
รุ่นด้านล่างประมวลผลไบต์แรกที่ได้รับเป็นผลสำเร็จ มันทำได้โดย:
ได้รับแรงบันดาลใจจาก FarO ในความคิดเห็นสิ่งนี้ทำให้โปรเซสเซอร์ตื่นขึ้นในรอบ 6 นาฬิกา (750 ns) ที่ 9600 baud ในแต่ละ bit เวลาเท่ากับ 1/9600 (104.2 )s) ดังนั้นการหน่วงเวลาเพิ่มเติมจึงไม่มีนัยสำคัญ
#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
การใช้พลังงานเมื่อนอนหลับวัดได้ที่ 260 nA (0.260 µA) ดังนั้นจึงสิ้นเปลืองพลังงานน้อยมากเมื่อไม่ต้องการใช้
โปรดทราบว่าด้วยฟิวส์ที่ตั้งไว้เช่นนั้นโปรเซสเซอร์จะทำงานที่ 8 MHz ดังนั้นคุณต้องบอก IDE เกี่ยวกับเรื่องนั้น (เช่นเลือก "Lilypad" เป็นประเภทกระดาน) ด้วยวิธีนี้ความล่าช้าและ SoftwareSerial จะทำงานด้วยความเร็วที่ถูกต้อง