Use OCR0x to generate PWM for servo motors

This commit is contained in:
Rihards Skuja 2017-12-30 22:49:18 +02:00
parent ddf696e1da
commit e96258cdb8
No known key found for this signature in database
GPG Key ID: 53FA13A3F7F8571B

View File

@ -9,19 +9,25 @@
#include "debug.h" #include "debug.h"
#endif /* DEBUG */ #endif /* DEBUG */
#define SERVO_MIN 930 // (us). Go backwards
#define SERVO_MAX 1930 // (us). Go forwards
#define SERVO_MID (SERVO_MIN + SERVO_MAX) / 2 // Stop
#define PWM_PERIOD 16384 // (1000000 / F_CPU) * PRESCALER * 256) / F_CPU (us)
#define US2TIMER0(us) (255 * (uint32_t)us) / PWM_PERIOD
void init_pwm(void) void init_pwm(void)
{ {
DDRB |= 1 << SERVO_L_PIN | 1 << SERVO_R_PIN; SERVO_DDR |= _BV(SERVO_L_PIN) | _BV(SERVO_R_PIN);
/* Phase Correct PWM; Set/clear on Compare Match when down/up-counting */ TCCR0A |= _BV(COM0A1) | // Clear OC0A on Compare Match, set OC0A at BOTTOM
TCCR1A |= 1 << WGM11 | 1 << COM1A1 | 1 << COM1B1; _BV(COM0B1) | // Clear OC0B on Compare Match, set OC0B at BOTTOM
/* "Clear Timer on Compare match" mode; Prescaler = 1 */ _BV(WGM00) | _BV(WGM01); // Fast PWM, 0xFF TOP
TCCR1B |= 1 << WGM12 | 1 << WGM13 | 1 << CS10; TCCR0B |= _BV(CS00) | _BV(CS01); // clkPWM = clkIO / 64
ICR1 = F_CPU / 50 - 1; // 50Hz required by servos
} }
void init_led(void) void init_led(void)
{ {
DDRD |= 1 << LED_1; DDRD |= 1 << LED_1;
DDRD |= 1 << LED_2;
} }
void init_adc(void) void init_adc(void)
@ -38,7 +44,7 @@ void read_temp(void)
sei(); sei();
for (;;) { for (;;) {
d = ds18b20_gettemp(); d = ds18b20_gettemp();
if (d >= 21) if (d >= 23)
SET(PORTD, LED_1); SET(PORTD, LED_1);
else else
CLR(PORTD, LED_1); CLR(PORTD, LED_1);
@ -49,20 +55,9 @@ void read_temp(void)
void run_servos(void) void run_servos(void)
{ {
/* Stop */ SERVO_L = US2TIMER0(SERVO_MAX);
SERVO_L = 1500; SERVO_R = US2TIMER0(SERVO_MID);
SERVO_R = 1500; _delay_ms(10000); // 10s
_delay_ms(1500);
/* Reverse */
SERVO_L = 2000;
SERVO_R = 2000;
_delay_ms(1500);
/* Forwards */
SERVO_L = 1000;
SERVO_R = 1000;
_delay_ms(1500);
} }
uint16_t read_adc(uint8_t channel) uint16_t read_adc(uint8_t channel)
@ -77,22 +72,12 @@ uint16_t read_adc(uint8_t channel)
int main(void) int main(void)
{ {
uint16_t adc_val;
init_led(); init_led();
init_pwm(); init_pwm();
init_adc(); init_adc();
while (1) { run_servos();
adc_val = read_adc(0); read_temp();
if (adc_val <= 512) {
SERVO_R = 2000;
SERVO_L = 2000;
} else {
SERVO_R = 1000;
SERVO_L = 1000;
}
}
return 0; return 0;
} }