ATtiny13a Fridge Alarm
Was in the process of designing my own fridge alarm from ATtiny85 when I saw Ralph Bacon take the challenge of making one from an ATtiny13. I contacted Ralph and picked on him about mentioning "Alexa" on his channel.. Because it my Alexa kept trying to order stuff he would say :) . But I had to try this challenge. I had some difficulty. I then tried his and still has some difficulty and with mixing the two I got it to work but I just chose a single tone. Its been working now since February 2021.
Update June 2022:
This has worked so well I ended up doing a PCB from Oshpark and using this on any external door for my home. It works Great!!
https://oshpark.com/profiles/shermluge
UPDATE May 2023:
Ported to Microchip Studio:
works better and lower current
- Microchip studio port :)
* TONE TESTING!!! * SLEEP TESTING!!! Sherm, new fridge alarm inspired from Ralph Bacon...
for attiny13 By sherm
trying at 1.2MHzwith MiniCore/MicroCore (MCUDude / Nerd Ralph)
Serial at 19200 baud.but very poor quality..
2021-2-26 Tested and works as of 2021-2-27 Tested again on 2022-02-27 Use this one 2022-02-12
MAJOR OVER HAUL: 2022-03-19 1) added sleep @ 6uAmps 2) major code over haul*/#define F_CPU 1200000UL#include <avr/io.h>#include <avr/interrupt.h>#include <avr/sleep.h>#include <util/delay.h>
// constants won't change. Used here to set a pin number:#define ledPin PB4 #define buzzer PB3#define door PB2#define stealth PB1#define TX PB0 //now is output for timer#define LOW 0#define HIGH 1//need to swap these because they are BACKWARDS, but need to correct other code (swapped 3/16/22)#define doorClosed 1 //pulled high#define doorOpen 0 //pulled low
//////////////////////////////////volatile uint8_t doorStatus = doorClosed;volatile uint8_t prevDoorStatus = doorClosed; //changed from doorOpenvolatile uint8_t WarnCount = 0;volatile uint8_t AlarmCount = 0;
// Generally, you should use "unsigned long" for variables that hold time// The value will quickly become too large for an int to storevolatile unsigned long currentMS = 0; // will store last time LED was updated
// constants won't change:const int Second = 1000; // interval at which to blink (milliseconds)const int ThreeSeconds = 3000;const int WarnTimeSeconds = 15000;const uint8_t MaxWarn = 8;const uint8_t MaxAlarm = 20;
//functionsvoid beep();void doorClosedSound();void doorOpenSound();void sleepNow(void);
ISR(PCINT0_vect){// cli(); //GIMSK &= ~(1<<PCIE); // clear Pin change interrupts /* _delay_ms(50); //doorStatus = (PINB & (1 << PB2)); if(PINB & (1 << PB2)){ PORTB |= (1<<PB1); doorStatus=doorClosed; }else{ PORTB &= ~(1<<PB1); doorStatus=doorOpen; }*/ if(PINB & (1 << PB2)){ _delay_ms(50); PORTB |= (1<<PB1); doorStatus=doorClosed; }else{ PORTB &= ~(1<<PB1); doorStatus=doorOpen; }
}
ISR(TIM0_COMPA_vect){ TCNT0 = 0; //reset timer currentMS++;}
void initTimer(void){ TCCR0A |= (1<<COM0A0); TIMSK0 |= (1<<OCIE0A)|(1<<TOIE0); OCR0A = 145; //with CS01 this top is at 1khz TCCR0B |= (1<<WGM01)|(1<<FOC0A)|(1<<CS01);// DDRB = 0b00001111;// sei();}//void setup() {int main(){ // set the digital pin as output: //pinMode(ledPin, OUTPUT); //pinMode(buzzer, OUTPUT); DDRB |= (1 << ledPin); //set for output DDRB |= (1 << buzzer); //set for output DDRB |= (1 << PB0)|(1<<PB1); DDRB &= ~(1<< door); //set door to input PORTB |= (1<< door);//set pull up.
//to enable pull up, do after DDRB: //DDRB &= ~_BV(pin); // Set pin as input //PORTB |= _BV(pin); // Enable pullup resistors
//Pin Change interrupt on door //PB2 PCMSK |= (1<<PCINT2); // Sets the Pin change interrupt mask, only (PCINT3) PB3 will trigger the PCINT once it is enabled before sleep GIMSK |= (1<<PCIE); // Activate Pin change interrupts //rem by someone else not sherm initTimer(); // SREG |= (1<<SREG_I); //Enables Interrupts globally after setup //already included in initTimer() sei(); //pinMode(door, INPUT); #ifdef DEBUG // Note that any baud rate specified is ignored on the ATtiny13. See header above. // Serial.begin(); #endif beep(); //beep(50); while(1){
if (doorStatus != prevDoorStatus){ if(doorStatus == doorOpen){ //test sherm 2-28-22 //change to doorOpen!! BACKWARDS //fixed 3/16/22 doorOpenSound(); }else{ doorClosedSound(); _delay_ms(2000); sleepNow(); AlarmCount=0; WarnCount=0; currentMS=0; } prevDoorStatus=doorStatus; // currentMS=0; } if(PINB & (1 << PB2)){ PORTB |= (1<<PB1); doorStatus=doorClosed; }else{ PORTB &= ~(1<<PB1); doorStatus=doorOpen; } if(doorStatus == doorOpen){ // BACKWARDS NEED TO CHANGE TO == OR CHANGE TO doorClosed //fixed 3/16/22 //Warn door is open every so many seconds. if(WarnCount <= MaxWarn && currentMS >= WarnTimeSeconds){ // reset timer currentMS=0; WarnCount++; for(uint8_t i=0;i<=WarnCount;i=i+2){ //beep(60-(2*i)); beep(); } }//if warn //Alarm, beep every so many seconds if(WarnCount >MaxWarn && currentMS >= ThreeSeconds){ beep(); // save the last time you blinked the LED currentMS=0; AlarmCount++; }//if alarm //Max Alarm sound after so long on normal alarm. if(AlarmCount >MaxAlarm && currentMS >= Second){ beep(); // Reset timer currentMS=0; }//if alarm MAX }else{ //door closed: doorClosedSound(); //just unremmed sleepNow(); } } }
void sleepNow(void){ DDRB = 0; PORTB = 0b11100111;
//PCMSK |= (1<<PCINT2); // Sets the Pin change interrupt mask, only (PCINT3) PB3 will trigger the PCINT once it is enabled before sleep GIMSK |= (1<<PCIE); // Activate Pin change interrupts //rem by someone else not sherm //worked: // ADCSRA &= ~(1<<ADEN); // disable ADC - must be done before PRR // PRR = 1<<PRADC; // shut down ADC //sei(); // Enable global interrupts set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_mode(); //sleep_cpu();//does not work sleep_disable(); initTimer(); DDRB |= (1 << ledPin); //set for output DDRB |= (1 << buzzer); //set for output DDRB |= (1 << PB0)|(1<<PB1); DDRB &= ~(1<< door); //set door to input PORTB |= (1<< door);}
void doorOpenSound(){// PORTB |= (1 << buzzer); // _delay_ms(10);// PORTB &= ~(1 << buzzer); // _delay_ms(20); PORTB |= (1 << buzzer); _delay_ms(10); PORTB &= ~(1 << buzzer); _delay_ms(20); PORTB |= (1 << buzzer); _delay_ms(10); PORTB &= ~(1 << buzzer);
PORTB |= (1 << ledPin); _delay_ms(80); PORTB &= ~(1 << ledPin); }void doorClosedSound(){ //beep PORTB |= (1 << buzzer); _delay_ms(20); PORTB &= ~(1 << buzzer); _delay_ms(200); PORTB |= (1 << buzzer); _delay_ms(20); PORTB &= ~(1 << buzzer); _delay_ms(400); PORTB |= (1 << buzzer); _delay_ms(20); PORTB &= ~(1 << buzzer); //led flash PORTB |= (1 << ledPin); _delay_ms(80); PORTB &= ~(1 << ledPin); }void beep(void){ //beep PORTB |= (1 << buzzer); _delay_ms(50); PORTB &= ~(1 << buzzer); //led PORTB |= (1 << ledPin); _delay_ms(40); PORTB &= ~(1 << ledPin); }
/*
Arduino version:
Sherm, new fridge alarm inspired from Ralph Bacon...
for ATtiny13
trying at 1.2MHz
with MiniCore/MicroCore (MCUDude / Nerd Ralph)
Serial at 19200 baud.
2021-2-26
Tested and works as of 2021-2-27
*/
#include <avr/io.h>
#define DEBUG
// constants won't change. Used here to set a pin number:
#define ledPin PB4
#define buzzer PB3
#define door PB2
#define stealth PB1
#define TX PB0
// Variables will change:
int ledState = LOW; // ledState used to set the LED
bool doorClosed = 0; //pulled to ground
bool doorOpen = 1; //high
bool doorStatus = doorClosed;
bool prevDoorStatus = doorOpen;
uint8_t WarnCount = 0;
uint8_t AlarmCount = 0;
// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0; // will store last time LED was updated
// constants won't change:
const int Second = 1000; // interval at which to blink (milliseconds)
const int ThreeSeconds = 3000;
const int WarnTimeSeconds = 15000;
const long Minute = 60000;
const long FiveMinutes =240000;
const uint8_t MaxWarn = 8;
const uint8_t MaxAlarm = 20;
//functions
bool isDoorOpen();
void beep();
bool stealthMode();
void doorClosedSound();
void doorOpenSound();
void setup() {
// set the digital pin as output:
//pinMode(ledPin, OUTPUT);
//pinMode(buzzer, OUTPUT);
DDRB |= (1 << ledPin); //set for output
DDRB |= (1 << buzzer); //set for output
//pinMode(door, INPUT);
#ifdef DEBUG
// Note that any baud rate specified is ignored on the ATtiny13. See header above.
Serial.begin();
#endif
beep();
beep();
}
void loop() {
// here is where you'd put code that needs to be running all the time.
// check to see if it's time to blink the LED; that is, if the difference
// between the current time and last time you blinked the LED is bigger than
// the interval at which you want to blink the LED.
if(isDoorOpen()==doorOpen){
unsigned long currentMillis = millis();
#ifdef DEBUG
if(!((currentMillis-previousMillis)%100)){
// Serial.print(currentMillis-previousMillis);
Serial.println(F(" in loop"));
}
#endif
//Warn door is open every so many seconds.
if(WarnCount <= MaxWarn && currentMillis - previousMillis >= WarnTimeSeconds){
#ifdef DEBUG
Serial.println(F("Warn"));
#endif
// save the last time you blinked the LED
previousMillis = currentMillis;
//ledState=ledState ? HIGH:LOW;
WarnCount++;
for(uint8_t i=0;i<=WarnCount;i=i+2){
beep();
}
}//if warn
//Alarm, beep every so many seconds
if(WarnCount >MaxWarn && currentMillis - previousMillis >= ThreeSeconds){
#ifdef DEBUG
Serial.println(F("Alarm"));
#endif
beep();
// save the last time you blinked the LED
previousMillis = currentMillis;
AlarmCount++;
//doorIsOpen = doorStatus ? true : false;
}//if alarm
//Max Alarm sound after so long on normal alarm.
if(AlarmCount >MaxAlarm && currentMillis - previousMillis >= Second){
#ifdef DEBUG
//Serial.println(F("Alarm MAX"));
#endif
beep();
// save the last time you blinked the LED
previousMillis = currentMillis;
//doorIsOpen = doorStatus ? true : false;
}//if alarm MAX
} //isDoorOpen()
}
bool isDoorOpen(){
doorStatus=digitalRead(door);
if (doorStatus!=prevDoorStatus){
if(doorStatus==doorOpen){
#ifdef DEBUG
Serial.println(F("Door Open"));
#endif
doorOpenSound();
}else{
#ifdef DEBUG
Serial.println(F("Door Closed"));
#endif
doorClosedSound();
AlarmCount=0;
WarnCount=0;
}
prevDoorStatus=doorStatus;
previousMillis=millis();
}
_delay_ms(20);
return doorStatus;
}
bool stealthMode(){
return digitalRead(stealth);
}
void doorOpenSound(){
if(!stealthMode()){
PORTB |= (1 << buzzer); //replaces digitalWrite(buzzer, HIGH);
delay(10);
PORTB &= ~(1 << buzzer); //replaces digitalWrite(buzzer, LOW);
delay(20);
PORTB |= (1 << buzzer);
delay(10);
PORTB &= ~(1 << buzzer);
delay(20);
PORTB |= (1 << buzzer);
delay(10);
PORTB &= ~(1 << buzzer);
}
PORTB |= (1 << ledPin);
delay(80);
PORTB &= ~(1 << ledPin);
}
void doorClosedSound(){
if(!stealthMode()){
PORTB |= (1 << buzzer);
delay(20);
PORTB &= ~(1 << buzzer);
delay(150);
PORTB |= (1 << buzzer);
delay(10);
PORTB &= ~(1 << buzzer);
}
PORTB |= (1 << ledPin);
delay(80);
PORTB &= ~(1 << ledPin);
}
void beep(){
if(!stealthMode()||AlarmCount >MaxAlarm){
PORTB |= (1 << buzzer);
delay(20);
PORTB &= ~(1 << buzzer);
}
PORTB |= (1 << ledPin);
delay(80);
PORTB &= ~(1 << ledPin);
}
Posted this in November so its been working solid for over 8 months now and no issues..
Links:
A great source for Attiny13 info https://blog.podkalicki.com/