Here is the code. Sorry about not noticing the reformatted option. Looks much better now.
But the documentation information I have at the start would not preformat, don’t know why.
Cheers.
#include <avr/sleep.h>
#include <LedControl.h>
//#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
//#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#define LED 9 // LED attached pin 15 // changes state every time micro wakes up, ie 1 sec on 1 second off.
// remove in final design as LED uses power half the time.
#define DIN 8 // Display data pin 14 // 7 seg display control
#define CS 7 // Display enable pin 13
#define CLK 6 // Display clock pin 12
#define PUSHBUTTON 2 // Push button on pin 4 // press button to show counter
#define DEVICES 1 // Only 1 Display
#define ADDRESS 0 // Only 1 Display, address is device 0
#define BRIGHTNESS 1 // Display brightness
#define DAY_U 7 // Days upper char display position 7
#define DAY_L 6 // Days lower char display position 6
#define HOUR_U 5 // Hours upper char display position 5
#define HOUR_L 4 // Hours lower char display position 4
#define MINUTE_U 3 // Minutes upper char display position 3
#define MINUTE_L 2 // Minutes lower char display position 2
#define SECOND_U 1 // Seconds upper char display position 1
#define SECOND_L 0 // Seonds lower char display position 0
volatile bool ButtonON = false; // flags button has been pressed, used in ISR
unsigned int seconds = 0;
unsigned int minutes = 0;
unsigned int hours = 0;
unsigned int days = 0;
LedControl lc = LedControl(DIN, CLK, CS, DEVICES);
//=================================================================================
void ButtonPressedISR() { // button pressed interrupt service routine
sleep_disable();
ButtonON = true;
}
//==================================================================================================
void setup(){
ADCSRA= 0; // ADC disable, reduces current from 140uA to 21uA in sleep mode
pinMode(LED, OUTPUT);
digitalWrite(LED, HIGH);
lc.setIntensity(ADDRESS,BRIGHTNESS); // set brightness
lc.clearDisplay(ADDRESS); // clear display
pinMode(PUSHBUTTON, INPUT_PULLUP); // Push buton input, set internal pullup, button active when low level
attachInterrupt(digitalPinToInterrupt(PUSHBUTTON), ButtonPressedISR, LOW); // INT0 on D2 pin 4
EIFR = bit(INTF0); // clear interrupt flag for INT0
Timer2_init();
}
//==================================================================================================
void loop() {
// Push button pressed, display date time for 3 seconds
if (ButtonON) {
lc.shutdown(ADDRESS,false); // startup display
lc.setChar(ADDRESS,SECOND_U,seconds/10,false); // upper character
lc.setChar(ADDRESS,SECOND_L,seconds%10,false); // lower character
lc.setChar(ADDRESS,MINUTE_U,minutes/10,false);
lc.setChar(ADDRESS,MINUTE_L,minutes%10,true);
lc.setChar(ADDRESS,HOUR_U,hours/10,false);
lc.setChar(ADDRESS,HOUR_L,hours%10,true);
lc.setDigit(ADDRESS,DAY_U,days/10,false);
lc.setDigit(ADDRESS,DAY_L,days%10,true);
unsigned long t = millis();
while (millis() < t + 2000) {} // wait 2 seconds
lc.clearDisplay(ADDRESS); // clear display
lc.shutdown(ADDRESS,true); // shutdown display, power down mode
ButtonON = false; // clear push button flag
}
// back to sleep
cli(); // disable interrupts while setting up sleep mode
set_sleep_mode(SLEEP_MODE_PWR_SAVE); // set the sleep mode we want, will wake on Timer2 interrupt
sleep_enable(); // enables the sleep bit in the MCUCR register.
sleep_bod_disable(); // disable brown out detect in sleep
sei(); // enable interrupts, Timer 2 and Push button
sleep_mode(); // sets SMCR SE bit 0. This causes micro to enter sleep mode.
// micro will start from here after interrupts executed
// sleep disabled in Button press interrupt
}
//==================================================================================================
//==================================================================================================
void Timer2_init(void) {
// Timer 2 setup, CTC Mode. Allows varying the clk if not exactly 32K768Hz.
// Counter B used. OC2B has clock rate.
// Register bits cleared on reset.
//
// TCCR2A Control Register
// COM2A1 = 0, COM2A0 = 0, COM2B1 = 0, COM2B0 = 1, WGM21 = 1, WGM21 = 0.
// Toggle OC2B on compare match. CTC mode OCRB has compare value = TOP.
//
// TCCR2B Control Register
// FOC2A = 0, FOC2B = 0, WGM22 = 0, CS22 = 1, CS21 = 0, CS20 = 1.
// CS22,21,20 = 101. Prescaler 128.
//
// TIMSK2 Interrupt Mask Register
// OCIE2B = 1, OCIE2A = 0, TOIE2 = 0.
// OCIE2B = 1. Timer B compare match interrupt.
//
// ASSR Asynchronous Status Register
// EXCLK = 0, AS2 = 1, TCN2UB = 0, OCR2AUB = 0, OCR2BUB = 0, TCR2AUB = 0, TCR2BUB = 0.
// AS2 = 1. Timer2 Asynchronous mode.
// These bits cleared on reset, only need to set AS2.
//
// Interupt frequency = 32768Hz / (Prescale * count) = 32768/(128 * 256) = 1
TCCR2A |= _BV(COM2B1);
TCCR2B |= _BV(WGM22);
TCCR2A |= _BV(WGM21);
TCCR2A |= _BV(WGM20);
TCCR2B |= _BV(CS21);
TIMSK2 |= _BV(OCIE2B); //enable timer2B compare match
OCR2A = 127; // compare match value, closest to 1 second
// DVM Hz mode measured: 126 = 1.007s, 127 = 0.999s, 128 = 0.991s
DDRD |= _BV(0x03); // Set Data Direction PD3, D3, pin 5, OCR2B as output
ASSR |=_BV(AS2);
}
//==================================================================================================
ISR(TIMER2_COMPB_vect) {
digitalWrite(LED, !digitalRead(LED)); // toggle LED, could remove in final design
if (++seconds == 60) {
seconds = 0;
if (++minutes == 60) {
minutes = 0;
if (++hours == 24) {
hours = 0;
if (++days == 100) { days = 0; } // can only display 99 days
}
}
}
}
//==================================================================================================
//==================================================================================================
//==================================================================================================