Motor Control

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)
{36 \over (36 + 54) * 100 } = 40 \% duty cycle

Oscilloscope Output

osccapturepwm.tif

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;
    }
}
page_revision: 9, last_edited: 1209615460|%e %b %Y, %H:%M %Z (%O ago)
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License