NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » Infrared Remote control with Nerdkit

July 11, 2010
by Keyster
Keyster's Avatar

ok guys, i have no questions today. i just completed a sample project i have been working on and wanted to post the code here for others to use. i used a simple infrared LED i purchased from Radio Shack (276-143) years ago for another project i was working on. this code only controls the Volume Up on my TV but is the "proof of concept" i was looking for. the code is also overly bloated to make it visually easy to see what is happening at the LED level. in the control string a "1" is used to send an ON burst and a "0" is used to send an OFF burst. here are some links i used for this project:

knowedge base on different protocols

some codes for samsung TV

cool page on how the IR works

i will put the code in the next post.

--Bryan

July 11, 2010
by Keyster
Keyster's Avatar
//
//  Infrared NEC Protocol Transmitter by Bryan Key
// my attempt at the NEC Protocol for IR remote controls
//
// Samsung uses 38kHz carrier wave
//   IR LED is connected at PB1
//   visible LED is connected at PB2 (for visual aid during testing)
//

//  set processor speed
#define F_CPU 14745600

//  set how many pulses are in each burst
//  19->23 Works
#define _BURSTWIDTH 21

#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
//#include <string.h>
#include <inttypes.h>

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"
#include "../libnerdkits/uart.h"

// prescale 8 & 102 counter = 18070.588 Hz
// prescale 8 & 51 counter = 36141.176 Hz   (~36kHz)
// prescale 8 & 48 counter = 38400 Hz       (~38kHz)
// prescale 8 & 25 counter = 73728 Hz  (.01356 ms)
// prescale 8 & 24 counter = 76800 Hz (~38hz * 2) (.01302 ms)
//   i uses 76800 because there is one cycle with LED on and one cycle with the LED off
//   hince making one complete LED cycle at ~38kHz

volatile uint8_t indx = 0;
volatile int8_t toggle = 0, HighLow = 0;
volatile uint16_t BurstWidth;
volatile uint8_t buffer[210];

//
// each interrupt fire is 0.01302ms
//
ISR(TIMER0_COMPA_vect)
{   int8_t data;

    if (toggle)
    {   PORTB |= (HighLow<<PB1);        // if HighLow is 1 then turn on PB1
        PORTB |= (HighLow<<PB2);        // PB2 is a "test" LED (visible light)
    }
    else
    {   PORTB &= ~(1<<PB1);         // turn off PB1
        PORTB &= ~(1<<PB2);         // turn off PB2 (test LED)
        BurstWidth--;               //each burst change is 0.02604ms
    }
    toggle ^= 1;    //toggle the toggle

    if (!BurstWidth)                //if BurstWidth == 0
    {   BurstWidth = _BURSTWIDTH;   // reset BurstWidth counter
        data = '-';
        while (data == '-')         // skip dashes, i put the dashes in for visual aid when creating strings
            data = buffer[indx++];  // grab the next byte in string
        if (data == 0x39)       // look for a "9", 9 is "end-of-string"
        {   indx = 0;           // reset index back to zero
            HighLow = 0;        // turn pulse off
        }
        if (data == 0x38)       // "8" = insert a pause of 46.716ms
        {   HighLow = 0;        //  this is the "filler" at the end of the command to make it 110ms
            BurstWidth = 1794;
        }
        if (data == 0x37)       // "7" = insert a pause of 96.192ms
        {   HighLow = 0;        //  "filler" at the end of a "repeat" command if needed
            BurstWidth = 3694;
        }
        if (data == 0x31)
            HighLow = 1;        // a "1" turns the pulse on
        if (data == 0x30)
            HighLow = 0;        // a "0" turns the pulse off
    }

}

int main()
{
    cli();              //make sure interrups are disabled during setup
    TCCR0A = (1<<WGM01);    //CTC (Clear Timer on Compare Match)
    TCCR0B = (1<<CS01);     // set prescaler to 8
    OCR0A = 23;         //24 is 76800 interrupts per second (38kHz * 2)

    DDRB |= (1<<DDB1) | (1<<DDB2);  // set pin for Output
    TIMSK0 = 2;                 // set the bit mask to enable interrupt - Timer 0 Compare Match A

    toggle = 1;
    HighLow = 1;
    BurstWidth = _BURSTWIDTH;   //set the number of pulses in each burst

    //Samsung 52 inch LCD TV, also works on my 19 inch Samsung
    //  Volume Up 0xE0E0-E01F
    memcpy_P((void*)buffer, PSTR("11111111-00000000--1000-1000-1000-10-10-10-10-10--1000-1000-1000-10-10-10-10-10--1000-1000-1000-10-10-10-10-10--10-10-10-1000-1000-1000-1000-1000--189-------------"),160);
    //  Power 0xE0E0-40BF
    //memcpy_P((void*)buffer, PSTR("11111111-00000000--1000-1000-1000-10-10-10-10-10--1000-1000-1000-10-10-10-10-10--10-1000-10-10-10-10-10-10--1000-10-1000-1000-1000-1000-1000-1000--189--------"),155);

    sei();              //start the interrupts
    while (1)
    {   // just do nothing, let the interrupt do all the work
    }

}

//
// 11111111-00000000 is the AGC pulse (header/Automatic Gain Control)
// 1000 is a "1"
// 10 is a "0"
// 189 is - 1 stop bit (single ON burst) - pause for filler (~46ms) - end string/start over
// keep in mind the "-" in the string is only for visual aid, it has no bearing on the output
// each byte is .54684ms (547 microseconds)
July 12, 2010
by lcruz007
lcruz007's Avatar

What a coincidence. I am working on a 'similar' project as well. I will post my project in the next few weeks :)

Very nice project by the way!! :)

Post a Reply

Please log in to post a reply.

Did you know that the printf format string "%.3f" will show three digits after the decimal point? Learn more...