/* Name: main.c * Author: Toshi Nagata * Copyright: 2009 (c) Toshi Nagata * License: Modified BSD License * * Pin 3: relay * Pin 5: motor PWM control * Pin 6, 7: IR receiver */ #include #include #include #define NBITS 16 #define CL 6.67 /* Timer clock in microseconds */ #define T0 ((short)(1500 / CL)) /* threshold for bit 0/1 */ #define T1 ((short)(20000 / CL)) /* interval within one chunk */ #define T2 ((short)(50000 / CL)) /* interval between 2 separate chunks */ volatile unsigned short t, start; volatile unsigned short tempData, oldData, data; volatile char tempCount; volatile char ready; volatile unsigned char mask; char current; ISR(TIM0_OVF_vect) { t += 256; if (t - start >= T2) { /* Long interval is detected */ /* Start waiting for the first interrupt */ /* (The incomplete data is discarded if present) */ tempCount = -1; oldData = 0; start = t = 0; mask = 0b00000110; } else if (t - start >= T1) { /* Short interval is detected */ if (tempCount >= 0 && tempCount < NBITS + 1) { /* Not waiting for end of chunk */ tempCount = -1; /* Start waiting for new data (may be overridden later; see below) */ /* Check the validity of the data */ /* (Specific for old DENON remote controller) */ if ((tempData & 0x1f) == 0x08) { tempData >>= 5; if (tempData & (1 << 9)) tempData = (~tempData) & 0x03ff; if (tempData == oldData) { data = tempData; ready = 1; /* Valid data */ tempCount = NBITS + 1; /* Skip until the end of chunk */ } oldData = tempData; } start = t = 0; } } } ISR(PCINT0_vect) { if ((PINB & mask) == 0) { /* pin input is low -> falling edge */ if (tempCount < 0) { /* Start data collection */ tempData = 0; tempCount = 0; mask = ~PINB & 0b00000110; /* Which pin caused the interrupt? */ } else if (tempCount < NBITS) { /* Read out one more bit */ if (t + (unsigned char)TCNT0 - start >= T0) tempData |= (1 << tempCount); tempCount++; } t = 0; start = (unsigned char)TCNT0; } } void setCurrent(void) { if (current < 0) { if ((PORTB & 0b00010000) == 0) { PORTB |= 0b00010000; _delay_ms(50); } OCR0A = 255 + current * 2; } else { if ((PORTB & 0b00010000) != 0) { PORTB &= 0b11101111; _delay_ms(50); } OCR0A = 255 - current * 2; } } int main(void) { cli(); /* Disable interrupt globally */ DDRB = 0b00010001; /* pin 3 (bit 4) and pin 5 (bit 0) for output */ TCCR0A = 0b11000000 /* PWM: set OC0A on compare match and clear at TOP */ | 0b00000011; /* Fast PWM */ TCCR0B = 0b00000000 /* Fast PWM with TOP = MAX */ | 0b00000010; /* Clock prescale by 8 */ current = 0; OCR0A = 255; /* PWM duty ratio */ TIMSK0 = 0b00000010; /* Timer0 overflow interrupt enabled */ /* MCUCR = 0b00000010; *//* INT0 interrupt on falling */ GIMSK = 0b00100000; /* PCINT enabled */ PCMSK = 0b00000110; /* PCINT1/2 (pin 6/7) enabled */ mask = 0b00000110; /* Observe both PCINT1/PCINT2 */ tempCount = -1; t = start = 0; sei(); /* Enable interrupt globally */ for (;;) { char c1; if (!ready) continue; /* Data is available */ switch (data) { case 0b1000010: /* button 1 */ c1 = 0; break; case 0b1000011: /* button 2 */ c1 = 80; break; case 0b1000100: /* button 3 */ c1 = 127; break; case 0b1000101: /* button 4 */ c1 = -80; break; default: c1 = -127; /* No valid button */ break; } ready = 0; /* This data is processed */ if (c1 != -127) { if (c1 != current) { do { if (c1 < current) current--; else current++; setCurrent(); _delay_ms(10); } while (c1 != current); } } } return 0; /* Never reached */ }