Go Down

Topic: Generating 38kHz pulse for ir project (Read 1 time) previous topic - next topic

drhoff

I'm trying to work my way step by step through building a remote control for the tv in my dining room. This is the part I'm on now. I have a 328p that I put a bootloader on using this board file:
Code: [Select]

##############################################################
atmega328p8int2_7v.name=Atmega328P 8MHz internal 2.7v
atmega328p8int2_7v.upload.protocol=arduino
atmega328p8int2_7v.upload.maximum_size=30720
atmega328p8int2_7v.upload.speed=9600
atmega328p8int2_7v.bootloader.low_fuses=0xe2
atmega328p8int2_7v.bootloader.high_fuses=0xd8
atmega328p8int2_7v.bootloader.extended_fuses=0x05
atmega328p8int2_7v.bootloader.path=optiboot
atmega328p8int2_7v.bootloader.file=optiboot_atmega328.hex
atmega328p8int2_7v.bootloader.unlock_bits=0x3F
atmega328p8int2_7v.bootloader.lock_bits=0x0F
atmega328p8int2_7v.build.mcu=atmega328p
atmega328p8int2_7v.build.f_cpu=8000000L
atmega328p8int2_7v.build.core=arduino
atmega328p8int2_7v.build.variant=standard

So, my first question is about these fuse settings. They seem to be working, but is there anything weird about them that could cause trouble?

Next topic... Here is my program's code so far (comments explain what I think it should be doing):
Code: [Select]
#include <avr/io.h>

int Timer2APin = 11; // OC2A PIN = PORT B PIN 3 = ATMEGA328 PIN 17 = ARDUINO PIN 11

void setup(){
  pinMode(Timer2APin, INPUT); // SETS DATA DIRECTION REGISTER
  // OUTPUT WILL NOT SHOW UP WHILE SET TO INPUT
  // OUTPUT WILL SHOW UP WHILE SET TO OUTPUT

  TCNT2 = 0; // RESET COUNTER2 VALUE
  OCR2A = 104; // SET TOP COUNTER2 VALUE (FOR CTC)
  // formula from datasheet for ctc
  //                f_clk_io
  // f_OC2A = ---------------------------
  //           2 * prescale * (1 + OCR2A)
 
  //               8000000
  // f_OC2A = ------------------- = 38095.2381 Hz
  //           2 * 1 * (1 + 104)

  // SET VALUE OF TCCR2A
  // (0 << COM2A1) | (1 << COM2A0)             TOGGLE OC2A PIN ON COMPARE MATCH
  // (0 << COM2B1) | (0 << COM2B0)             OC2B PIN DISCONNECTED
  // (1 << WGM21) | (0 << WGM20)               CTC MODE - WGM22 IN TCCR2B MUST ALSO BE 0
  TCCR2A = ((0 << COM2A1) | (1 << COM2A0) | (0 << COM2B1) | (0 << COM2B0) | (1 << WGM21) | (0 << WGM20));
  // SET VALUE OF TCCR2B
  // (0 << FOC2A) | (0 << FOC2B)               FORCE OUT COMPARE A AND B OFF
  // (0 << WGM22)                              CTC MODE - WGM21 AND WGM20 IN TCCR2A MUST ALSO BE 1 AND 0 RESPECTIVELY
  // (0 << CS22) | (0 << CS21) | (1 << CS20)   CLOCK SELECT - NO PRESCALAR
  TCCR2B = ((0 << FOC2A) | (0 << FOC2B) | (0 << WGM22) | (0 << CS22) | (0 << CS21) | (1 << CS20));
}

void loop(){
  pinMode(Timer2APin, OUTPUT); //let the timer pin toggle for 5 seconds
  delay(5000);
  pinMode(Timer2APin, INPUT); //stop it for 5 seconds
  delay(5000); 
}

