#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/sleep.h>
static void forwards(void) {
/* Set motors 1 and 2 to move forwards */
PORTB |= _BV(PB0) | _BV(PB2);
PORTB &= ~(_BV(PB1) | _BV(PB3));
/* Set both PWMs to 100% duty cycle */
OCR0A = UINT8_MAX;
OCR0B = UINT8_MAX;
}
static void turning(void) {
/* Set motor 1 to move forward and motor 2 to move backwards */
PORTB |= _BV(PB0) | _BV(PB3);
PORTB &= ~(_BV(PB1) | _BV(PB2));
/* Set both PWMs to 50% duty cycle */
OCR0A = UINT8_MAX / 2;
OCR0B = UINT8_MAX / 2;
}
/* Start a timer for 1 second */
static void start_timer(void) {
TCNT1 = 34285;
/* Set prescaler as F_CPU / 256 */
TCCR1B |= _BV(CS12);
}
static void stop_timer(void) {
/* Disable TIMER1 */
TCCR1B &= ~(_BV(CS12));
}
ISR(INT0_vect) {
turning();
start_timer();
}
ISR(TIMER1_OVF_vect) {
forwards();
stop_timer();
}
int main(void) {
/* Enable pins for motor output */
DDRB |= _BV(PB0) | _BV(PB1) | _BV(PB2) | _BV(PB3);
/* Enable OC0A and OC0B for PWM */
DDRD |= _BV(PD5) | _BV(PD6);
/* Enable INT0 */
EIMSK |= _BV(INT0);
/* Set INT0 interrupt sense on rising edge */
EICRA |= _BV(ISC01) | _BV(ISC00);
/* Set non-inverting mode for PWM on OC0A and OC0B */
TCCR0A |= _BV(COM0A1) | _BV(COM0B1);
/* Set fast PWM mode on OC0A and OC0B */
TCCR0A |= _BV(WGM01) | _BV(WGM00);
/* Set PWM prescaler to F_CPU / 256, start PWM */
TCCR0B |= _BV(CS02);
/* Enable Timer 1 Overflow Interrupts */
TIMSK1 |= _BV(TOIE1);
/* Set the CPU sleep mode to Idle */
set_sleep_mode(SLEEP_MODE_IDLE);
/* Enable interrupts globally */
sei();
/* Set the starting state (robot moving forwards) */
forwards();
for (;;) {
/* Sleep; interrupts will do all the work */
sleep_mode();
}
return 0;
}