Hello
I want to control 2 DC motors...
I set the Timer1 for fast pwm no problem... I run at 4 mhz....
what prescaller I need?
and even if I set the OCR1A and OCR1B the speed is constant... any ideea?
thanks
TCCR1A |= (1<<WGM10)|(1<<WGM11)|(1<<COM1B1)|(1<<COM1B0)|(1<<COM1A1)|(1<<COM1A0);
TCCR1B |= (1<<CS11)|(1<<WGM13)|(1<<WGM12); //prescaller
here is the whole
here is the whole code
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
/* PB4 M1 - pwm
* PB2 M1
* PB3 M2 - pwm
* PB1 M2
* PD6 M1 -enable
* PB0 M2 -enable
* forward: PB1,PB2 low, pwm
* reverse: PB1,PB2 high, inverted pwm
* stop: PB1,PB2 low, pwm 0(low);
* protocol has to send first the direction, 2. left speed (M2), 3. right speed
*/
void forward(void);
void reverse(void);
void left(void);
void right(void);
void stop(void);
void USART_init(uint16_t ubrr_value);
unsigned char USART_get(void);
void btimer(void);
int direction; //0-stop, 1-forward, 2-reverse, 3 - left, 4 - right
int main()
{
DDRB |= 0xFF; //motors output
DDRD |= (1<<PD6); //motor output
PORTD |= (1<<PD6); //enable 1
PORTB |= (1<<PB0); //enable 2
USART_init(51); //9600 baud
sei();
while(1)
{
direction = 1;
switch(direction)
{
case 0:
stop();
while(direction==0);
break;
case 1:
forward();
OCR1A = 25;
OCR1B = 25;
while(direction==1);
break;
case 2:
reverse();
while(direction==2);
break;
case 3:
left();
while(direction==3);
break;
case 4:
right();
while(direction==4);
break;
}
}
};
void reverse()
{
PORTB = 0x00;
PORTB |= (1<<PB2)|(1<<PB0);
PORTD |= (1<<PD6);
TCCR1A = 0x00;
TCCR1A |= (1<<WGM10)|(1<<WGM11)|(1<<COM1A1)|(1<<COM1B1)|(1<<COM1B0);
btimer();
TCCR1C = 0x00;
};
void forward()
{
PORTB = 0x00;
PORTB |= (1<<PB1)|(1<<PB0);
PORTD |= (1<<PD6);
TCCR1A = 0x00;
TCCR1A |= (1<<WGM10)|(1<<WGM11)|(1<<COM1A1)|(1<<COM1B1)|(1<<COM1A0);
btimer();
TCCR1C = 0x00;
};
void right()
{
PORTB |= (1<<PB1);
PORTB |= (1<<PB2);
PORTB |= (1<<PB0);
PORTD |= (1<<PD6);
TCCR1A = 0x00;
TCCR1A |= (1<<WGM10)|(1<<WGM11)|(1<<COM1B1)|(1<<COM1B0)|(1<<COM1A1)|(1<<COM1A0);
btimer();
TCCR1C = 0x00;
};
void left()
{
PORTB = 0x00;
PORTB |= (1<<PB0);
PORTD |= (1<<PD6);
TCCR1A = 0x00;
TCCR1A |= (1<<WGM10)|(1<<WGM11)|(1<<COM1A1)|(1<<COM1B1);
btimer();
TCCR1C = 0x00;
};
void stop()
{
if(direction==2)
{
forward();
_delay_ms(100);
};
if(direction==1)
{
reverse();
_delay_ms(100);
};
PORTB = 0x00;
PORTD = 0x00;
TCCR1A = 0x00;
TCCR1B = 0x00;
TCCR1C = 0x00;
};
//UART PART
void USART_init(uint16_t ubrr_value)
{
UBRRL = ubrr_value;
UBRRH = (ubrr_value>>8);
UCSRC = (1 << UCSZ1) | (1 << UCSZ0); //8bit 1 stop bit
UCSRB=(1<<RXEN)|(1<<TXEN)|(1<<RXCIE); //interrupt enable
};
unsigned char USART_get(void)
{
while ( !(UCSRA & (1<<RXC)) );
return UDR;
};
ISR(USART_RX_vect)
{
direction=USART_get();
OCR1A=USART_get();
OCR1B=USART_get();
};
void btimer()
{
TCCR1B = 0x00;
TCCR1B |= (1<<CS10)|(1<<CS12)|(1<<WGM13)|(1<<WGM12); //prescaller
};
hey check this link
hey check this link out: http://www.arcfn.com/2009/07/secrets-of-arduino-pwm.html
it has some formulas that should help you calculate the prescaler and the output frequency.
Next step: you got fast pwm with SET on compare match and CLEAR at bottom. Point is that the TOP is OCR1A…so basically it sets at the TOP and right after that it CLEARS, i guess that’s a problem as it stays on for almost no time, this would make the OC1A output useless. (mind that it’s 24.00 so i’m really tired…could have made some mistakes in checking the datasheet)
I suggest you use a fast PWM mode with a fixed TOP, such as the 0101, 0110 or 0111 (these 4 bits are WGM13, 12, 11 and 10).
Strange how speed doesn’t change though…