NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » Control Servo with Button

May 01, 2011
by lnino
lnino's Avatar

Hi at all.

Because I can't wait to get my parts which I have bought in a online shop to finish my Port Expansion project I started a new one. :-)

I am trying to control a servo with buttons. The servo shall go into a special position by a button press.

I studied as source the servo squirter project and some other stuff I found in the internet. But I don't get it work. The servo won't move.

Can somebody find an error?

Here is my code.

servo_test.c:

// servo_test.c
// for NerdKits with ATmega168

#define F_CPU 14745600

#include <stdio.h>
#include <math.h>

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"
#include "../libnerdkits/uart.h"

//Eingänge: Taster auf GND
//PORTB 1 - Servo moves left
//PORTB 2 - Servo moves to neutral positoin
//PORTB 3 - Servo moves right
//Ausgänge:
//PORTC 3 - Ouput Servo-Impuls

ISR(TIMER1_COMPA_vect)
{
    PORTC|=1<<PC3;
}

ISR(TIMER1_COMPB_vect)
{
    PORTC&=~(1<<PC3);
}

int main()
{
    DDRC |= (1<<PC3); // PORTB0 as Output

    DDRB &= ~(1<<PB1); // Button PB1 as Input

    PORTB |= (1<<PB1); // turn on internal pull up resistor

    //Prescaler 1/8, CTC-Modus
    TCCR1B|=(1<<WGM12)|(1<<CS11); 
    //20ms
    OCR1A=9999;
    //Endposition 1ms =499, 2ms=999
    //749 is a value for 1,5ms = Neutralposition
    OCR1B=749;
    //Interrupts for Compare Match A und B activate
    TIMSK0|=(1<<OCIE1A)|(1<<OCIE1B);
    //Interrupts activating
    sei();

    while(1)
    {
        if(!(PINB&(1<<PINB1)))
        {
            if(OCR1B<=999&&(!(TCNT1%43)))//The Modulo is for moving slow
                OCR1B+=1;
        }
        /*if(!(PINB&(1<<PINB3)))
        {
            if(OCR1B>=499&&(!(TCNT1%43)))//see above
                OCR1B-=1;
        }   
        if(!(PINB&(1<<PINB2)))
            OCR1B=749;
        */
    }
    return 0;
}
May 01, 2011
by missle3944
missle3944's Avatar

Hi lnino.

I am delayed on a project similar to this one. On my (working)code. I have it set when the button is pushed then add 25 to pos. The pos=+ is what you are using to control servo.

If i was you I would do the servo squirter project and just cut out the 2nd motor code.That is what I did here I think OCR1B is the pwm stuff that you dont use to control the servo but try something this...

mode_select = (PINC & (1<<PC2)) >> PC2;
if (mode_select == 0) // Pushbutton switch "******************OPEN*******************"  
{

 pos=+3000;
  }

Then once you push the button the servo will move 3000 over.

-missle3944

May 01, 2011
by lnino
lnino's Avatar

I had problems to get the servo squirter working when I modified it. Maybe you can post your code to see what I did wrong.

How did you get the right position? In my project it always stays at the same value.

May 03, 2011
by lnino
lnino's Avatar

Hi at all.

Now I got my code partitionally working.

But it still won't exactly do what I want. I want to press a button and the servo should walk to a secific position. And the servo should stay on this position until I press another key or something else. Can someone help me to solve this issue.

At the moment the button increases OCR1A and walks forward and after that maybe because of the interrupt the servo goes backwards.

Also my display shows always the text of my old programm. Which is definatly not in the chip. And it shows many squares. Is that because my button is also connected to PINB like the display?

And why is the led flashing and not lighting permanently? Because of the interrupt?

Some data:

Servo is connected to PB2

Button is connected to PB1

LED is connected to PC0

Here is a video of my test:

VIDEO

Here is the code:

// test.c
// for NerdKits with ATmega168

/*Inputs: Button on GND
PORTB 1 - Servo spins left
AOuputs:
PORTB 2 - Ouput Servo-Impuls
*/

#define F_CPU 14745600

#include <stdio.h>
#include <math.h>

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"
#include "../libnerdkits/uart.h"

ISR(TIMER1_COMPA_vect)
{
    PORTB|=1<<PB2;
}

ISR(TIMER1_COMPB_vect)
{
    PORTB&=~(1<<PB2);
}

int main()
{
    DDRC |= (1<<PC0); // LED Red as output
    //PORTB 2 as Ouput
    DDRB=1<<DDB2; 
    //Pullup-Widerstände for PORTB 1
    PORTB=(1<<PB1);
    //Prescaler 1/8, CTC-Modus
    TCCR1B|=(1<<WGM12)|(1<<CS11);

    OCR1A=0;

    OCR1B=100;

    TIMSK1|=(1<<OCIE1A)|(1<<OCIE1B);

    //Interrupts activating
    sei();

    while(1)
    {
        if(!(PINB&(1<<PINB1)))
        {
            // turn on Red LED
            PORTC |= (1<<PC0);

            OCR1A+=100;     
        }
    }
    return 0;
}
May 03, 2011
by Ralphxyz
Ralphxyz's Avatar

Sorry lnino but your video is not viewable on my mac OS X 10.6.7.

I even went through a complicated driver install but nothing appears, maybe after a reboot.

Ralph

May 03, 2011
by lnino
lnino's Avatar

Maye you can see it here:

VIDEO Imageshack

May 11, 2011
by lnino
lnino's Avatar

Hi, does anybody have an idea?

May 11, 2011
by Noter
Noter's Avatar

You need to debounce your button. Without debounce you may press once but the mcu will see many contacts which gives unpredictable results.

May 11, 2011
by lnino
lnino's Avatar

I think this is not the problem.

If I press the button just for a short period the servo moves just a bid forward.

If I press the button for a long time the servo moves on with a big step.

My problem is when I release the button the servo moves backwards.

When I push the button I want that the servo moves to a specific position. And when I release the button the servo should stay in that position.

How can I do that?

May 11, 2011
by Ralphxyz
Ralphxyz's Avatar

lnino, as Noter said that sounds like a bouncing switch are you doing anything about de-bounce?

Ralph

May 11, 2011
by Noter
Noter's Avatar

Ok, I see maybe the debounce is not the problem. How many times can you add 100 to OCR1A before it wraps back to zero? And how long does the button need to be closed for that to happen?

Maybe add a delay to the loop so slow things down?

May 12, 2011
by lnino
lnino's Avatar

It wraps back to zero every time.

If i push the button once it moves for instance 1cm forward and after that back to zero. If I keep the button pressed it moves forward until it reaches the end. When I release the button it goes back to zero.

Therefore I am not able to keep a position.

A delay would only slow down the back movement to zero, but won't stay in the current position. Or will this solve my problem?

Difficult problem.

May 12, 2011
by Noter
Noter's Avatar

Here's what I think is going on. The while loop is really fast. I don't think you can press and release the button quick enough to get only a few iterations. Probably you're getting thousands of iterations even with the shortest press you can do. The results are unpredictable and the motor definately can't respond to changes in the PWM as fast as they are happening so who knows where it will end up. If you add a delay of 100ms then you'll get 10 iterations per second while the button is pressed and then a quick press should move the position forward and leave it there. A longer press will wrap back to zero and move the position back. Maybe even 500ms would work better. Experiment with different values to see which one works best.

Post a Reply

Please log in to post a reply.

Did you know that many systems in nature can be described by a first order response? Learn more...