void t2_fastpwm_init() // initialization for Phase Correct PWM signal using timer 2
{
// WGM2[1:0]= 11, for Fast PWM mode
// COM2[1:0]= 10, to select non inveting mode
// CS2[2:0] =010. for prescaler=8
// TCCR1A = (0<<COM1A0)|(1<<COM1A1)|(0<<COM1B0)|(0<<COM1B1)|(0<<FOC1A)|(0<<FOC1B)|(1<<WGM11)|(0<<WGM10);
//TCCR1B = (0<<ICNC1)|(0<<ICES1)|(1<<WGM13)|(1<<WGM12)|(0<<CS12)|(0<<CS11)|(1<<CS10);
TCCR2=(1<<FOC2)|(0<<WGM20)|(1<<WGM21)|(0<<COM20)|(1<<COM21)|(2<<CS20);
DDRD|=(1<<PD7); // selcet OC2 as output pin
TIMSK|=(1<<OCIE2); //enable Output compare interrupt
}
//-------------------------
#include <avr/io.h>
#include<avr/interrupt.h>
#include<util/delay.h>
int count;
int main(void) {
//Enable internal pull ups
PORTD=0xFF;
sei();
DDRD=0xFF;
DDRB=0xff;
//TOP=ICR1;
//ICR1=20000 defines 50Hz PWM
TCCR2|=(0<<FOC2)|(1<<WGM20)|(0<<WGM21)|(1<<COM20)|(1<<COM21)|(1<<CS20)|(1<<CS21)|(1<<CS22);
DDRD|=(1<<PD7); // selcet OC2 as output pin
TIMSK|=(1<<OCIE2); //enable Output compare interrupt
//TCCR2|=(0<<FOC2)|(1<<WGM21)|(0<<WGM20)|(0<<COM21)|(0<<COM20)|(1<<CS20)|(1<<CS20)|(1<<CS20);
OCR2=215;
while(1) {
//OCR2=62;
}
}
ISR(TIMER2_COMP_vect)
{
TCCR2|=(0<<FOC2)|(1<<WGM20)|(0<<WGM21)|(1<<COM20)|(1<<COM21)|(1<<CS20)|(0<<CS21)|(1<<CS22);
OCR2=172;
//TCCR2|=(
PORTB ^= 0x01;
}
Hi Im doing a small project for servo control using the avr mega 16. I am doing a phase correct PWM with timer 2 of the avr. the thing is driving me crazy.
how can i get a 50Hz wave for the control. and how can i control that. i have done the same with timer 1 with 1 Mhz Internal clock. but need this odd frequency for a better UART communication. and timer 1 is used as a counter, so I cant access that too. any help?
#include <avr/io.h>
int main(void) {
DDRB|=(1<<PB3); // selcet OC0 as output pin
// Fast PWM, TOP = 255, Prescale = 256, F_CPU = 11.0592Mhz
TCCR0 |= (0<<FOC0)|(1<<WGM00)|(1<<WGM01)|(0<<COM00)|(1<<COM01)|(0<<CS00)|(0<<CS01)|(1<<CS02);
// This gives you ~1ms pulse. 43.2 is accurate for 1ms.
OCR0=43;
while(1) { }
}
There are two interrupts for Timer2 - the overflow (vector 5) and compare (vector 4).NOTE: This uses Timer/Counter0, because there are no interrupts available for Timer/Counter2. The output will be on pin PB3. The interrupt is needed for the trick to remove pulses from the signal.
There are two interrupts for Timer2 - the overflow (vector 5) and compare (vector 4).
If you want an exact 50Hz, you can use CTC mode with a prescaler of 1024, OCR2=TOP=215. You then have to use an compare interrupt to create the pulse, during which you set the prescaler to 128 and OCR2 between 172 and 64 for a pulse between 1ms and 2ms. This allows you to have a better resolution of your pulse width; 109 steps rather than the 12 steps above.
.. if you modify the prescaler rather than skipping output pulses for a constant interrupt rate there will be less time wasted in the interrupt. Additionally, a lower prescaler may be used for the actual pulse to provide finer resolution of the pulse width.
#include <avr/io.h>
#include<avr/interrupt.h>
// Volatile keyword is important
volatile char count=0;
// We use this ISR to leave only every sixth pulse and remove the rest.
// This reduces the PWM frequency to ~56Hz.
ISR(TIMER2_COMP_vect) {
if (count){ // Disconnect the OC2 to reduce pulse rate
TCCR2 &= ~(1<<COM21);
count--;
}
else { // Connect the OC2 (PD7) for this pulse
TCCR2 |= (1<<COM21);
count=6;
}
}
int main(void) {
DDRD|=(1<<PD7); // selcet OC0 as output pin
// Fast PWM, TOP = 255, Prescale = 128, F_CPU = 11.0592Mhz
TCCR2 |= (0<<FOC2)|(1<<WGM20)|(1<<WGM21)|(0<<COM20)|(1<<COM21)|(1<<CS20)|(0<<CS21)|(1<<CS22);
// This gives you ~1ms pulse. (86.4 is accurate value).
OCR2=86;
// Setup interrupt so we can remove pulses from the pulse train
TIMSK |= OCIE2;
sei();
while(1) {
}
}
It only gives finer resolution if you're using a prescaler of 256. The pulses are just as accurate with either method; the gaps can be less consistent with the method I outlined, but the frequency can be adjusted more readily. I don't see any added safety in accessing OCR2 directly from main code rather than the interrupt. I don't think it's particularly more convenient either.I don't see how your method gives finer resolution. You still have the same limits.. max OCR2 is 255. My flaw was to use the Timer0, which does not have a prescaler of 128.
My method give more accurate and consistent pulses, because the ISR call overhead does not affect the timing, unlike in your method. My method is also more convenient and safer, because you can modify OCR2 at anytime. In your method you can only modify OCR2 inside the interrupt. Which means that you need a global variable to hold the actual PWM value you want.
#include <stdint.h>
#define XTAL 11059200
#define LOW_PWM (uint8_t)(0.001 * XTAL / 128 - 0.5)
#define HIGH_PWM (uint8_t)(0.002 * XTAL / 128 - 0.5)
#define COUNT_50HZ (uint8_t)(0.020 * XTAL / 1024 - 0.5)
#define setPwmPercent(pc) do{pwmValue = LOW_PWM + pc * (HIGH_PWM - LOW_PWM) * 5 / 512;}while(0)
volatile uint8_t pwmValue;
void initPwm()
{
PORTD &= ~(1<<7); // output defaults to low when PWM disabled
DDRD |= (1<<7);
setPwmPercent(50); // center pulse width
TCCR2 = (1<<WGM20) | (1<<WGM21) | // fast PWM
(1<<CS22) | (1<<CS21) | (1<<CS20); // 1:1024 prescaler
TIMSK |= (1<<OCIE2);
}
ISR(TIMER2_COMP_vect)
{
if(TCCR2 & (1<<COM21)) // just finished a pulse?
{
TCCR2 = (1<<WGM20) | (1<<WGM21) | // fast PWM
(1<<CS22) | (1<<CS21) | (1<<CS20); // 1:1024 prescaler
OCCR2 = COUNT_50HZ; // interrupt again in 50ms
TCNT = 255; // force rollover
}
else
{
OCR2 = pwmValue;
TCCR2 = (1<<WGM20) | (1<<WGM21) | // fast PWM
(1<<COM21) | // non-inverted PWM
(1<<CS22) | (1<<CS20); // 1:128 prescaler
}
}
int main()
{
initPwm();
while(1)
{
setPwmPercent(** some value **);
.. do some other stuff..
}
return 0;
}
I don't see any added safety in accessing OCR2 directly from main code rather than the interrupt. I don't think it's particularly more convenient either.
Silly users... they can just use the setPwmPercent() function provided then, and not touch things they don't understand.The point was that with your method the user can't access the OCR2 directly. If he does that accidentally it messes up the signal.
Silly users...
cli(); //disable interrupts
setPwmPercent(** some value **);
sei(); // enable interrupts
What, in case only 3 of the 8 bits have been copied over? The byte load and store commands are atomic, there's no need for that craziness...and the convenience point. Everytime you need to change the pwm in your method, you need to make that operation atomic:
In summary, either approach is completely usable.
So i have a question, in avr gcc there are many Interrupt vectors. where can i get a list of all interrupt vectors? 'cse I some times get an error misspelled interrupt handler.. or something.
avr simulator version is AVR Simulator: 1, 0, 2, 1 is that an issue?! i use the older avr studio avr studio 4. I kinda want the newer version, is there any new things in that? excluding the newer cores and things how about the editor?
#include <avr/io.h>
#include<avr/interrupt.h>
#include<util/delay.h>
// Volatile keyword is important
volatile char count=0;
// We use this ISR to leave only every sixth pulse and remove the rest.
// This reduces the PWM frequency to ~56Hz.
ISR(TIMER2_COMP_vect) {
if (count){ // Disconnect the OC2 to reduce pulse rate
TCCR2 &= ~(1<<COM21);
count--;
}
else { // Connect the OC2 (PD7) for this pulse
TCCR2 |= (1<<COM21);
count=6;
}
}
int main(void) {
DDRD|=(1<<PD7); // selcet OC0 as output pin
// Fast PWM, TOP = 255, Prescale = 128, F_CPU = 11.0592Mhz
TCCR2 |= (0<<FOC2)|(1<<WGM20)|(1<<WGM21)|(0<<COM20)|(1<<COM21)|(1<<CS20)|(0<<CS21)|(1<<CS22);
// This gives you ~1ms pulse. (86.4 is accurate value).
OCR2=86;
// Setup interrupt so we can remove pulses from the pulse train
TIMSK |= OCIE2;
sei();
while(1)
{
OCR2=OCR2+10;
_delay_ms(200);
if(OCR2==160)
{
OCR2=86;
}
}
}
for the servo to move from 0 to 180; which values do i have to write to OCR2?
is the equation for that: f_desired=f_cpu/2N(1+OCR2) ??
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?