Explanation
Code that controls by software a continuous rotation servo motor, also known as a PWM motor. Timer 0 and timer 1 are used as in sound.c.
The servo motors that has been used for this project, need a frequency of 350 Hz, which is around the frequencies of the tones used for the little piece of music generated. Servo motors' speed depend on the duty cycle of the signal sent to them. The square signals that the motors need have been implemented in software. In the code can be found:
if (turn == 0){ if(tck == 36){ tck = 0; turn = 1; INVERTPORTD; } else{ tck++; } } else if(turn == 1){ if(tck == 54){ tck = 0; INVERTPORTD; turn = 0; } else{ tck++; } }
turn == 0 implements the high level of the square signal and turn == 1 implements the low level of the square signal. By making tck equal for both cases we create a 50 % duty cycle signal. By making tck different from one case to the other we achieve a signal with any duty cycle. In this example the signal has a (1)

Oscilloscope Output
The wave above represents the output of one of the port pins. This is the created wave. The one below that is another pin output.
Note that the Atmega168, the controller that has been selected for this design, has several PWM (Pulse Width Modulation) outputs, that could, a priori, be used to control the servos.
Whole code
#define STOP_TIMER TCCR0 &= 0xF8; #define START_TIMER TCCR0 |= 0x05; #define SETUP_TIMER1A TCCR1A |= 0x00; #define SETUP_TIMER1B TCCR1B |= 0x09; #define SETUPNIB PORTB |= (1<<7) | (1<<6) | (1<<5) | (1<<4); #define RESETUPNIB PORTB |= (0<<7) | (0<<6) | (0<<5) | (0<<4); #define RESETLOWNIB PORTB |= (0<<3) | (0<<2) | (0<<1) | (0<<0); #define INVERTPORTD PORTD = ~PORTD; #include <avr/io.h> #include <avr/interrupt.h> #include <inttypes.h> #include <avr/pgmspace.h> uint8_t count; uint8_t tone; uint8_t timeout; int ticks; void delay_ms(void){ int i; for(i=880u; i != 0; i--); } void delay(uint8_t tms){ uint8_t i; for(i = tms; i != 0; i--){ delay_ms(); } } ISR(TIMER1_COMPA_vect){ static uint8_t tck = 0; static uint8_t turn = 0; cli(); //the following code works as a multiplexer if (turn == 0){ if(tck == 36){ tck = 0; turn = 1; INVERTPORTD; } else{ tck++; // increment the count } } else if(turn == 1){ if(tck == 54){ tck = 0; INVERTPORTD; turn = 0; } else{ tck++; } } else{ turn = 0; tck = 0; // avoid overflow if error } sei(); } ISR(TIMER0_OVF_vect){ cli(); count--; if (ticks == 11){ ticks = 0; if (count == 0x00){ RESETLOWNIB; count = 0x0f; } else{ PORTB = (PORTB & 0xf0) | (count & 0x0f); } } else{ ticks++; } sei(); } void iniconf(void){ cli(); // Disable interrupts /* Program timer0 */ TCNT0 = 0x00; // Reset timer count TCCR0A |= 0x00; // Normal functioning, clk_io/1024 TCCR0B |= 0x05; TIMSK0 |= _BV(TOIE0); // Enable interrupts when overflow /* Program timer1 */ TCNT1H = 0x00; // Reset timer count TCNT1L = 0x00; OCR1AH = 0x01; // Set output compare value OCR1AL = 0xFF; TCCR1A |= 0x00; // Normal functioning, clk_io TCCR1B |= 0x09; TIMSK1 |= _BV(OCIE1A); // Enable interrupts when overflow sei(); // Enable interrupts /* Program the ports */ DDRB = 0xff; // PortB as output port DDRC = 0x01; // PortC0 for wave output DDRD = 0xff; } int main(void){ /* Initialize the system */ iniconf(); /* Initialize goblal variables */ count = 0; ticks = 0; tone = 0; while(1){ delay(50); PORTB = (PORTB & 0x0f) | 0xf0; //SETUPNIB; delay(50); PORTB = (PORTB & 0x0f); //RESETUPNIB; } }






