Last active
February 1, 2021 17:44
-
-
Save kramolnic/c5911da146c887f441b7abac021dbfab to your computer and use it in GitHub Desktop.
Airfresher photo controller firmware for ATtiny10
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <avr/io.h> | |
#include <avr/interrupt.h> | |
#include <avr/pgmspace.h> | |
#include <avr/sleep.h> | |
#include <avr/wdt.h> | |
#include <stdint.h> | |
// Airfresher photo controller for an ATTiny 4/5/9/10 | |
// by kramolnic | |
/////////////////////////////////////////////////////////////////////////////////////// | |
// SETTINGS (you can change this values) | |
// Light time, sec: | |
#define LIGHT_SECS_TO_FIRE 150 | |
// Dark time, sec: | |
#define DARK_SECS_TO_FIRE 5 | |
/////////////////////////////////////////////////////////////////////////////////////// | |
//(Input) Light sensor is PB2 (PCINT2 / INT0) pin | |
#define LIGHT_SENSOR_PIN _BV(2) | |
//(Output) LED indicator | |
#define LED_PIN _BV(1) | |
//(Output) Drive control is PB0 (OC0A) pin | |
#define DRIVE_CONTROL_PIN _BV(0) | |
enum State | |
{ | |
s1 = 0, //Active mode - time counting | |
s2 //Waiting for watchdog reset | |
}; | |
volatile enum State state; | |
volatile uint32_t lightTimeCounter; | |
volatile uint32_t darkTimeCounter; | |
//Light sensor INT0 external interrupt (low-level async interrupt) | |
ISR (INT0_vect) | |
{ | |
asm("nop"); | |
} | |
//Timer compare A match interrupt (one-second timer) | |
ISR (TIM0_COMPA_vect) | |
{ | |
if (PINB & LIGHT_SENSOR_PIN) // dark | |
{ | |
PORTB ^= LED_PIN; | |
darkTimeCounter++; | |
} | |
else // light | |
{ | |
PORTB &= ~LED_PIN; | |
lightTimeCounter++; | |
darkTimeCounter = 0; | |
} | |
} | |
int main() | |
{ | |
///////////////////////////////////////////////////////////////////////////////////// | |
cli(); // Initialization begin | |
// disable watchdog timer (activated once, still active after reset!) | |
wdt_reset(); | |
RSTFLR &= ~(1<<WDRF); | |
CCP = 0xD8; | |
WDTCSR &= ~(1<<WDE); | |
// disable Analog comparator (enabled by default) | |
ACSR = (1<<ACD); | |
// disable Voltage level monitor | |
VLMCSR = 0; | |
// configure output pins | |
DDRB = DRIVE_CONTROL_PIN | LED_PIN; | |
// configure INT0 interrupt from light sensor | |
EICRA = (0<<ISC01) | (0<<ISC00); //Low level on INT0 generates an interrupt request | |
EIMSK = (1<<INT0); //Enable external INT0 from light sensor | |
// configure timer (OCR0A = 500 = 0x01F4) => 1Hz timer | |
OCR0AH = 0x01; | |
OCR0AL = 0xF4; | |
// reset counters and state | |
state = s1; | |
lightTimeCounter = 0; | |
darkTimeCounter = 0; | |
// Configure sleep mode | |
set_sleep_mode(SLEEP_MODE_PWR_DOWN); | |
// configure Main Clock Source to 500Hz | |
CCP = 0xD8; //Enable CCP. | |
CLKMSR = (0<<CLKMS1) | (1<<CLKMS0); //Internal 128 kHz Oscillator (WDT Oscillator) | |
CCP = 0xD8; | |
CLKPSR = (1<<CLKPS3) | (0<<CLKPS2) | (0<<CLKPS1) | (0<<CLKPS0); //500 Hz Main Clock operation (128 kHz / 256) | |
sei(); // Initialization end | |
///////////////////////////////////////////////////////////////////////////////////// | |
// Enter Power-down mode | |
sleep_enable(); | |
sleep_cpu(); | |
cli(); | |
EIMSK = (0<<INT0); //Disable external INT0 | |
sleep_disable(); | |
//activate timer | |
TCCR0A = (0<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (0<<WGM01) | (0<<WGM00); //Toggle OC0B on compare match | |
TCCR0B = (0<<ICNC0) | (0<<ICES0) | (0<<WGM03) | (1<<WGM02) | (0<<CS02) | (0<<CS01) | (1<<CS00); //clkIO/1 (no prescaling) => 1Hz | |
TIMSK0 = (1<<OCIE0A); // Output compare A match int enable | |
set_sleep_mode(SLEEP_MODE_IDLE); | |
sei(); | |
while(1) | |
{ | |
sleep_enable(); | |
sleep_cpu(); | |
switch (state) | |
{ | |
case s1: | |
{ | |
if (darkTimeCounter > DARK_SECS_TO_FIRE) // the light is off longer than DARK_SECS... | |
{ | |
if (lightTimeCounter > LIGHT_SECS_TO_FIRE) // the light was ON longer than LIGHT_SECS... | |
{ | |
PORTB |= DRIVE_CONTROL_PIN; //enable drive | |
} | |
// enable watchdog | |
wdt_reset(); | |
wdt_enable(WDTO_1S); | |
state = s2; | |
} | |
} | |
break; | |
case s2: //NOTE: nothing to do - waiting for watchdog reset | |
break; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment