Saturday, May 6, 2017

ATtiny IR Remote

ATtiny2313 Infrared Sender

parts:
  • ATtiny2313 @4MHz (internal oscillator)
  • IR LED (series with 220-ohm resistor)
  • Tact switches
  • 3.7V lithium ion battery & Capacitor




avr-gcc (main.c) code:
/*
* 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();
}
}


References:
ESP8266 IR Remote
z3t0/Arduino-IRremote
ATtiny Low Power

5 comments:

  1. Thanks for great resource, i will try this solution.

    Internet of Things Solutions

    ReplyDelete
  2. Thanks for great code! Uploaded with arduino IDE succesfully! How to make vol up, down codes sending every few miliseconds if button is pushed down? I have motorized alps potentiometer and if receive code it moves only short time programmed into receiver code. Daniel

    ReplyDelete
  3. what an incredible achievement, I pray that you'll keep advance and achieve higher milestone!

    cara beli barang dari china
    beli tanah

    ReplyDelete
  4. "Very great post. Thanks for sharing this post.
    Great post on the latest in Set Top Box DTH Remote technology! For anyone looking to enhance their home entertainment system, Tomson Electronics offers a range of high-quality remotes and electronic components. Their collection includes everything from durable remotes to essential components that ensure optimal performance of your Set Top Box. If you're interested in upgrading or finding reliable accessories, be sure to check out Tomson Electronics for top-notch products and service!"

    ReplyDelete