Hallo!
Is er ergens een tutorial te vinden over het aansturen van een servo met een AVR controller?
Hier zijn toch vast wel stukjes script voor te vinden lijkt mij?
Ik heb geen scope, dus zelf code schrijven om een goed puls signaal te genereren zit er waarschijnlijk niet in.
Ik zal wel verkeerd zoeken, maar ik heb nog niks gevonden 
Voor PICs vind ik vanalles, maar voor een AVR alleen hex files of 'grote' source files met te veel functies. Ik ben helaas nog te onervaren om alleen het servo sturen daar uit te destilleren.
Ik hoef geen seriële input te verwerken, het aansturen van de servo is genoeg.
Wie o wie helpt mij op weg?
bij voorbaat dank,
Joost
Marcel
AVR C tutorial http://expand.xs4all.nl/avr
Script? Wat voor taal moet het zijn dan, ASM, basic, C, etc.. ? En wat voor servo? Bedoel je een standaard modelbouw servo met 1-2ms PWM signaal?
[Bericht gewijzigd door Marcel op ]
Sorry voor mijn onvolledigheid.
Ik bedoel inderdaad een 'gewone' modelbouw servo.
En met script bedoelde ik de C cource.
Ik programmeer namelijk in CodeVision, dus ik heb het liefst een C voorbeeld.
Bedankt voor je antwoord.
Joost
Marcel
AVR C tutorial http://expand.xs4all.nl/avr
Op zich is een servo sturing wel een leuke uitbreiding voor mijn AVRGCC tutorial. Ik zal eens kijken wat ik kan doen. Maar heb vooral geen haast. Wellicht dat ik er vanavond nog mee begin. Maar anders schuift het zo door naar volgende week. Het wordt dan uiteraard geschreven voor de AVRGCC compiler. Je moet het dan zelf maar zien te porteren naar Codevision. Of je stapt over op AVRGCC, dat kan natuurlijk ook.
Marcel
AVR C tutorial http://expand.xs4all.nl/avr
Zo, ik heb wat in elkaar gezet. Het is vrij eenvoudig, maar toch heb ik er nog wel even mee zitten klooien. Ik kreeg de timing niet goed en snapte er niets van. Om de getallen met elkaar uit te lijnen had ik er een 0 voorgezet en er niet bij stilgestaan dat dat de octale notatie is.
Dit is voor een ATtiny2313 op 1MHz (1MHz is ook de fabriekinstelling). Voor een andere kloksnelheid hoeft alleen de timing aangepast te worden. Een andere AVR is ook geen probleem mits die een 16 bits timer heeft.
Een servo signaal is een pulsbreedte gemoduleerd signaal. De totale puls is altijd 20ms lang. De tijd dat de puls hoog is varieert van 1ms tot 2ms, waarbij 1.5ms overeenkomt met de middenstand van de servo. De servo waarmee ik heb getest, een oude Robbe S122, heeft een iets groter bereik 0.6ms tot 2.4ms.
Timer 1 loopt op de zelfde snelheid als de core (1MHz). Deze loopt tot 20.000 (output compare register 1A) en begint dan opnieuw. 20.000 tellen komt precies overeen met 20ms.
De output compare registers 1A en 1B triggeren een bijbehorend interrupt die er voor zorgt dat poort PB3 op de max van 20.000 hoog gemaakt wordt en op de instelbare waarde van OCR1B weer laag. OCR1B representeert het servo signaal in us.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
SIGNAL(SIG_TIMER1_COMPA)
{
PORTB |= (1 << PB3); // PB3 high
}
SIGNAL(SIG_TIMER1_COMPB)
{
PORTB &= ~(1 << PB3); // PB3 low
}
int main()
{
TCCR1B = (1 << WGM12) | (1 << CS10); // timer1: ctc, clk/1
TIMSK = (1 << OCIE1A) | (1 << OCIE1B); // timer1: output_compare a and b
OCR1A = 20000; // 20ms
OCR1B = 1500; // 1.5ms
DDRB |= (1 << PB3); // PB3 as output
unsigned int servoTiming; // servo timing in us
sei(); // enable interrupts
while(1)
{
// slowly turns servo from one side to the other
for(servoTiming = 1000; servoTiming < 2000; servoTiming++)
{
OCR1B = servoTiming;
_delay_ms(10);
}
// slowly turns the servo back
for(servoTiming = 2000; servoTiming > 1000; servoTiming--)
{
OCR1B = servoTiming;
_delay_ms(10);
}
}
return 0;
}
Testopstelling
Timing servo controller op scoop. (5V/div 5ms/div)
Hier is duidelijk het 20ms herhalende signaal te zien.
Een 1.5ms signaal. (5V/div 1ms/div)
Vet!
Hier moet het zeker mee lukken, bedankt!!
zelf ook nog een linkje gevonden:
http://www.seattlerobotics.org/encoder/200106/16csscnt.htm#1.2
Binnenkort eens testen.
Nogmaals bedankt.
Joost
Hallo!
Ik heb het zojuist even geprobeerd, maar mijn servo duikt de hoek in 
Terwijl hij toch in het midden zou moeten blijven staan lijkt mij. (compare register B verander ik niet)
Ik zal wel iets fout ingesteld hebben, maar ik kan helaas niet vinden wat.
// Timer 1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
PORTB.0 = 1;
}
// Timer 1 output compare B interrupt service routine
interrupt [TIM1_COMPB] void timer1_compb_isr(void)
{
PORTB.0 = 0;
}
void main(void)
{
.....
........
......
....
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 1000,000 kHz
// Mode: Normal top=FFFFh
// OC1A output: Toggle
// OC1B output: Toggle
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: On
// Compare B Match Interrupt: On
TCCR1A=0x50;
TCCR1B=0x01;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0b1001110; // 20000
OCR1AL=0b00100000;
OCR1BH=0b101; // 1500
OCR1BL=0b11011100;
....
.....
....
// Global enable interrupts
#asm("sei")
while (1)
{
PORTB.1 = 1; // zet power led aan
};
}
Ziet iemand wat ik fout doe?
En is het trouwens niet mogelijk een servo aan te sturen met een PWM signaal? Zo ja, is dat niet makkelijker/handiger?
Ik hoop dat iemand mij kan helpen.
Joost
Hmm, kan je me daar iets meer over vertellen?
Compare registers en PWM zijn nieuw voor mij.
Ik weet wel wat het in grote lijnen inhoud, maar niet goed hoe ik het moet uitvoeren.
Zonder scope is het moeilijk om te zien wat je doet, hij doet het, of hij doet het niet. Waardoor hij het niet doet, is met mijn ervaring moeilijk te achterhalen.
[Bericht gewijzigd door Joosty op ]
Ik gebruik de attiny2313 voor een rgbled projectje maar het zal vast aan te passen zijn voor die servo;
hieronder wat code:
#define OC0A PB2
#define OC1A PB3
#define OC1B PB4
#define OCR_R OCR1B
#define OCR_G OCR1A
#define OCR_B OCR0A
...onderstaande heb ik in een init methode staan
TCCR0A = (1<<WGM00) | (1<<COM0A1); // timer0 op 8bit normal pwm en doe ook even compare reg goed
TCCR0B = (1<<CS01); // timer 0 op 1/8 vd kloksnelheid
TCCR1A = (1<<WGM10) | (1<<COM1A1) | (1<<COM1B1); // timer1 op 8bit normal pwm en doe ook even compare reg goed
TCCR1B = (1<<CS11); // timer 1 op 1/8 vd kloksnelheid
OCR_R = 0; // pwm waardes op 0
OCR_G = 0;
OCR_B = 0;
DDRB = (1<<OC0A) | (1<<OC1A) | (1<<OC1B); // enable de output compare pinnen, PB2 PB3 PB4
TIMSK = (1<<TOIE1); // enable de interrupts
sei ();
....onderstaande is de functie die de interrupt steeds aanroept
ISR (TIMER1_OVF_vect)
{
//zet hier de waarde van je pwm bijv. (mooi kleurtje maken)
OCR_R = 100;
OCR_B = 0;
OCR_G = 255;
}
Ik speel nog niet zo lang met C en AVR dus spaar me 
Sorry voor de layout
rookie35
wie geen vragen stelt zal geen antwoord krijgen, maar wie geen antwoord krijgt kan wel een vraag hebben gesteld, raaaaaaaaaarrrrr!!!
Op 27 juni 2006 12:54:48 schreef Joosty:
Hallo!Ik heb het zojuist even geprobeerd, maar mijn servo duikt de hoek in
Terwijl hij toch in het midden zou moeten blijven staan lijkt mij. (compare register B verander ik niet)Ik zal wel iets fout ingesteld hebben, maar ik kan helaas niet vinden wat.
Hey
Het kan zijn dat je de pulsbreedte verkeerd hebt want ik heb eens ergens gezien geloof ik dat de ene servo bij een signaal van 1,5 ms het ene doet maar een ander type weer iets anders.
Ook kan het liggen aan het fiet dat je servo´s met een negative en een positieve impuls hebt.In de elektuur van deze maand stond ook een servotester, hiervan was een compleet bouwpakket verkrijgbaar,of een losse voorgeprogrammeerde controller, de code voor het benodigde PIC kon je ook op de site vinden
als het goed is.
Marcel
AVR C tutorial http://expand.xs4all.nl/avr
Zonder interrupts, maar met de PWM module.
#include <avr/io.h>
#include <util/delay.h>
int main()
{
// timer1: fast pwm, clear OC1B on match
TCCR1A = (1 << COM1B1) | (1 << WGM11) | (1 << WGM10);
// timer1: fast pwm, ctc top=OCR1A, clk/1
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10);
OCR1A = 20000; // 20ms
OCR1B = 1500; // 1.5ms
DDRB |= (1 << PB4); // PB4/OC1B as output
uint16_t servoTiming; // servo timing in us
while(1)
{
// slowly turns servo from one side to the other
for(servoTiming = 1000; servoTiming < 2000; servoTiming++)
{
OCR1B = servoTiming;
_delay_ms(10);
}
// slowly turns the servo back
for(servoTiming = 2000; servoTiming > 1000; servoTiming--)
{
OCR1B = servoTiming;
_delay_ms(10);
}
}
return 0;
}
Bedankt voor je hulp!
ik krijg het alleen niet zo 123 naar codevision omgezet.
(1 << COM1B1) | (1 << WGM11) | (1 << WGM10)wat is COM1B1 en WGM11 etc.?
CodeVision lijkt de OCR1 registers verdeeld te hebben over een Hi en een Lo register.
Bij jou is het 1 register, is dit een verschil tussen de compilers, of zit ik in de verkeerde registers te roeren?
Waarom gebruikt niemand CodeVision? Is AVRGCC beter? En waarom?
Ik wil eventueel best overstappen op AVRGCC, maar dan nog is het wel handig als ik weet wat er met bijv. COM1B1 bedoeld word. 
nogmaals bedankt
[Bericht gewijzigd door Joosty op ]
Marcel
AVR C tutorial http://expand.xs4all.nl/avr
Wat betreft die bit definities, lees even pagina 108 van de ATtiny2313 datasheet "16-bit Timer/Counter Register Description" De AVRGCC header files gebruiken altijd bit definities die overeenkomen met de benaming in de datasheet. Het gebruik daarvan is stukken duidelijker dan bijv. TCCR1A = 0x11;
OCRA1 is in werkelijkheid ook verdeelt over twee 8-bits registers, namelijk OCR1AL en OCR1AH. De AVRGCC library maakt daarvan een pseudo 16-bits register. Als je compiler daar niet in voorziet moet je dat dus zelf doen door het 16-bits getal op te splitsen in een hoge byte en een lage byte. Hoe je dat doet lees je op pagina 88 van de datasheet.
CodeVision moet ik voor betalen. AVRGCC kost niets. Met beide kan ik hetzelfde. De keuze lijkt me duidelijk.
virtollie
Modeltreinen automatiseren is géén kinderspel!
Naar aanleiding van deze post heb ik een vervolg vraag. Ik weet niet zeker of dit dan de juiste plek is maar vooruit...
Ik heb de 'tutorial' van Marcel overgenomen en dat werkt (uiteraard) perfect. Maar nu wil ik een tweede servo (tegelijk) aansturen met dezelfde ATTINY2313. Mijn gedachte was als volgt:
De herhalingscyclus voor een servo is 20msec. Volgens mij maakt het dan niet uit waar in die cyclus je het stuursignaal geeft, als het maar steeds op dezelfde plek in de cyclus is. Doe je het bv. steeds op 10msec dan duurt het nog steeds 20msec voor de volgende puls gegeven wordt, toch?
Stel nu dat ik steeds op de 0msec en op de 10msec een stuursignaal geef om zo twee servo's aan te sturen. Dan moet ik er natuurlijk voor zorgen dat de puls op 0msec bij de ene servo komt (en de andere servo op dat moment geen puls krijgt) en op de 10msec de ander.
Iemand een idee hoe ik kan aansturen dat het stuursignaal op het ene moment bij de eerste servo aan komt en op het tweede moment bij de tweede? Ik wou dat via een vrije poort op de ATTINY doen maar krijg het niet voor elkaar...
Alvast bedankt voor het meedenken!
Jeroen.
