fast PWM low main app

Hi everybody;

i am willing to create ir remote controller for my robot.
For that i have to create about 39.2khz for carrier.
it is not a problem but when i do something in main it wont work properly.

for exp:

#include <avr/io.h>
#include <avr/interrupt.h>

const int ledPin = 13;
const int ocr2aval = 25;

// The following are scaled for convenient printing
//
// Interrupt interval in microseconds

int stop[]={0,0,1,1 ,0,0,1,1 ,1,0,1,0, 1,0,1,0};
int i=0;
void setup()
{
pinMode(ledPin, OUTPUT);
pinMode(22, OUTPUT);
Serial.begin(9600);

cli();

TCCR2A = (1 << WGM21);

TCCR2B = (1 << CS21);

TIMSK2 = (1 << OCIE2A);

OCR2A = ocr2aval;

sei();

}

void loop()
{
for(i=0;i<16;i++)
{ if(stop*) func_1();*

  • else func_0();*
  • }*

*delay(100); *

}
// ISR For Timer 2 Compare-match overflow
volatile unsigned char value = 0;
ISR(TIMER2_COMPA_vect)
{

  • digitalWrite(ledPin, (++value)&1);*
    }

void func_1()
{digitalWrite(22,HIGH);
delayMicroseconds(3332);
digitalWrite(22,LOW);
delayMicroseconds(833);
}
void func_0()
{digitalWrite(22,HIGH);
delayMicroseconds(833);
digitalWrite(22,LOW);
delayMicroseconds(833);
}
when i measure pin 22 i observe not 833microsec. delays ,but around 15ms delays?
i tried it without pwm signal it worked well.
How can i avoid this time mismatching?
Thanks :slight_smile:

Does func_1() and func_0() have the correct timing if you dont fool with Timer 2 or ISR?

Yes it does:) i tried to run main app. Without using timers it works with no issue.

any idea?

Anything here help...
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1289879390

For small carrier periods (approaching something like 20 microseconds) you can't reliably use that interrupt-driven output to be able to generate and modulate your carrier. The program spends too much time in the interrupt routine (with interrupts disabled) so the other timing is screwed up. I mean, you could use direct manipulation of the output port bit to save a little time, but it's still not practical (in my opinion).

So: Since you are using Arduino Pin 9 for your output, consider the following: Pin 9 can be connected directly to the the OCR1A output pin, so use Timer1, not Timer2.

Maybe something like the following:

#include <avr/io.h>

// Since you are using Arduino pin 9 as an output pin, why not use Timer1 since OC1A
// is connected to pin 9 and the timer circuit can manipulate it directly (no
// interupt routine required)
//
//  davekw7x

void setup()
{
    unsigned long hz = 39200L; // Carrier frequency
    pinMode(9, OUTPUT);        // The OC1A pin will have LED output signal

    cli(); // I like to disable interrupts while setting up timer stuff
    
    //WGM13:0 = 1010 for Phase-correct PWM with ICR1 as top
    //CS12:0  = 001 for no prescaling
    TCCR1A = _BV(WGM11);
    TCCR1B = _BV(WGM13) | _BV(CS10);

    //
    // IRC1 determines the frequency, OCR1A determines the duty cycle of the carrier
    //
    ICR1 = F_CPU / 2 / hz - 1;
    OCR1A = ICR1 / 3; // 33% duty cycle. If you want a 50% duty cycle, change it to ICR1 / 2

    TIMSK2 = 0; // Disable Timer2 Interrupt (We won't be using it to transmit.)
    
    sei();
}

byte msg[16] = {0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0};

void loop()
{
    
    for(int i = 0; i < 16; i++) 
    { 
        if(msg[i]) {
            sendMark();
        }
        else {
           sendSpace();
        }
    }
    delay(1000);  // Give it enough delay so that you can see the stuff on a scope.

}


void sendMark()
{
    TCCR1A |= _BV(COM1A1);    // Enable pin 9 PWM output
    delayMicroseconds(3332);
    TCCR1A &= ~(_BV(COM1A1)); // Disable pin 9 PWM output
    delayMicroseconds(833);
}

void sendSpace()
{
    TCCR1A |= _BV(COM1A1);    // Enable pin 9 PWM output
    delayMicroseconds(833);
    TCCR1A &= ~(_BV(COM1A1)); // Disable pin 9 PWM output
    delayMicroseconds(833);
}

Note that you don't have to start and stop the timer; you just control whether pin 9 is connected to OCR1A or not. You can also see that the carrier is (automatically) turned off between messages. Note that, in the "Real World", you will probably need a certain amount of carrier presence before you send the first message (due to the way that most IR Remote receivers work---check the data sheet of your device). Anyhow, maybe this is a start???

If you just want to observe (measure) the carrier with no modulation, then you can use the following loop:

void loop()
{
    TCCR1A |= _BV(COM1A1);
    while (1)
        ;
}

Or some such thing.

Regards,

Dave

thanks for great explanation.but i have about 255 command with arrays :slight_smile: so i used externat 555 timer chip for carrier frequency.it works so i am happy with it.

you will probably need a certain amount of carrier presence before you send the first message

yes you were right.this array written for receiver not transmitter.i toggle it before start.

Again thanks i appriciate your helps :slight_smile: