Created
May 6, 2017 13:26
-
-
Save julznc/2d750d4441182144db46685137e269af to your computer and use it in GitHub Desktop.
ATtiny2313 Infrared Sender (avr-gcc)
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
/* | |
* http://projectproto.blogspot.com/2017/05/attiny-ir-remote.html | |
*/ | |
#include <avr/io.h> | |
#include <avr/interrupt.h> | |
#include <avr/sleep.h> | |
#include <util/delay.h> | |
// led (OC0B) pin | |
#define IRLED_ENABLE() DDRD |= _BV(DDD5); PORTD &= ~_BV(PD5); | |
#define IRLED_DISABLE() DDRD &= ~_BV(DDD5); | |
// push buttons | |
#define POWER_BTN _BV(PB3) | |
#define FUNCTION_BTN _BV(PB2) | |
#define VOLUP_BTN _BV(PB4) | |
#define VOLDOWN_BTN _BV(PB5) | |
#define TUNEUP_BTN _BV(PB7) | |
#define TUNEDOWN_BTN _BV(PB6) | |
#define ALL_BTN (POWER_BTN|FUNCTION_BTN|VOLUP_BTN|VOLDOWN_BTN|TUNEUP_BTN|TUNEDOWN_BTN) | |
#define TIMER_ENABLE_PWM() (TCCR0A |= _BV(COM0B1)) | |
#define TIMER_DISABLE_PWM() (TCCR0A &= ~(_BV(COM0B1))) | |
#define TIMER_CONFIG_KHZ(val) ({ \ | |
const uint8_t pwmval = F_CPU / 2000 / (val); \ | |
TCCR0A = _BV(WGM00); \ | |
TCCR0B = _BV(WGM02) | _BV(CS00); \ | |
OCR0A = pwmval; \ | |
OCR0B = pwmval / 3; \ | |
}) | |
#define MARK(us) TIMER_ENABLE_PWM(); _delay_us(us) | |
#define SPACE(us) TIMER_DISABLE_PWM(); _delay_us(us) | |
#define SONY_HDR_MARK 2400 | |
#define SONY_HDR_SPACE 600 | |
#define SONY_ONE_MARK 1200 | |
#define SONY_ZERO_MARK 600 | |
//http://elektrolab.wz.cz/katalog/samsung_protocol.pdf | |
#define SAMSUNG_HDR_MARK 4500 | |
#define SAMSUNG_HDR_SPACE 4500 | |
#define SAMSUNG_BIT_MARK 560 | |
#define SAMSUNG_ONE_SPACE 1690 | |
#define SAMSUNG_ZERO_SPACE 560 | |
void enableIROut (int khz) | |
{ | |
IRLED_ENABLE(); | |
TIMER_CONFIG_KHZ(khz); | |
} | |
uint32_t reverseBits(uint32_t input, uint8_t nbits) { | |
uint32_t output = input; | |
for (uint8_t i = 1; i < nbits; i++) { | |
output <<= 1; | |
input >>= 1; | |
output |= (input & 1); | |
} | |
return output; | |
} | |
uint32_t encodeSony (uint8_t nbits, uint8_t command, | |
uint8_t address, uint8_t extended) | |
{ | |
uint32_t result = 0; | |
switch (nbits) { | |
case 12: // 5 address bits. | |
result = address & 0x1F; | |
break; | |
case 15: // 8 address bits. | |
result = address & 0xFF; | |
break; | |
case 20: // 5 address bits, 8 extended bits. | |
result = address & 0x1F; | |
result |= (extended & 0xFF) << 5; | |
break; | |
default: | |
return 0; | |
} | |
result = (result << 7) | (command & 0x7F); | |
return reverseBits(result, nbits); | |
} | |
void sendSony (uint32_t data, int nbits) | |
{ | |
// Set IR carrier frequency | |
enableIROut(40); | |
// Header | |
MARK(SONY_HDR_MARK); | |
SPACE(SONY_HDR_SPACE); | |
// Data | |
for (uint32_t mask = 1UL << (nbits - 1); mask; mask >>= 1) { | |
if (data & mask) { | |
MARK(SONY_ONE_MARK); | |
SPACE(SONY_HDR_SPACE); | |
} else { | |
MARK(SONY_ZERO_MARK); | |
SPACE(SONY_HDR_SPACE); | |
} | |
} | |
} | |
void sendSamsung (uint32_t data, int nbits) | |
{ | |
// Set IR carrier frequency | |
enableIROut(38); | |
// Header | |
MARK(SAMSUNG_HDR_MARK); | |
SPACE(SAMSUNG_HDR_SPACE); | |
// Data | |
for (uint32_t mask = 1UL << (nbits - 1); mask; mask >>= 1) { | |
if (data & mask) { | |
MARK(SAMSUNG_BIT_MARK); | |
SPACE(SAMSUNG_ONE_SPACE); | |
} else { | |
MARK(SAMSUNG_BIT_MARK); | |
SPACE(SAMSUNG_ZERO_SPACE); | |
} | |
} | |
// Footer | |
MARK(SAMSUNG_BIT_MARK); | |
SPACE(0); // Always end with the LED off | |
} | |
void enterSleep(void) | |
{ | |
IRLED_DISABLE(); | |
// Enable Pin Change Interrupts on all buttons | |
GIMSK |= _BV(PCIE); | |
PCMSK |= ALL_BTN; | |
sleep_enable(); | |
sei(); // Enable interrupts | |
sleep_cpu(); | |
} | |
ISR(PCINT_vect) { | |
cli(); // Disable interrupts | |
PCMSK &= ~ALL_BTN; // clear interrupt flags | |
sleep_disable(); | |
_delay_ms(1); | |
switch ( (~PINB) & ALL_BTN ) | |
{ | |
#if 1 // sony dvd | |
case POWER_BTN: | |
sendSony(encodeSony(15, 21, 80, 0), 15); // on/off | |
break; | |
case FUNCTION_BTN: | |
sendSony(encodeSony(15, 105, 208, 0), 15); // source | |
break; | |
case VOLUP_BTN: | |
sendSony(encodeSony(15, 18, 80, 0), 15); // volume + | |
break; | |
case VOLDOWN_BTN: | |
sendSony(encodeSony(15, 19, 80, 0), 15); // volume - | |
break; | |
case TUNEUP_BTN: | |
sendSony(encodeSony(20, 52, 16, 16), 20); // tune + | |
break; | |
case TUNEDOWN_BTN: | |
sendSony(encodeSony(20, 51, 16, 16), 20); // tune - | |
break; | |
#else // samsung tv | |
// https://github.com/lepiaf/IR-Remote-Code | |
case POWER_BTN: | |
sendSamsung(0xE0E040BF, 32); // on/off | |
break; | |
case FUNCTION_BTN: | |
sendSamsung(0xE0E0807F, 32); // source | |
break; | |
case VOLUP_BTN: | |
sendSamsung(0xE0E0E01F, 32); // volume + | |
break; | |
case VOLDOWN_BTN: | |
sendSamsung(0xE0E0D02F, 32); // volume - | |
break; | |
case TUNEUP_BTN: | |
sendSamsung(0xE0E048B7, 32); // channel + | |
break; | |
case TUNEDOWN_BTN: | |
sendSamsung(0xE0E008F7, 32); // channel - | |
break; | |
#endif | |
} | |
} | |
int main(void) | |
{ | |
// analog comparator off | |
ACSR &= ~_BV(ACD); | |
DIDR |= _BV(AIN1D) | _BV(AIN0D); | |
// initially all input pins with pull-up's | |
DDRA = DDRB = DDRD = 0; | |
PORTA = PORTB = PORTD = 0xFF; | |
IRLED_ENABLE(); | |
set_sleep_mode(SLEEP_MODE_PWR_DOWN); | |
while(1) { | |
enterSleep(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment