ATtiny424 Binary kitchen timer-internal clock

Simple binary timer for the kitchen, using the ATtiny424 (was going to initially use the 402 but needed more pins). This was my way of learning more about the 2-series ATtiny chips. I also have 2 different mounting versions of 424 (both the SOP and SSOP). It works and I use it. It sleeps at 1.4uAmps..

If I would had thought it out a tad more. I would have used the 12th charlieplexed light to use to make it go to 32 minutes instead of 15 minutes max.. Maybe in next version.. But for now I want to work on the binary clock.

The internal 32768Hz clock works great on these ATtiny chips (0,1, and 2 series).


https://www.thingiverse.com/thing:5397464

Updated Case with clear windows using UV glue:

20220528_072030.mp4
/* * ATtiny424-Binary-Timer-v5-debounce.c * * Up Dated: 5/28/2022 * * Author : Sherm * * Works Great!! sleeps at 1.4ua's * Set needs to be done with holding set, then taping start stop briefly. * due to de-bounce maybe, need to check with scope. * * * Created: 4/29/2022 18:23:01 *v3 5/3/2022 * 5/4/2022 got it working :) * 5/8/2022 started working on switch debounce v4 * After trying software vs hardware and both. The 100nf cap seemed to do best.. * 5/24/2022 fixed de-bounce issue and now it sleeps after PauseMax seconds (if paused). * 5/28/2022 Fixed bleed threw killed pull up resistors after sleep * * Author : Sherman Stebbins */

