Hi y'all -
I'm working on a project using Adafruit Floras to pulse IR LEDs at 38kHZ for IR transmission. The LED pulses will be sensed by IR phototransistors connected to other Arduinos. By varying the length of the IR blasts, I want each LED to send a different signal, so I can trigger various activities on the receiving Arduinos, based on the position/direction of the person wearing the Flora(s).
The main problem I'm having is generating a reliable 38kHz carrier wave on the IR LED. Right now I'm using code based on delayMicroseconds() in order to guesstimate the 26.32 microseconds needed for a full cycle at 38kHz.
Here's that code:
while (microsecs > 0) {
// 38 kHz is about 13 microseconds high and 13 microseconds low
digitalWrite(IRledPin, HIGH); // this takes about ? microseconds to happen
delayMicroseconds(4); // hang out for some microseconds, change this if not working
digitalWrite(IRledPin, LOW);
delayMicroseconds(4); // hang out for some more microseconds
// so 26 microseconds altogether
microsecs -= 26;
}
That code works! But I think it would work better if I were using interrupts to get really accurate timing.
I've done some research, but am running into trouble since the Flora uses the ATMega32u4 and runs at 8MHz and has a somewhat confusing (to me!) pinout. I'm new to Arduino (and electronics) and C / AVR programming is quite a bit over my head still.
Here's my paltry attempt at a sketch using interrupts - it doesn't seem to do anything with the IR led, however and I'm not sure why.
#define CODE 2000 //length of "mark" in usecs (1 cycle of IR mark @ 38khz == 26.32 usecs // CODE x 0.038 = # of cycles)
int irLedPin = 3; //IR on Pin 3
float codeCyclesFloat = 0; //exact # of cycles for each burst
unsigned int codeCyclesInt = 0; //approx. # of cycles for each burst (for faster math)
//storage variables
boolean irLedBurst = 0; //toggles between IR "bursts" and "breaks"
volatile boolean toggleIR = 1; //toggles HIGH/LOW @ 38kHz IR pulse
volatile int irBurstTimer = 0;//counts the IR pulses (irBurstTimer x 2 == # of full HIGH/LOW cycles) (irBurstTimer x 13.16 == # of microseconds)
void setup(){
pinMode(irLedPin, OUTPUT);
cli();
//set timer1 (16-bit) interrupt at 76000 Hz (i.e. 38kHz x 2 for full wave)
TCCR1A = 0;// set entire TCCR1A register to 0
TCCR1B = 0;// same for TCCR1B
TCNT1 = 0;//initialize counter value to 0
// set compare match register for 38khz increments
OCR1A = 104;// = ((8*10^6) / (76000*1)) - 1 [must be <65536] ... that is: (8MHz / (76Khz*prescaler) - 1 [count begins with 0]
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS10 bit for no prescaler
TCCR1B |= (1 << CS10);
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
sei();
//figure out # of cycles from CODE
codeCyclesFloat = (float)CODE / 26.32; //derive # of cycles per burst from CODE
Serial.print("codeCyclesFloat = ");
Serial.print(codeCyclesFloat, 10);
Serial.print("\n\r");
codeCyclesInt = (int)codeCyclesFloat;
Serial.print("codeCyclesInt = ");
Serial.print(codeCyclesInt, DEC);
Serial.print("\n\r");
}
void loop(){
//program here
Serial.print("Sending 10 bursts of IR code: ");
Serial.print(CODE);
for (int i=0;i<10;i++){
//send burst of CODE usecs, and delay appropriately after each burst
//burst:
burstIR(codeCyclesInt);
//delay:
if (CODE < 1780) {
//delay for >= 10 cycles, per Vishay TSOP 38338 datasheet
delayMicroseconds(300);
} else {
//delay for 7x CODE, per datasheet
delayMicroseconds(7 * CODE);
}
}
}
void burstIR(int burstLength) {
// we'll count until we reach the number of cycles we are told to burst for (burstLength)
//turn on IR LED pulse (in ISR)
irLedBurst = true;
while (irBurstTimer < (burstLength / 2)) {
//burst // irBurstTimer is incremented in half-cycles
}
//turn off IR LED pulse (in ISR)
irLedBurst = false;
//make sure IR LED is off
digitalWrite(irLedPin, LOW);
}
ISR(TIMER1_COMPA_vect) {
//timer1 interrupt @ 76kHz toggles pin 2 (irLedPin) if irLedBurst boolean is true
//generates pulse wave of frequency 76kHz/2 = 38kHz (takes two cycles for full wave - toggle high then toggle low)
//also increments irBurstTimer variable
//FIND OUT HOW TO HARDWARE TOGGLE PIN 3 ON FLORA... Arduino Forum
//Simply Toggle Pin rather than Digital Write
if (irLedBurst){
//if there should be an IR pulse, cycle IR
digitalWrite(irLedPin, toggleIR);
toggleIR = !toggleIR;
}
irBurstTimer++;
//increment the timer (counts half-cycles == +13.16us)
}
I would like to change this so that the ISR toggles the IR LED pin directly rather than using digitalWrite (actually the pin is connected to a transistor hooked into Vbatt to power the LED with a lot of amperage). I also need to count a certain number of microseconds or cycles in order to figure out how long to send the IR blasts so that different LEDs are identifiable. I'm not sure if incrementing a counter in the ISR is the best way to do that.
Any ideas on what I might be doing wrong? The LED doesn't seem to light up at all. Any advice or resources on interrupts would be welcome to. I've tried to do my homework but at this point things are over my head.
Thanks!