#include <TinyDebug.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#include <avr/sleep.h>
#include <math.h>
#define F_CPU 1200000UL // ATtiny13 operates at 1.2 MHz
#define PWM1_PIN PB0 // OC0A
#define PWM2_PIN PB1 // OC0B
#define BUTTON_PIN PB2
#define SHORT_PRESS_THRESHOLD (uint16_t)(50) // ~170 ms
#define LONG_PRESS_THRESHOLD (uint16_t)(1000) // ~5 seconds
#define PWM1_ON_DURATION (uint32_t)(1000) // 15 minutes in 3.6ms ticks
#define PWM1_FADE_STEPTIME (uint16_t)(50) // Nr of 3.6ms ticks before a next fadeing step is made
#define PWM2_FADE_STEPTIME (uint16_t)(50) // Nr of 3.6ms ticks before a next fadeing step is made
uint32_t button_press_time = 0;
uint16_t pwm1_counter = 0;
uint8_t pwm1_stepCount = 0;
uint8_t pwm2_stepCount = 0;
int16_t pwm1_duty_cycle = 0; //Need 16bit for calculation in decay to be handled
int16_t pwm2_duty_cycle = 128; //Need 16bit for calculation in decay to be handled
volatile uint8_t timer_interrupt_flag = 0;
uint8_t button_history = 0xFF;
uint16_t press_count = 0;
uint8_t StepUp = 1;
uint8_t EEMEM stored_pwm2_duty_cycle;
ISR(TIM0_OVF_vect) {
timer_interrupt_flag = 1;
}
void handle_pwm1() {
if (pwm1_duty_cycle>0) {
pwm1_counter = pwm1_counter+1;
if (pwm1_counter > PWM1_ON_DURATION) {
pwm1_stepCount = pwm1_stepCount+1;
if (pwm1_stepCount > PWM1_FADE_STEPTIME) {
pwm1_duty_cycle = pwm1_duty_cycle - max(1,pwm1_duty_cycle/12); // Logarithmic decay
if (pwm1_duty_cycle < 0) { pwm1_duty_cycle=0; }
OCR0A = pwm1_duty_cycle;
pwm1_counter = PWM1_ON_DURATION+1; //Limit max count
pwm1_stepCount = 0;
}
}
} else {
pwm1_counter=0;
pwm1_stepCount = 0;
}
}
void handle_pwm2() {
pwm2_stepCount++;
if (pwm2_stepCount > PWM2_FADE_STEPTIME) {
if (StepUp) {
pwm2_duty_cycle = pwm2_duty_cycle + max(1,pwm2_duty_cycle/5); // Logarithmic increase
} else {
pwm2_duty_cycle = (pwm2_duty_cycle * 255) / 271; // Logarithmic decay
}
if (pwm2_duty_cycle <= 0) {
StepUp = 1;
pwm2_duty_cycle = 0;
} else if (pwm2_duty_cycle >= 255) {
StepUp = 0;
pwm2_duty_cycle = 255;
}
OCR0B = pwm2_duty_cycle;
pwm2_stepCount = 0;
}
}
void toggle_pwm1() {
if (pwm1_duty_cycle == 0) {
pwm1_duty_cycle = 255;
pwm1_counter = 0;
} else {
pwm1_duty_cycle = 0;
}
OCR0A = pwm1_duty_cycle;
}
int main() {
// Setup
Debug.begin();
DDRB |= (1 << PWM1_PIN) | (1 << PWM2_PIN); // PWM pins as output
DDRB &= ~(1 << BUTTON_PIN); // Button pin as input
PORTB |= (1 << BUTTON_PIN); // Enable pull-up resistor
// Configure Timer0 for Fast PWM mode, prescaler 8
TCCR0A = (1 << WGM00) | (1 << COM0A1) | (1 << COM0B1); // Fast PWM mode
TCCR0B = (1 << CS01) ; // Prescaler 8
TIMSK = (1 << TOIE0); // Enable Timer0 overflow interrupt
pwm2_duty_cycle = eeprom_read_byte(&stored_pwm2_duty_cycle);
OCR0B = pwm2_duty_cycle;
OCR0A = pwm1_duty_cycle;
sei(); // Enable global interrupts
while(1) {
OCR0A = 255;
OCR0B = 0;
_delay_ms(1000);
OCR0A = 0;
OCR0B = 255;
_delay_ms(1000);
}
}