/* fan_control - Copyright (c) 2016 Pat Thoyts <[email protected]>
*
* ATtiny85 with LED on pin PB2 and a 2N7000 MOSFET on PB3 which controls
* a computer fan run off 12V supply. Toggle the fan on for 10 minutes then
* off for 20 minutes. Start with the fan ON
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/power.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
/* Timing is designed for 8MHz system clock */
#ifndef F_CPU
# define F_CPU 8000000UL
#endif
#define LED_PIN PB2
#define FAN_PIN PB3
volatile uint8_t ticks;
volatile uint8_t seconds;
volatile uint8_t minutes;
ISR(TIMER0_COMPA_vect)
{
/* count up to 1s (254 ticks) then toggle the LED.
* after 15 minutes, toggle the fan
* Note: should in theory be 250 but measured it and require 254 for 1s
* Note: 125Hz on oscilloscope is for full wave so on and off.
*/
if (++ticks == 254)
{
if (++seconds == 61)
{
/*
* 33% duty cycle
* on for 10 minutes out of every 30
*/
if (minutes == 0) /* on */
DDRB |= _BV(FAN_PIN);
if (minutes == 10) /* off */
DDRB &= ~_BV(FAN_PIN);
if (++minutes == 30)
minutes = 0;
seconds = 0;
}
ticks = 0;
/* toggle the led every other second */
if ((seconds & 1) == 0)
PORTB |= _BV(LED_PIN);
}
}
/* put the processor into the currently defined sleep mode */
static void
sleep_now(void)
{
cli();
sleep_enable();
sei();
sleep_cpu();
sleep_disable();
}
/* configure timer 0 as a counter. Raises interrupts at 250 Hz */
static void
init_timer0(void)
{
cli();
ticks = seconds = minutes = 0;
/*
* WGM = 0b010: CTC mode (0 -> OCRA)
* COM0A = 0b00: PWM A disabled
* COM0B = 0b00: PWM B disabled
* CS = 0b011: CLK/64; 0b100: CLK/256
* freq = 8e6 / 64 / 125 == 1000.0 ie 1kHz.
* freq = 8e6 / 256 / 125 == 250 Hz
*/
TCCR0A = _BV(WGM01);
TCCR0B = _BV(CS02);
TCNT0 = 0;
OCR0A = 125;
TIMSK |= (1 << OCIE0A); /* interrupt on compare match with OCR0A */
sei();
}
/* Configure fast PWM on PB3 (OC1B) */
static void
init_pwm_timer1()
{
cli();
/* set pin PB3 (OC1B) as output */
DDRB |= _BV(DDB3);
PORTB &= ~_BV(PB3);
/*
* PWM1A = 0: disabled modulator A (attached to PB0 and PB1)
* PWM1B = 1: enable PWM mode for OCR1B and 0 when match OCR1C
* COM1A = 0b00: OC1A disconnected
* COM1B = 0b01: OC1B clear on compare match, set at BOTTOM,
* OC1B# set on compare match, clear at 0. (Table 12-1).
* CS = 0b0001: PCK/1
* OCR1C = 0xFF: TOP, resets counter when matches
* freq = (8MHz / 1 / 256) -> 31kHz.
*/
TCCR1 = _BV(CS10);
GTCCR = _BV(PWM1B) | _BV(COM1B0);
OCR1B = 60; //lower is faster 190 is stalled
OCR1C = 255;
sei();
}
int
main(void)
{
wdt_enable(WDTO_1S);
power_adc_disable();
power_usi_disable();
/* set all unused pins high-z, led pin output and low */
DDRB = _BV(LED_PIN);
PORTB = ~(_BV(LED_PIN));
init_timer0();
init_pwm_timer1();
set_sleep_mode(SLEEP_MODE_IDLE);
sei();
for (;;)
{
/* sleep all the time. Gets woken up by the timer at 250Hz */
wdt_reset();
sleep_now();
}
}