I attached 2 hobby servos on D9 and D10 of UNO, I tested the Arduino IDE example for servo, it works, while when I used registers, it didn't work, could anyone tell me what I lost?
void setup() {
// put your setup code here, to run once:
TCCR1A|=(1<<COM1A1)|(1<<COM1B1)|(1<<WGM11); //NON Inverted PWM
TCCR1B|=(1<<WGM13)|(1<<WGM12)|(1<<CS11)|(1<<CS10); //PRESCALER=64 MODE=14(FAST PWM)
DDRB |= (1<<PB1) | (1<<PB2); //PWM Pins as Output
ICR1=2499; //fPWM=50Hz
}
void loop() {
// put your main code here, to run repeatedly:
OCR1A = 250;
delay(1000);
OCR1A = 375;
delay(1000);
OCR1A = 500;
delay(1000);
OCR1B = 250;
delay(1000);
OCR1B = 375;
delay(1000);
OCR1B = 500;
delay(1000);
}
I can't help, since I have never done that port addressing stuff, but please explain what you think it does? Maybe it's doing what you expect, and that might not be what a servo expects.
I see you seem to set the pins as pwm, but servos don't use pwm in the simple Arduino sense.
Yes that indeed is the problem. @MianQi you are using the registers to set the PWM function of the timers. Why do you want to do this anyway?
Servos are fed with PPM, pulse position modulation. That is where a pulse is generated ever 50mS or so and it is the width of this pulse that controls the servo's position. This can be generated on any pin using the servo library. It seems a waste of time using anything else unless you have a good reason.
Yes, I also meant to say that with the PPM approach it's the absolute high time that's important, not the % ala PWM. The frequency (afaik) just needs to make sure the pulse is often enough to get the servo to keep on station.
There are some problems when setting the registers. You must not use the |= operator, because there are bits set from arduino initializing, that must be cleared. Therefore use the '=' operator to set the control registers.
With a prescaler of 64, TOP must be set to 5000 to get a 20ms refresh rate.
Using 16-bit registers is ok, the compiler handles this correctly.
N.B. You can have a better resolution with a prescaler of 8 and a TOP value of 40000.
In remote-controlled model flight, PPM is a mutliplex signal from the receiver that contains the information for all connected servos. Each individual servo receives a pure PWM signal, whereby the servo position does not depend on the pulse-pause ratio, but on the absolute pulse length ( 1..2ms ) with a constant repetition rate of 20ms ( the repetition rate is less important and may vary a bit without changing the servo position ).
And that's exactly what the timer creates. The timer pulses are much more stable than the ISR created pulses of the servo library.
DDRB |= (1 << DDB1)|(1 << DDB2);
// PB1 and PB2 is now an output
ICR1 = 0xFFFF;
// set TOP to 16bit
OCR1A = 0x3FFF;
// set PWM for 25% duty cycle @ 16bit
OCR1B = 0xBFFF;
// set PWM for 75% duty cycle @ 16bit
TCCR1A |= (1 << COM1A1)|(1 << COM1B1); // |(1 << COM1A0)|(1 << COM1B0); // Add the extra code to make it inverting
// set none-inverting mode
TCCR1A |= (1 << WGM11);
TCCR1B |= (1 << WGM12)|(1 << WGM13);
// set Fast PWM mode using ICR1 as TOP
TCCR1B |= (1 << CS10);
// START the timer with no prescaler
while (1);
{
// we have a working Fast PWM
}
What's the deference between it and my code? I mean the setting pattern are the same.
Don't knkow what you are doing. I tested on UNO and Leonardo. It worked perfectly on both boards.
Not for me. The '|=' is still the problem. If you don't use '=' or clear the register first, you don't know how the register is set at the end.
And the code doesn't creat a servo suitable signal. How do you check if it works?
Now, I found the block was in ADC, i am not sure it is suitable to attach the ADC code here or I should open a new thread. Since it was part of my question, so I just attach them here: