Wykorzystałem Atmege16. FCPU 8MHz.
PWM dla serwa
Użyłem licznika 16 bitowego. Preskaler 8. ICR20000 i mamy 50Hz.
Najcieżej było pogodzić 10bitowa rozdzielczość ADC z rejestrem OCR1A. Wiadomo ADC ma wartość maksymalna 1024, potrzebny jest impuls szer. od ok 0,5 do ok 2,5 ms. dlatego potrzebujemy do OCR1A wisac wartości ok 500-2500 aby uzyskac impulsy do sterowania serwem.
Ja to zrobiłem tak że wartość ADC pomnożyłem przez trzy i podstawiałem pod OCR1A. Niżej są pomierzone voltomierzem i analizatorem stanów logicznyc wartości dla minimalnego i maksymalnego wychylenie orczyka serwa:
min:
0,48V - 0,600ms. - ADC=200 - OCR1A=630
max:
2,2V - 2,600ms. - ADC=900 - OCR1A=2700
f= 52.00 Hz
Miałem tez problem z przekroczeniem jak i za niską wartością OCR1A przy kręceniu potencjometrem (kiedy to potencjometr był w skrajnych pozycjach), co powodowało że impuls był za waski bądż za szeroki dla serwa, dokladnie to widać na filmie, to też rozwiązalem programowo. Mały minus że steruje serwem w pewnym zakresie potencjometru, ale i tak wiecej go wykorzystuje.
Kod: Zaznacz cały
if (ADC<210)
{ OCR1A = 630;}
else if (ADC>900)
{ OCR1A = 2700;} http://www.youtube.com/watch?v=iqof8xaW ... e=youtu.be
I cały kod
Kod: Zaznacz cały
#define F_CPU 8000000UL
#include <stdio.h>
#include <avr/io.h>
#include <util/delay.h>
#define LED1 PD7
#define ADCIN PA3
int main(void)
{
DDRD |= (1<<LED1); //LED Pins as Out
DDRA &=~ (1<<ADCIN);
ADCSRA |= (1<<ADEN)|(1<<ADPS2)|(1<<ADPS0);
ADMUX |= (1<<MUX1)|(1<<MUX0)|(1<<REFS1)|(1<<REFS0);
DDRB = 0xFF;
PORTB = 0xFF;
DDRC = 0xFF;
PORTC = 0xFF;
DDRD = 0xFF;
PORTD = 0xFF;
TCCR1A|=(1<<COM1A1)|(1<<COM1B1)|(1<<WGM11);
TCCR1B|=(1<<WGM13)|(1<<WGM12)|(1<<CS11);
ICR1 = 20000;
while(1)
{
uint16_t x;
{
ADCSRA |= (1<<ADSC);
while(ADCSRA & (1<<ADSC));
x = ADC*3;
if (ADC<210)
{ OCR1A = 630;}
else if (ADC>900)
{ OCR1A = 2700;}
else
{ OCR1A = x;}
if(ADC<500)
{
PORTD &=~ (1<<LED1);
}
else
{
PORTD |= (1<<LED1);
}
}
}
}