Society of Robots - Robot Forum
Software => Software => Topic started by: tristantech on January 30, 2009, 05:11:40 PM
-
I'm stumped on a problem I've been working weeks on. I want to use the ATmega 88's 8-bit timer0 to generate a 38khz wave for an ir light gate. I want to do this completely in hardware without interrupts because my chip is running at only 1 Mhz. I'm using the code below:
TCCR0A |= (1 << WGM01); // Configure timer 0 for CTC mode
TCCR0A |= (1 << COM0B0); // Enable timer 0 Compare Output channel B in toggle mode
OCR0B = 13; //Toggle the output every 13 uS
TCCR0B |= (1 << CS00); // Start timer w/o presaler
When I program the chip and turn it on, my oscilloscope show no waveform on the pin. I have all the outputs and inputs correctly configured.
What's wrong with the code? ??? ???
-
Maybe you have done it and not mentioned it here. Have you changed the mode of the respective pin as output pin?
-
Ok... This is how it should look
TCCR0A =&B01000010
TCCR0B =&B00000001
Then you should be fine...
I set prescaler to 1...
With a prescaler at 8 you get no good resolutions...
Cheers, mate
-
I'm using Channel B, not A
You set the Channel A pin to toggle, but I am using the Channel B pin. So you actually need to set bit 4 in TCCR0A (COM0B0)
-
Ok then... It's
TCCR0A =&B00010010
TCCR0B =&B00000001
That isn't working too???
That's set on B channel toggle mod....
-
No that doesn't work.
The output is set right, my scope is hooked up right to the avr's OC0B pin.
-
Check out the source code for ladyada's tv-b-gone...It runs at 8MHz and has code to generate IR diode pulses for tv's which is around 38Khz
#define freq_to_timerval(x) ((F_CPU / x - 1 )/ 2)
// Code 000 -- Sony, Baur, Neckermann, Otto Versand, Palladium, Quelle, SEI, Sinudyne, Sonolor, Universum
const struct powercode sonyCode PROGMEM = {
freq_to_timerval(37470), // 37.47 KHz
{{245, 60},
{123, 60},
{61 , 60},
.....
-
That looks like it may work. I downloaded the source code of one of the many TV-B-Gone kits on the web.
-
I looked through the source code but couldn't find anything about 38kHz.
-
I think it is simply inserting a delay to create a pulse at the appropriate frequency. The first number in the struct is the amount of time it is on, the second it the amount of time it is off.
-
I know it doesn't cover the ATMMega88 specifically but it may still be worth checking http://www.societyofrobots.com/member_tutorials/node/233 (http://www.societyofrobots.com/member_tutorials/node/233)
-
Can anyone just give me some source code?
-
The ATMega88 is similar to ATMega168 (with different memory sizes). So looking at the sheet of the 168 from the link I gave you http://www.societyofrobots.com/member_tutorials/files/ATMega168.pdf (http://www.societyofrobots.com/member_tutorials/files/ATMega168.pdf)
Assumptions: you said your processor is running at 1Mhz and you MUST use Timer0
Here's the formula from my tutorial:-
Output_PWM_Frequency = Clock_Speed / (Prescaler * (1 + TOP))
Where:
Output_PWM_Frequency = 38kHz = 38,000
Clock_Speed = 1Mhz = 1,000,000
As per my sheet then, for Timer0, the value of TOP is fixed at 255.
So we can re-write the formula as:
38,000 = 1,000,000 / (Prescaler * (1+255))
38,000 = 1,000,000 / (Prescaler * 256)
38,000*256 = 1,000,000 / Prescaler
Prescaler = 1,000,000 / (38,000 * 256)
Prescaler = 1,000,000/9,728,000
Prescaler = (approx) 0.1
So you can't do it!!! The minimum for the prescaler is 1
If we use a 16 bit timer like Timer 1 then we have more control over the value of TOP:
TOP = (Clock_Speed / (Prescaler * Output_PWM_Frequency)) - 1
TOP=(1,000,000 / (Prescaler * 38,000))-1
Assuming Prescaler=1 then
TOP=(1,000,000/38,000)-1 = 26 -1 = 25 // NB This is approximate
Since TOP isn't one of the fixed values: 255, 511, 1023 then we need a mode that sets TOP using ICR1 - so lets choose 16 bit fast pwm.
Here is some untested code:-
// Set Timer1 to 16 bit fast PWM using ICR1 (NB this code could be made smaller):-
TCCR1B &= ~( (1<<CS12) | (1<<CS11) | (1<<CS10)); // disable PWM
TCCR1B |= (1<<WGM13);
TCCR1B |= (1<<WGM12);
TCCR1A |= (1<<WGM11);
TCCR1A &= ~(1<<WGM10);
// Set up the prescaler to clock div 1 (assuming 1MHz)
TCCR1B |= (1<<CS10);
// Set the value of TOP
ICR1 = 25;
You can now get the output on either OC1A and/or OC1B
To output on OC1A:
TCCR1A |= (1<<COM1A1) | (1<<COM1A0);
OCR1A = (ICR1>>1); // 50% duty cycle
To output on OC1B:
TCCR1A |= (1<<COM1B1) | (1<<COM1B0);
OCR1B = (ICR1>>1); // 50% duty cycle
while(1){
// Adjust duty cycle by changing OCR1A or OCR1B
// Adjust frequency by changing ICR1
}
-
The only way you can use Timer0 or Timer2 (8 bit timers) is if you use an external clock source - a crystal. So, using Webbot's calculations. for 38kHz you need a crystal of 9.728MHz with a prescaler of 1. Using internal 8MHz clock, the max frequency you can generate is 31.250kHz, for this frequency you can use a 32kHz sensor instead of a 38kHz one.
Long time ago I was struggling with this because I was using ATmega8 that has 1 PWM output for Timer0 and Timer1 so I coud not use that to drive the motors. So I have designed my Ro-Bot-X board to use a 9.728MHz crystal. Now, that ATmega168 has 2 PWM outputs for each Timer, I would use Timer1 to generate the 38kHz signal and Timer2 to drive the motors, since the motors don't need such a high frequency PWM.
-
I feel stupid...I knew I was making some obvious mistake!! I think I'll just use an external oscillator circuit using a 555 or TTL chip.
I'm already using the 16-bit timer. The project i'm doing is a track timer for measuring the speed of robots and things. I planned on using 2 ir 38khz lightgates and the 16 bit timer for measuring the ellapsed time.
-
Could you not use of the 8bit timers to measure the elapsed time instead - thus freeing the 16 bit timer? You could have the 8bit timer overflow interrupt increment another variable so that your elapsed time would be (external variable)*256 + (timer count in range 0...255)
-
the 8-bit timer overflow interrup will interrupt my program every 255 instructions (assuming the prescale is 1) and won't give as good of a resolution as the 16-bit timer could.