Hi I am trying to control a micro servo without the library. A8 is reading voltage from potential divider and as I rotate the potential divider I expect the servo to rotate with it.
It seems like it would only stop at 5 equally spaced angle e.g. 0, 45, 90, 135 and 180. I have tried the servo library and it was capable of stopping at a more specific angle.
Is the duty cycle between 1-2ms ? I have tried 2ms and it does not stop at 180 and it required higher duty cycle like 4ms to reach 180.
float angle=0.00; //duty cycle
float total=20.00; //PWM period
float potential;
void setup() {
pinMode(A8, INPUT); //voltage from potential divider
pinMode(8, OUTPUT); //control signal to servo
}
void loop() {
potential=analogRead(A8);
angle = potential*(4/1023.00);
digitalWrite(8,HIGH);
delay(angle);
digitalWrite(8,LOW);
delay(total-angle);
}
But anyway with that code your main problem is that you can't use delay() to get short accurate delays. The parameter to it is an integer not a float so 2.00 and 2.99 will end up at exactly the same delay. Try using delayMicroseconds instead.
And servos aren't fussy about the pulse repetition rate so you might as well just use a constant 20ms for the off time.
BTW you might not get 180 degrees anyway. Many/most hobby servos are limited to about 120-150 degrees.
You might try this test sketch to determine the end limits and micro values thereof.
/*
Try this test sketch with the Servo library to see how your
servo responds to different settings, type a position
(0 to 180) or if you type a number greater than 200 it will be
interpreted as microseconds(544 to 2400), in the top of serial
monitor and hit [ENTER], start at 90 (or 1472) and work your
way toward zero (544) 5 degrees (or 50 micros) at a time, then
toward 180 (2400).
*/
#include <Servo.h>
Servo servo;
void setup() {
// initialize serial:
Serial.begin(9600); //set serial monitor baud rate to match
servo.write(90);
servo.attach(9);
prntIt();
}
void loop() {
// if there's any serial available, read it:
while (Serial.available() > 0) {
// look for the next valid integer in the incoming serial stream:
int pos = Serial.parseInt();
pos = constrain(pos, 0, 2400);
servo.write(pos);
prntIt();
}
}
void prntIt()
{
Serial.print(" degrees = ");
Serial.print(servo.read());
Serial.print("\t");
Serial.print("microseconds = ");
Serial.println(servo.readMicroseconds());
}
kc15781:
It's working with delayMicroseconds thank you! but it is not as smooth as what I got from the library
As has been asked before;
Why don't you use the servo library?
What you have to realize is that without the library, you trying to do some output timing while you code also has to do other activities.
You code might not get to the part of the code that decides if the servo signal needs to go HIGH or LOW on the exact microsecond you want.
It may be 10 or 15 us late, which means your servo pulse may be 10 or 15us longer or shorter.
The more code you have around it the more inaccuracy in your servo signal because your code has more and more other things to do.
Wrote this and it works but is jittery, I guess because the processor is busy doing other things like Tom said. What's the reason for not wanting to use the lib?
uint32_t uStime, cycle = 2500, pTime = 1476;
void setup() {
// initialize serial:
Serial.begin(9600); //set serial monitor baud rate to match
pinMode(9,OUTPUT);
}
void loop()
{
// if there's any serial available, read it:
while (Serial.available() > 0) {
// look for the next valid integer in the incoming serial stream:
int pos = Serial.parseInt();
pos = constrain(pos, 544, 2400);
pTime = (pos);
Serial.println(pTime);
}
bitWrite(PORTB,1,micros() - uStime < pTime);
if(micros() - uStime > cycle)
uStime += cycle;
}
I believe the lib makes use of a hardware timer to control the pulse width, why not read the code in the files Servo.h and Servo.cpp inside the Servo library.