SparkFun Forums 

Where electronics enthusiasts find answers.

Your source for all things Atmel.
By keen101
#58714
Hi, I'd like to attempt a project involving an AVR as the microprocessor, and to add some code to turn it into learning IR remote receiver. It should be noted that i am still relatively new at this kind of thing, and i have almost no programming knowledge at all. I have made a few simple AVR projects, but those were with code that was provided. I have an arduino, and a bunch of Mega8's handy.

basically i want to clone this device:

http://www.tauntek.com/tinyir2-learning ... ceiver.htm

I have some sample AVR based IR recording code, but i don't know that much about programing to modify it to what i need. Ideally it would be nice if someone could help me translate the c code into arduino code.

here are two sample codes that might be useful...
Code: Select all
/pin connected to TSOP1736

#define K1 (1<

uint8_t impulse_prev = 0;

uint8_t counter_impulse_1 = 0;

uint8_t flag_rx = 0;

uint8_t counter_impulse_0 = 0;

uint8_t impulse = 0;

uint64_t counter_ik = 0;

uint64_t code = 0;

ISR(TIMER0_OVF_vect)

{

uint8_t c;

uint8_t str[35];

uint64_t i;

//Timer0 initialization

TCNT0=0xFF;

//Invert input signal

if (K1==1) impulse=0; else impulse=1;

if ((impulse_prev==0)&&(impulse==1))

{//rising edge detection

//reset counter

counter_impulse_1=0;

if ((counter_impulse_0>3)&&(flag_rx==1)&&(counter_impulse_0<23))

{//if receiving symbols

if(counter_impulse_0>12)

//logical 1 received

code |=(1<

counter_ik++;

};

};

if((impulse==1)&&(counter_impulse_1<50))

//counting positive pulses

counter_impulse_1++;

if((impulse_prev==1)&&(impulse==0))

{//negative front

counter_impulse_0=0;

if(counter_impulse_1>30)

{//one long synchro pulse

code=0;

counter_ik=0;

flag_rx=1;

}

};

if((impulse==0)&&(flag_rx==1)&(counter_impulse_1<150))

//counting negative pulses

counter_impulse_0++;

if((counter_impulse_0>50)&&(flag_rx==1)&&(impulse==0))

{//end of receive

flag_rx=0;

counter_impulse_0=0;

counter_impulse_1=0;

counter_ik=0;

code=0;

};

impulse_prev=impulse;

}
Code: Select all
#include <avr/io.h>
#include <avr/interrupt.h>
#include "uart.h"

/* constants */
#define MAX 160

/* global variables */

/* allocate 160*2 = 320 byte memory for storing a code,
 * this means we can store 80 on/off sequence timings */
volatile uint16_t code[MAX];
/* current index in code[] (default: 0) */
volatile uint8_t pos = 0;
/* current pin state (default: high == idle) */
volatile uint8_t state = 1;
/* signal for the main application that a code has been received
 * (default: 0) */
volatile uint8_t done = 0;
/* signal button presses from interrupt to main */
volatile uint8_t button_press;
/* current system mode */
enum {
    MODE_OFF = 0,
    MODE_DISPLAY = 1,
} mode = MODE_DISPLAY;
/* current viewmode */
enum {
    VIEW_VALUE_AND_TIME = 0,
    VIEW_VALUE = 1,
    VIEW_TIME = 2,
} view = VIEW_VALUE_AND_TIME;

/* call every 10 ms, for buttons at pins PC0-PC3 */
static uint8_t button_sample(void)
{
    static uint8_t btn_state = 0b1111;       /* initialize state, buttons are active low! */
    static uint8_t last_sample = 0b1111; /* initialize old sample */
    uint8_t new_sample = PINC & 0b1111;  /* read inputs */

    /* mark bits which are sampled with the same value */
    uint8_t same_sample = (last_sample ^ ~new_sample);
    /* all bits set in same_sample now have been sampled with the same value at
     * least two times, which means the button has settled */

    /* compare the current button state with the most recent sampled value,
     * but only for those bits which have stayed the same */
    uint8_t state_different = btn_state ^ (new_sample & same_sample);
    /* all bits set in state_different have been sampled at least two times
     * with the same value, and this value is different from the current button state */

    /* if a bit is set in state (means: button is not pressed) AND bit is set
     * in state_different (means: input has settled and value is different from state)
     * together means: button has been pressed recently */
    uint8_t btn_press = btn_state & state_different;

    /* toggle all bits for inputs which switched state */
    btn_state ^= state_different;

    /* store current sample for next time */
    last_sample = new_sample;

    /* if bit is set in btn_press, a button has been pressed (not released yet) */
    return btn_press;
}


/* pin change interrupt 1 service function */
ISR(PCINT1_vect)
{
    /* do nothing if we are just processing a code in the main loop,
     * or no more space is available for a timer value */
    if (done || pos == MAX)
        return;

    /* if this would be the first timing value ever recorded, and the
     * state before was high (=idle), do not record the timing value
     * and just reset the timer */
    if (state && pos == 0) {
        TCNT1 = 0;
    /* else record the timing value */
    } else {
        /* store current timer value in code[]
         * and reset the timer */
        code[pos++] = TCNT1;
        TCNT1 = 0;
    }

    /* toggle second led */
    PORTD ^= _BV(PD3);

    /* toggle state */
    state = !state;
}

/* timer 1 compare A interrupt service function */
ISR(TIMER1_COMPA_vect)
{
    /* do nothing if we are just processing a code in the main loop */
    if (done)
        return;

    /* if some code has been received */
    if (pos > 0) {
        /* if pos is odd, one last 'off'-timing is missing, fill with zero */
        if (pos % 2 == 1)
            code[pos++] = 0;

        /* signal main */
        done = 1;

        /* turn on third led */
        PORTD |= _BV(PD6);
    }
}

/* timer 2 compare A interrupt service function */
ISR(TIMER2_COMPA_vect)
{
    /* sample buttons every 10ms */
    button_press |= button_sample();
}

int main(void)
{
    /* initialize uart */
    uart_init();
    uart_printf("rumpus ir analyzer\n");

    /* configure led pins as outputs and turn leds off */
    DDRC |= _BV(PC4);
    DDRD |= _BV(PD3) | _BV(PD6) | _BV(PD7);
    PORTC &= ~_BV(PC4);
    PORTD &= ~(_BV(PD3) | _BV(PD6) | _BV(PD7));

    /* configure ir input pin, with pullup */
    DDRC &= ~_BV(PC3);
    PORTC |= _BV(PC3);

    /* configure button input pins, with pullup */
    DDRC &= ~(_BV(PC0) | _BV(PC1) | _BV(PC2) | _BV(PC3));
    PORTC |= _BV(PC0) | _BV(PC1) | _BV(PC2) | _BV(PC3);

    /* wait until pin is high (no ir carrier is detected) */
    while(!(PINC & _BV(PC3)));

    /* enable pin change interrupt 1 for ir input pin (PC3/PCINT11) */
    PCMSK1 |= _BV(PCINT11);
    PCICR |= _BV(PCIE1);

    /* configure timer1 with prescaler 64 and CTC for measuring ir timings */
    TCCR1B = _BV(CS11) | _BV(CS10) | _BV(WGM12);
    /* configure timer action after 200ms: 20mhz/64/5 */
    OCR1A = F_CPU/5/64;
    /* enable OCR1A interrupt */
    TIMSK1 = _BV(OCIE1A);

    /* configure timer 2 with prescaler 1024 and CTC
     * for button sampling */
    TCCR2A = _BV(WGM21);
    TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20);
    /* configure compare event a to occur after 10ms and enable interrupt */
    OCR2A = F_CPU/1024/100;
    TIMSK2 = _BV(OCIE2A);

    /* signal user availability by turning on led 1 */
    PORTC |= _BV(PC4);

    /* enable interrupts */
    sei();

    /* signal the user that the analyzer part has started by turning led 1 on */
    PORTC |= _BV(PC3);

    while(1) {
        /* if a code has been received */
        if (mode == MODE_DISPLAY && done) {

            /* print code to serial uart */
            uart_printf("complete code received, %u on-off-timings:\n", pos/2);
            for (uint8_t i = 0; i < pos; i += 2) {

                if (view == VIEW_VALUE_AND_TIME) {
                    uint32_t on, off;

                    /* compute timing in microseconds */
                    on = ((uint32_t)code[i]) * 64 / 20;
                    off = ((uint32_t)code[i+1]) * 64 / 20;

                    uart_printf("  %5lu us (%5u) on, %5lu us (%5u) off\n",
                            on, code[i],
                            off, code[i+1]);
                } else if (view == VIEW_VALUE) {
                    uart_printf("  %5u on, %5u off\n",
                            code[i], code[i+1]);
                } else if (view == VIEW_TIME) {
                    uint32_t on, off;

                    /* compute timing in microseconds */
                    on = ((uint32_t)code[i]) * 64 / 20;
                    off = ((uint32_t)code[i+1]) * 64 / 20;

                    uart_printf("  %5lu us on, %5lu us off\n",
                            on, off);
                }
            }


            /* turn off second and third led */
            PORTD &= ~(_BV(PD3) | _BV(PD6));

            /* wait until pin is high (no ir carrier is detected) */
            while(!(PINC & _BV(PC3)));

            /* reset all global variables */
            pos = 0;
            state = 1;
            done = 0;
        }

        if (button_press) {
            /* first button toggles system mode */
            if (button_press & 0b1) {
                mode++;
                if (mode > MODE_DISPLAY)
                    mode = MODE_OFF;

                if (mode == MODE_OFF) {
                    uart_printf("ir analyzer switched off\n");

                    /* disable timer1 and pin change interrupts */
                    TIMSK1 &= ~_BV(OCIE1A);
                    PCMSK1 &= ~_BV(PCINT11);

                    /* turn off led1 */
                    PORTC &= ~_BV(PC4);

                } else if (mode == MODE_DISPLAY) {
                    uart_printf("scan and display codes\n");

                    /* clear interrupt flags, enable timer1 and pin change interrupts */
                    TIFR1 = _BV(OCIE1A);
                    TIMSK1 |= _BV(OCIE1A);
                    PCMSK1 |= _BV(PCINT11);

                    /* turn on led1 */
                    PORTC |= _BV(PC4);
                }
            }


            /* second button toggles view mode */
            if (button_press & 0b10) {
                view++;
                if (view > VIEW_TIME)
                    view = VIEW_VALUE_AND_TIME;

                if (view == VIEW_VALUE_AND_TIME)
                    uart_printf("display timer value and time (in us)\n");
                else if (view == VIEW_VALUE)
                    uart_printf("display timer value\n");
                else if (view == VIEW_TIME)
                    uart_printf("display time (in us)\n");
            }

            button_press = 0;
        }
    }
} 