So, it would seem that one or more of the things above are not working as expected. Circuit picture is in attachment. This is the receiver I'm using:
http://www.mouser.com/ProductDetail/Vishay-Semiconductors/TSOP38338SS1V/?qs=sGAEpiMZZMsj2w6QBC0lciAHmYLQvta4
I was expecting to see the led hooked up to the detector alternate between on and off for 5 seconds at a time. Instead it is almost always on dimly, and it sort of flickers every once in a while. I hooked up another arduino as a logic analyzer and got what looked like erratically spaced pulses of varying lengths. Any ideas what is wrong with my code?

drhoff

Also, I know people have libraries to do this already, but I want to understand what I'm doing. I think I'll learn more and understand better by writing my own code and asking questions.

PeterH

Have you tried a simple sketch that doesn't have all that timer manipulation in, that just toggles an output pin at regular intervals so you can confirm the program has loaded, booted and is running?
I only provide help via the forum - please do not contact me for private consultancy.

drhoff

After putting the bootloader on it, I uploaded the blink example to make sure the clock was working right and it was running at the right speed. The blinking speed was right, and everything seemed ok. Is that what you meant?

drhoff

Also, using a camera, I can see that the ir led is lighting up at least somewhat for 5 seconds and then off for 5 seconds.

PeterH

Looks like it's running, then.

What's supposed to happen when you run this sketch?
I only provide help via the forum - please do not contact me for private consultancy.

Nick Gammon

You need to set the counter after starting the timer. This works:

Code: [Select]

const int Timer2APin = 11; // OC2A PIN = PORT B PIN 3 = ATMEGA328 PIN 17 = ARDUINO PIN 11

void setup(){
 TCCR2A = (0 << COM2A1) | (1 << COM2A0)  | (1 << WGM21);
 TCCR2B =  (1 << CS20);
 OCR2A = 104; // SET TOP COUNTER2 VALUE (FOR CTC)
}

void loop(){
 pinMode(Timer2APin, OUTPUT); //let the timer pin toggle for 100 mS
 delay(100);
 pinMode(Timer2APin, INPUT); //stop it for 100 mS
 delay(100);  
}
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Nick Gammon

Actually this works too:

Code: [Select]

const int Timer2APin = 11; // OC2A PIN = PORT B PIN 3 = ATMEGA328 PIN 17 = ARDUINO PIN 11

void setup(){
  TCCR2A = (0 << COM2A1) | (1 << COM2A0)  | (1 << WGM21);
  OCR2A = 104; // SET TOP COUNTER2 VALUE (FOR CTC)
  TCCR2B =  (1 << CS20);
}

void loop(){
  pinMode(Timer2APin, OUTPUT); //let the timer pin toggle for 100 mS
  delay(100);
  pinMode(Timer2APin, INPUT); //stop it for 100 mS
  delay(100); 
}


So more precisely, you need to set the counter after setting the mode.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Nick Gammon

I can't really see in the datasheet where it warns you about this, except for this sentence on page 155:

Quote
When writing to one of the registers TCNT2, OCR2x, or TCCR2x, the value is transferred to a temporary register, and latched after two positive edges on TOSC1. The user should not write a new value before the contents of the temporary register have been transferred to its destination.


This was under the heading "Asynchronous Operation of Timer/Counter2" which doesn't seem to apply. However you might say that until we have established a timer mode, perhaps changing OCR2x goes into the temporary register, and is not latched because the timer is not running. However that's just a guess.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

dhenry

Code: [Select]
  OCR2A = 104; // SET TOP COUNTER2 VALUE (FOR CTC)

I would change that slightly, to make it more portable:

Code: [Select]

#define F_IR 38000ul //IR frequency, in hz

  OCR2A = F_CPU / F_IR / 2 - 1 /*104*/; // SET TOP COUNTER2 VALUE (FOR CTC) - assuming prescaler 1:1


No need to calculate that manually.

drhoff

Awesome! Thanks! I figured it was something sneaky like that.

drhoff

So just to make sure I understand what I'm reading / doing here, the #define part is there for the compiler, right? An you would do that instead of making a variable because you don't actually need the arduino to know what the number is, so you save some space by having the compiler replace it before uploading?

Nick Gammon

He could just as easily have said:

Code: [Select]
const unsigned long F_IR = 38000UL; //IR frequency, in hz

That also wouldn't take any extra space.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Go Up