/* * 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);}