Skip to content

Instantly share code, notes, and snippets.

@julznc
Created May 6, 2017 13:26
Show Gist options
  • Save julznc/2d750d4441182144db46685137e269af to your computer and use it in GitHub Desktop.
Save julznc/2d750d4441182144db46685137e269af to your computer and use it in GitHub Desktop.
ATtiny2313 Infrared Sender (avr-gcc)
/*
* 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