I obtained these codes from here:

http://www.scienceprog.com/ir-remote-co ... ontroller/
http://git.lochraster.org:2080/?p=fd0/rumpus

I also found this arduino code, but it was not very helpful
http://www.arduino.cc/playground/Code/InfraredReceivers


If someone could help me out a little it would be appreciated. I don't expect someone to write all the code for me, nor do i really want that either. I just need a boost to get started.

Thanks,

-Andrew
By keen101
#58769
thanks, that was an interesting link.

However, that's not what i want. I don't want to hook this up to a serial port at all. Instead i want to have the chip remember the codes (at least 4), and after that when one of the 4 codes is sent to the device it sends a 5v pulse to a robot.....

This is the actual device i want to copy....
http://www.usfirst.org/uploadedfiles/co ... e=AndWords


I think what i need is to store 4 different IR variables to 4 different strings?
By Thunderhammer
#58872
You're almost certainly going to need an external EEPROM to store the codes locally. I would also suggest taking a look at the TVBGone, for which the source code and schematic is readily available
http://www.ladyada.net/make/tvbgone/download.html

Basically you probably want to store remote codes in a similar way to how that program stores them - a carrier frequency combined with a number of on/off pulses at that frequency. Then you'll have to write some code that recognizes incoming signals and compares them to previous signals, allowing for a certain tolerance.

There are IR receiver modules that basically filter out the carrier frequency - usually something like 38 KHz, I think - and just give you a number of on/off pulses. It sounds like you just have one remote you want to work with, so this would probalby be the easier choice for your project. They're like $2 or $3 on digikey/mouser.
By stevech
#58892
thanks, that was an interesting link.

However, that's not what i want. I don't want to hook this up to a serial port at all. Instead i want to have the chip remember the codes (at least 4), and after that when one of the 4 codes is sent to the device it sends a 5v pulse to a robot.....

This is the actual device i want to copy....
http://www.usfirst.org/uploadedfiles/co ... e=AndWords


I think what i need is to store 4 different IR variables to 4 different strings?
Take that code for receiving and sending IR, and add your code to store in EEPROM or some such, and omit the PC interface portion.

Or start with one of the other several RC5 and IR projects donated here.


BUT BASED ON THIS " i have almost no programming knowledge at all" then

If you want to be given the exact functionality you wish, then either do a hobby collaboration with someone with the requisite skills, collaborate with fellow students if applicable, or hire the work done.