SparkFun Forums 

Where electronics enthusiasts find answers.

Your source for all things Atmel.
By kitsu.eb
#116489
I rigged up a couple of attiny85s with a ir diode and this ir receiver:
http://www.sparkfun.com/products/10266

Surprisingly both my transmitter and receiver code worked on my first try!

Transmitter:
Code: Select all
// Test transmitter, 38khz modulation, 100ms on, 100ms off
#include <avr/io.h>
#include <util/delay.h>

// width of up and down pulse in ms
#define pulse_width 100
#define FCPU 8000000
#define FMOD 38000
// output pin is PB4, OC1B

void setup_timer(void) {
    // Using 8bit timer 1, OCR1B
    // CTC1 clears timer on match, CS10 sets clock to FCPU
    TCCR1 |= (1 << CTC1) | (1 << CS10);
    // Set compare registers
    OCR1C = 1 + (FCPU/FMOD); // 211, triggers CTC
    OCR1B = FCPU/FMOD; // 210, trigger OC1B match
    // COM1B1 = 0 & COM1B0 = 1 toggles OC1B on match
    GTCCR |= (1 << COM1B0);
    // Enable timer/counter 1
    PLLCSR |= (1 << PLLE);
}

int main(void) {
    setup_timer();
    PORTB |= (1 << PB4); // debugging
    for (;;) {
        // Wait pulse_width
        _delay_ms(pulse_width);
        // Toggle pin output enable
        DDRB ^= (1 << PB4);
    }
}
Receiver:
Code: Select all
// Test receiver, toggle lights on high and low pulse
#include <avr/io.h>
#include <util/delay.h>

// PB0 = sensor input
// PB3 = green led
// PB4 = red led

int main(void) {
    // Digital direction out, out, in
    DDRB = (1 << PB4) | (1 << PB3) | ~(1 << PB0);
    // Enable pull-up on sensor port
    PORTB = (1 << PB0);
    for (;;) {
        if (PINB & (1 << PB0)) { // Red on, green off
            // If pin is high then there is no signal
            PORTB |= (1 << PB4);
            PORTB &= ~(1 << PB3);
        } else { // Green on, red off
            // If pin is low then there is a signal
            PORTB |= (1 << PB3);
            PORTB &= ~(1 << PB4);
        }
        _delay_ms(5);
    }
}
Of course for a proper receiver you would probably setup an interrupt to watch for a start bit and set a variable to tell the mainloop to stop and receive instructions.

A proper transmitter is trickier. I guess you need to setup some kind of timing scheme, and to use short vs. long pulses to signal 0/1? For my application I only need 4 bits of data intermittently to signal mode changes based on button presses. Signaling a held button without a full transmission would be cool too. Maybe something like a double long pulse?

I'm sure there is a better way to setup timers/PWM to produce 38kHz, but there are so many ways to setup the timers on these things... Any suggestions are welcome.
By stevech
#117821
on AVRfreaks.com, project section, there are several IR transmit/receive projects.
One is called TWIRP (two-way IR processor). It sends IR by setting the AVR chip's timer to half the period of 38KHz and in a mode so that each time the timer overflows, it toggles an output pin of the AVR. Thus, the CPU does not generate the 38KHz; it's done in the timer.
The CPU turns the timer off and on to generate 1's and 0's in the serial data. The period of a bit is given by whatever remote system you're emulating. the RC5 standard is commonly used.

On receive, the CPU simply uses interrupts or polling to collect transitions of the data line from the IR receiver. Time-tag each transition using a timer accurate to about 10 microseconds. After no-data for x amount of time, the time tagged bit transitions can be decoded according to what modulation method the sending unit used, e.g., RC5.