#define F_CPU 3333333UL#include <avr/io.h>#include <avr/interrupt.h>#include <util/delay.h>#include <avr/sleep.h>
#define PA PIN4_bm //PIN3_bm_cxl //PIN3_bm_cxl#define PB PIN5_bm //PIN6_bm //PIN6_bm#define PC PIN6_bm //PIN7_bm //PIN7_bm#define PD PIN7_bm //PIN1_bm_set //PIN1_bm_set#define PIN1_bm_set PIN1_bm#define PIN2_bm_strt_stop PIN2_bm#define PIN3_bm_cxl PIN3_bm
#define ModeMax 3#define PauseMax 300//#define DEBG
const uint8_t led_dir[12] = { ( PA | PB), //LED 0 1 ( PA | PB), //LED 0 1 ( PC | PA), //LED 2 3 ( PC | PA), //LED 2 3 ( PB | PC), //LED 4 5 ( PB | PC), //LED 4 5 -- ( PD | PA), //LED 6 7 ( PD | PA), //LED 6 7 ( PB | PD), //LED 8 9 ( PB | PD), //LED 8 9 ( PD | PC), //LED 10 11 ( PD | PC) }; //LED 10 11
const uint8_t led[12] = { ( PB ), //LED 0 ( PA ), //LED 1 ( PC ), //LED 2 ( PA ), //LED 3 ( PC ), //LED 4 PB PA ( PB ), //LED 5 PC PD ( PD ), //LED 6 PD PC ( PA ), //LED 7 PA PB ( PD ), //LED 8 ( PB ), //LED 9 ( PD ), //LED 10 ( PC) }; //LED 11 volatile uint8_t timerOn = 0;volatile uint8_t trigger = 0;volatile int8_t seconds = 0;volatile int8_t tSeconds = 0;volatile int8_t minutes = 1;volatile uint8_t setMinutes = 1;volatile uint8_t setCount = 0;volatile uint8_t alarm = 0;volatile uint8_t alarmCount = 0;volatile uint8_t paused = 1; volatile uint8_t timerStopped =0;volatile uint8_t newSetTime = 1;volatile int8_t loopsCount = 3; // might remove, not seeing use other then debounce maybe..volatile uint16_t pauseCount=0; //if left on pause to long, then sleep
void ledOn(uint8_t light);void allLedOff(void);void mySleep(void);void displayTime(void);
ISR(PORTA_PORT_vect){ if(PORTA.INTFLAGS & PIN2_bm_strt_stop){ PORTA.INTFLAGS &= PIN2_bm_strt_stop; while(PORTA.IN & PIN2_bm_strt_stop){;} //tested great and fixed bounce. RTC.PITINTCTRL = 0b00000001; //restart PIT interrupt if(!paused){ paused=1; }else{ paused=0; loopsCount=0; pauseCount=0; } alarm=0; PORTB.OUT &= ~PIN1_bm;//shut off alarm if just in case }}
ISR(RTC_PIT_vect){ trigger=1; RTC_PITINTFLAGS = 0b00000001; ///////Timer on so Count down/////////////////////// if(!(PORTA.IN & PIN2_bm_strt_stop) && timerOn && !alarm ){ //if timerOn is on and no alarm and no button2 then count down if(!paused)seconds--; } //////Set timer///////////////////// if(loopsCount-- <=0)loopsCount=0; if(PORTA.IN & PIN1_bm_set && (paused||!timerOn)){//!timerOn ){ //if Pin1 and no timer, set minutes setCount=1; setMinutes++; alarmCount=0; alarm=0; trigger=0; loopsCount= 3; paused=1; } ///////Alarm/////////////////////////////// if(alarm){ //if alarm out put tone allLedOff(); if(alarmCount<24){ //ledOn(alarmCount); PORTB.OUT ^= PIN1_bm; alarmCount++; }else{ PORTB.OUT &= ~PIN1_bm; alarm=0; alarmCount=0; } } /////Reset to 1 minute shortcut////////////////////////// if(PORTA.IN & PIN1_bm_set && PORTA.IN & PIN2_bm_strt_stop ){ timerOn=0; alarm=0; paused=0; trigger=0; setMinutes=1; } if(paused){ pauseCount++; }}
int main(void){ CCP = 0xD8; CLKCTRL_MCLKCTRLB = 0b00010101; //I just find binary easier.. //RTC.PITCTRLA = 0b01110001; //works also = RTC_PERIOD_CYC16384_gc same with PIT enable RTC.PITCTRLA = RTC_PERIOD_CYC32768_gc|RTC_PITEN_bm; //did it this way and it works while(RTC.PITSTATUS==1){} // RTC.CLKSEL = RTC_CLKSEL_INT32K_gc; //OSCULP32K RTC.PITINTCTRL = 0b00000001;//turn on interrupt for pit // PORTA.DIR = PIN7_bm | PIN1_bm_set |PIN2_bm_strt_stop|PIN3_bm_cxl|PIN6_bm; //or PORTA.DIR = 0b11110000; //both work PORTB.DIR |= PIN1_bm; PORTA.PIN3CTRL = PORT_PULLUPEN_bm | PORT_INVEN_bm; // pullup and invert for button logic PORTA.PIN2CTRL = PORT_PULLUPEN_bm | PORT_INVEN_bm | PORT_ISC_FALLING_gc; // pullup and invert for button logic PORTA.PIN1CTRL = PORT_PULLUPEN_bm | PORT_INVEN_bm; // pullup and invert for button logic sei(); ledOn(11); //visual start indicator PORTB.OUT |= PIN1_bm; //short beep on power up. _delay_ms(10); PORTB.OUT &= ~PIN1_bm; allLedOff(); //SLPCTRL.CTRLA = (2<<1)|1; //POWERDOWN, SEN sleep enable set_sleep_mode(SLEEP_MODE_PWR_DOWN); while (1) { ////////////////////cxl or paused to long/////////////////////////////// if((PORTA.IN & PIN3_bm_cxl)||pauseCount>PauseMax){ //if Alarm cxl button pressed, turn off alarm. pauseCount=0; alarmCount=0; alarm=0; PORTB.OUT &= ~PIN1_bm; //shut off alarm mySleep(); } ////////////////////Set timer/////////////////////////// if((PORTA.IN & PIN1_bm_set) && ((!timerOn && setCount)||paused)){ //set timer pauseCount=0; alarm=0; PORTB.OUT &= ~PIN1_bm; //shut off alarm if(setMinutes >15)setMinutes=0; setCount=0; newSetTime=1; loopsCount=3; } //////////////////Pause-Play//////////////////////////// if((PORTA.IN & PIN2_bm_strt_stop) && !(PORTA.IN & PIN1_bm_set )){ //start timer. // while(PORTA.IN & PIN2_bm_strt_stop){;} //tested hold until lifted. used one above instead if(!timerOn||newSetTime){ newSetTime=0; minutes = setMinutes; seconds=0; timerOn=1; minutes--; tSeconds=5; seconds=9; //paused=0; } } if(trigger && timerOn){ //if clock running, display and check times if(seconds<0){ seconds=0; //just added Seems to work!! on now all seconds lit. if(minutes<=0 && tSeconds<=0){ timerOn=0; alarm=1; allLedOff(); }else{ seconds = 9; tSeconds--; if(tSeconds<0){ if(!(minutes<=0)){ tSeconds=5; minutes--; if(minutes <0){ minutes=0; } } } } }// displayTime(); } /////////////Display time setting //if( alarm || ((loopsCount>0) && (!timerOn||paused) && setMinutes>0)){ //display time set when timer is NOT running. if( alarm || !timerOn ||newSetTime){ //display time set when timer is NOT running. if(setMinutes & 0x1){ ledOn(8);} if(setMinutes & 0x2){ ledOn(9); } if(setMinutes & 0x4){ledOn(10); } if(setMinutes & 0x8){ledOn(11); } newSetTime=1; paused=1; }else{ displayTime(); } }}
void displayTime(void){ if(seconds & 0x1){ledOn(0);} if(seconds & 0x2){ ledOn(1); } if(seconds & 0x4){ ledOn(2); } if(seconds & 0x8){ ledOn(3); } if(tSeconds & 0x1 ){ledOn(4);} if(tSeconds & 0x2 ){ ledOn(5); } if(tSeconds & 0x4 ){ ledOn(6); } if(tSeconds & 0x8 ){ ledOn(7); } if(minutes & 0x1){ ledOn(8);} if(minutes & 0x2){ ledOn(9); } if(minutes & 0x4){ledOn(10); } if(minutes & 0x8){ledOn(11); } }
void mySleep(void){ timerOn=0; paused=1; PORTB.OUT &= ~PIN1_bm; allLedOff();
//1-3 already inputs with pullups for power save PORTA.DIR &= ~(PIN4_bm|PIN5_bm|PIN6_bm|PIN7_bm); //pull up to save power PORTA.PIN4CTRL = PORT_PULLUPEN_bm; PORTA.PIN5CTRL = PORT_PULLUPEN_bm; PORTA.PIN6CTRL = PORT_PULLUPEN_bm; PORTA.PIN7CTRL = PORT_PULLUPEN_bm; // PORTB.DIR &= ~(PIN0_bm|PIN2_bm|PIN3_bm); PORTB.PIN0CTRL = PORT_PULLUPEN_bm; PORTB.PIN2CTRL = PORT_PULLUPEN_bm; PORTB.PIN3CTRL = PORT_PULLUPEN_bm;
timerStopped = 1; RTC.PITINTCTRL = 0b00000000; //turn off PIT interrupt - untested //sleep SLPCTRL.CTRLA = 0b00000101; //set power down and sleep enable sei(); sleep_mode(); //same: //sleep_enable(); //asm("sleep");// sleep_cpu(); //sleep_disable(); //after wake: RTC.PITINTCTRL = 0b00000001;//turn on interrupt for pit //this stopped bleed added 5-28-22 PORTA.PIN4CTRL &= ~PORT_PULLUPEN_bm; PORTA.PIN5CTRL &= ~PORT_PULLUPEN_bm; PORTA.PIN6CTRL &= ~PORT_PULLUPEN_bm; PORTA.PIN7CTRL &= ~PORT_PULLUPEN_bm; // PORTA.DIR |= (PIN7_bm | PIN6_bm |PIN5_bm|PIN4_bm); PORTA.OUT &= ~(PIN7_bm | PIN6_bm | PIN5_bm |PIN4_bm); //PORTB.DIR |= PIN1_bm;}
void ledOn(uint8_t light){ allLedOff(); PORTA.DIR = led_dir[light]; PORTA.OUT = led[light];}
void allLedOff(void){ PORTA.OUT &= ~(PIN4_bm|PIN5_bm|PIN6_bm|PIN7_bm); //much better, no bleed over now. PORTA.DIR &= ~(PIN4_bm|PIN5_bm|PIN6_bm|PIN7_bm);}