Hi everyone,
I'm trying to put my custom LED watch into deep sleep mode after it displays the time.
It uses an ATmega328P-MMHR (28-pin VQFN) with an M41T62 (8 pin LCC) real time clock, powered by a CR2016 coin battery. Time and day of the week are displayed on 33 multiplexed LEDs.
The watch only lasts for about 1-2 days before running out of power. I expected it to last longer if deep sleep is working, given that each time I press a button, only 3-4 leds are lit on and off very fast (creating persistence of vision) for about 2 seconds.
Can anyone see any problems with my code or if something is preventing the Atmega from going to sleep? Any advice is greatly appreciated.
NB. I use /// to distinguish my comments from commented out code (//).
#include "Wire.h" /// I2C connections
#include "M41T62.h" /// M41T62 real time clock
#include "PinChangeInterrupt.h" /// pin change interrupt
#include "OneButton.h" /// multi-button
#include <avr/sleep.h>
RTC_M41T62 RTC; /// real time clock
#define NUM_COL 6 /// columns are anodes
#define NUM_ROW 6 /// rows are cathodes
#define COL_ON LOW /// the following four lines of code control swtiching the multiplexed LEDs on and off
#define COL_OFF HIGH
#define ROW_ON HIGH
#define ROW_OFF LOW
const int colLED[NUM_COL] = { 2, 3, 4, 5, 6, 7 }; /// pins for anode (+) connections on ATmega328p, columns in LED matrix
const int rowLED[NUM_ROW] = { 0, 1, A0, A1, A2, A3 }; /// pins for cathode (-) connections on ATmega328p, rows in LED matrix
uint8_t display[NUM_ROW][NUM_COL]; /// this array holds the current image to display
const int button1 = 9; /// pin for button 1
const int button2 = 10; /// pin for button 2
int buttonState; /// the current reading from the input pin
int lastButtonState = LOW; /// the previous reading from the input pin
int rowPin = 6;
int colPin = 6;
unsigned long lastDebounceTime = 0; /// the last time the output pin was toggled
unsigned long debounceDelay = 50; /// the debounce time; increase if the output flickers
bool myFlag1 = false; /// create flag1 for pin change interrupt
bool myFlag2 = false; /// create flag2 for pin change interrupt
bool deepSleepEnabled = false;
unsigned long displayStartMillis = 0;
bool displayActive = false;
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/// - - - - - - - - - - - - - - - setup + loop - - - - - - - - - - - - - - - -
void setup() {
pinMode(button1, INPUT_PULLUP); /// button1 pulled LOW when pressed
pinMode(button2, INPUT_PULLUP); /// button2 pulled LOW when pressed
Wire.begin(); /// I2C communication with the RTC
RTC.begin(); /// start RTC
RTC.adjust(DateTime(__DATE__, __TIME__)); /// set RTC time to computer time
for (int i = 0; i < NUM_COL; i++) /// set all column pins to OUTPUT and OFF
{
pinMode(colLED[i], OUTPUT); /// set column LEDs to output
digitalWrite(colLED[i], COL_OFF); /// turn all columns off
}
for (int j = 0; j < NUM_ROW; j++) /// set all row pins to OUTPUT and OFF
{
pinMode(rowLED[j], OUTPUT); /// set row LEDs to output
digitalWrite(rowLED[j], ROW_OFF); /// turn all rows off
}
attachPCINT(digitalPinToPCINT(button1), setFlag1, CHANGE); /// interrupt when button 1's state changes
attachPCINT(digitalPinToPCINT(button2), setFlag2, CHANGE); /// interrupt when button 2's state changes
}
void loop() {
if (myFlag1) {
if (millis() - lastDebounceTime > debounceDelay) {
lastDebounceTime = millis();
displayStartMillis = millis();
displayActive = true;
myFlag1 = false; /// Reset the flag
}
}
if (displayActive) {
if (millis() - displayStartMillis < 200) {
displayTime();
} else {
displayActive = false;
enterDeepSleep(); /// Function to enter sleep mode
}
}
}
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/// - - - - - - - - - - - - - - - time functions - - - - - - - - - - - - - - -
void displayTime() {
DateTime now = RTC.now(); /// set "now" from the computer's time
int hour = now.hour() % 12;
if (hour == 0)
hour = 12;
int hourRow = (hour - 1) / 2;
int hourColumn = (hour - 1) % 2;
{
ledOn(hourRow, hourColumn);
delayMicroseconds(100);
ledOff(hourRow, hourColumn);
}
int minute = now.minute(); /// 0...59
int minuteRow;
if (minute < 5) /// zero minutes is located at the bottom
minuteRow = 5;
else
minuteRow = (minute - 5) / 10; /// start at 5 at the top
/// A change of column for each 5 minutes: (m / 5)
/// But the 10,20,30 are the right column: + 1
/// There are two columns : %2
/// The start column is : 2
int minuteColumn = 2 + ((minute / 5) + 1) % 2;
{
ledOn(minuteRow, minuteColumn);
delayMicroseconds(100);
ledOff(minuteRow, minuteColumn);
}
/// minute remainder 1...4
int remainder = now.minute() % 5;
if (remainder > 0) /// leds off for seconds 0 and 5
{
remainder--; /// row 0 for remainder 1
ledOn(remainder, 4);
delayMicroseconds(100);
//delay(15);
ledOff(remainder, 4);
}
/// ------------------------------
/// day of the week
/// ------------------------------
int weekday = now.dayOfWeek() - 1;
{
ledOn(weekday, 5);
delayMicroseconds(150);
ledOff(weekday, 5);
}
}
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/// - - - - - - - - - - - - - - - button functions - - - - - - - - - - - - - - -
void setFlag1() {
myFlag1 = true;
}
void setFlag2() {
myFlag2 = true;
}
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/// - - - - - - - - - - - - - - - sleep functions - - - - - - - - - - - - - - -
/// Add this function to handle sleep
void enterDeepSleep() {
/// disable ADC
ADCSRA = 0;
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_mode(); /// Enter sleep mode. Will wake up upon external interrupts
/// Re-enable things here if needed after waking up
sleep_disable();
}
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/// - - - - - - - - - - - - - main display functions - - - - - - - - - - - - - -
/// turn on specific LEDs
inline void ledOn(int row, int col) {
digitalWrite(rowLED[row], HIGH); /// row pin to +3V
digitalWrite(colLED[col], LOW); /// column pin to 0V
//allOff();
}
/// turn off specific LEDs
inline void ledOff(int row, int col) {
digitalWrite(rowLED[row], LOW); /// row pin to 0V
digitalWrite(colLED[col], HIGH); /// column pin to +3V
}
/// turn on all LEDs
void allOn() {
for (int i = 0; i < NUM_COL; i++) {
digitalWrite(colLED[i], COL_ON); /// all columns to 3V
}
for (int j = 0; j < NUM_ROW; j++) {
digitalWrite(rowLED[j], ROW_ON); /// all rows to 3V
}
}
/// turn off all LEDs
void allOff() {
for (int i = 0; i < NUM_ROW; i++) {
digitalWrite(rowLED[i], ROW_OFF); /// all row pins to 0V
}
for (int j = 0; j < NUM_COL; j++) {
digitalWrite(colLED[j], COL_OFF); /// all column pins to 0V
}
}
