Sida 1 av 1
Servostyrning med avr
Postat: 18 september 2005, 18:06:59
av MaggoT
Jag har knåpat ihop en kod som skall ställa servot i mittläge, sedan om man kopplar PD0 till jord skall servot hoppa till ena sidan, och när man kopplar PD1 till jord skall det hoppa till andra sidan. Jag undrar om man istället kan koppla en potentiometer till AVRen och styra servot steglöst med den? Hur skulle man kunna göra detta isåfall?
Här kommer koden
Kod: Markera allt
#include <avr/io.h>
#include <avr/delay.h>
int main()
{
// Output
DDRB = 0xFF;
PORTB &= ~_BV(PD0);
// Input
DDRD = 0x00;
PORTD = _BV(PD0) | _BV(PD1);
while(1)
{
if(!(PIND & _BV(PD0)))
{
// Om PD0 låg, Vänster (1ms)
_delay_ms(20);
PORTB |= _BV(PB0);
_delay_ms(1);
PORTB &= ~_BV(PB0);
}
else if(!(PIND & _BV(PD1)))
{
// Om PD1 låg, Höger (2ms)
_delay_ms(20);
PORTB |= _BV(PB0);
_delay_ms(2);
PORTB &= ~_BV(PB0);
}
else
{
// Annars mittläge (1,5ms)
_delay_ms(20);
PORTB |= _BV(PB0);
_delay_ms(1.5);
PORTB &= ~_BV(PB0);
}
}
}
Tyvärr har jag inte kunnat testa koden ännu, eftersom jag får mina servo's på posten först efter ett par dagar.
Postat: 18 september 2005, 22:38:02
av Kaggen
Om du har en inbyggd A/D omvandlare i avr:en kan du ju använda den. Kolla vad du får för värden med vridpotten max resp. min, sedan räknar du ut faktorn av differensen och 1000 us (1 ms, max-min pulstid för servot).
Iomed att jag inte är nån expert på analog elektronik så vet jag inte exakt hur du skall koppla potten mot A/D:n, men det första jag tänker på är ett fast motstånd (säg 10kOhm) från matningen i serie med en pott på 10kOhm. Där tar du ut spänningen till A/D:n mellan det fasta motståndet och potten, enligt:
Kod: Markera allt
+5V----------
|
-
| | 10 kOhm
| |
-
|
--------o till A/D
|
- /
|/| Vridpott 10kOhm
/| |
-
|
GND -----
Då borde ju spänningen bli 2.5V mellan dessa motstånd då potten är på max ohm och 0V då den är på min. Du utnyttjar ju inte alla bitar i A/D:n då iofs, men det blir ju en enkel koppling.
Sedan är det bara att läsa A/D värdet, multiplicera med faktorn och använda produkten som delay-värde.
Som sagt, någon får väl invända om jag är totalt fel ute. Vet inte heller hur det blir med linjäriteten i ovanstående koppling. Antar att om du skall göra det riktigt så ska du nog använda en OP. Blir lite fler komponenter då iofs.
mvh Mats
Postat: 18 september 2005, 23:15:01
av frejo
Gjorde precis samma sak för ca ett år sen, kommer inte ihåg riktigt hur jag tänkte men här är koden:
Kod: Markera allt
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include "a2d.c"
# define OC1 PB5
# define DDROC DDRD
# define OCR OCR1A
volatile uint16_t pwm;
volatile uint16_t freq;
volatile uint8_t direction;
SIGNAL (SIG_OVERFLOW1)
{
// Pulslängd ca 10ms gav bra respons
ICR1=10000;
//Försök att använda hela området på vridpot
//pwm_scope=(936/1024)*pwm;
//OCR=600+pwm_scope;
// Det som funka bäst
if(pwm*2<1536) // För att inte ge för lång pulstid till servot
OCR=600+(pwm*2);
// Försök med 8bit ad, 512*3=1536
//OCR=600+(pwm*3);
}
void
ioinit (void)
{
a2dInit(); // Initierar ADC
// Using phase & freq correct pwm, TOP=ICR1, freq scaling = 8
TCCR1A = _BV (COM1A1);
TCCR1B = _BV (CS11) | _BV (WGM13);
/* set PWM value to 0 */
OCR = 0;
ICR1 = 0;
/* enable OC1 and PB2 as output */
DDRD = _BV (OC1);
//DDRD= 0xFF;
timer_enable_int (_BV (TOIE1));
/* enable interrupts */
sei ();
}
int
main (void)
{
ioinit ();
while(1)
{
pwm=a2dConvert10bit(0);
freq=a2dConvert10bit(2);
}
return (0);
}
Postat: 18 september 2005, 23:50:57
av MaggoT
Hmm, jag försökte kompilera ovanstående kod och fick följande felmeddelande
Kod: Markera allt
> "make.exe" all
-------- begin --------
avr-gcc (GCC) 3.4.3
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Compiling: servo2.c
avr-gcc -c -mmcu=attiny2313 -I. -gdwarf-2 -DF_CPU=8000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=servo2.lst -std=gnu99 -MD -MP -MF .dep/servo2.o.d servo2.c -o servo2.o
servo2.c:5:17: a2d.c: No such file or directory
servo2.c:16: warning: `SIG_OVERFLOW1' appears to be a misspelled signal handler
servo2.c: In function `ioinit':
servo2.c:39: warning: implicit declaration of function `a2dInit'
servo2.c: In function `main':
servo2.c:66: warning: implicit declaration of function `a2dConvert10bit'
servo2.c:71:3: warning: no newline at end of file
make.exe: *** [servo2.o] Error 1
> Process Exit Code: 2
Försökte googla efter vad "a2d.c" är men blev inte så mycket klokare
Skall försöka förstå mig på koden lite
EDIT: Jag glömde skriva att det är en ATTiny2313 jag använder, antar att jag måste ändra någonting i koden för att det skall passa den.
Postat: 19 september 2005, 00:00:01
av Kaggen
Antar att "a2d.c" är frejo's egenhändigt hopknopade A/D konverterar funktioner. Antingen kanske han kan ge dig den koden också, eller får du knåpa ihop något motsvarande själv (mer utmaning och bra träning för de små grå).
mvh Mats
Postat: 19 september 2005, 00:05:29
av frejo
nä det var något jag hittade på nätet vid den tiden.
Nu har jag oftast använt avrlib, ad-libbet i den fungerar riktigt bra.
http://hubbard.engr.scu.edu/embedded/avr/avrlib/
Postat: 19 september 2005, 00:45:33
av MadModder
Varför inte koppla in alla tre anslutningar på en 10kOhm-potentiometer och utnyttja hela spannet mellan 0 och 5V?
Kod: Markera allt
+5V
|
|
-
| |
| |<-----till a/d
| |
-
|
|
0V
Postat: 19 september 2005, 09:31:50
av Kaggen
Eh! Tänkte inte på det.

Postat: 19 september 2005, 11:52:09
av MaggoT
Tack för alla svar

Jag fick mina servo's på posten idag.. sitter och labbar lite nu men något verkar vara fel
Med _delay_ms(0.75) ställer sig servot i mitten, (borde väl vara 1.5ms?). Hur ställer jag in "hastigheten" i AVRen? Verkar vara där det strular..
Postat: 19 september 2005, 19:24:36
av anlamotte
de flesta AVR har en inbyggd spänningsreferens som kan användas.. 2,56V eller liknande.
En pot kopplat mellan den utgången (AREF) och jord funkar bra.
Postat: 19 september 2005, 20:05:08
av cykze
MaggoT: Har du satt F_CPU till rätt värde?
Postat: 19 september 2005, 22:47:10
av MaggoT
cykze> Efter lite pill kom jag fram till att tiden (1.5ms för mittläge) stämde när jag satte såhär:
#define F_CPU 500000UL
Postat: 19 september 2005, 23:48:01
av cykze
Förlåt, jag skulle ju naturligtvis ha skrivit att F_CPU ska sättas till den frekvens (i Hz) som du kör din AVR i, och inget annat.
Postat: 20 september 2005, 00:45:38
av MaggoT
Jo jag tänkte på det, problemet är att jag inte vet vilken hastighet den körs i

jag läste någonstans att de flesta AVR'er är inställda på 1Mhz som default, jag vet dock inte hur man kollar/ändrar detta...
Postat: 20 september 2005, 18:38:45
av cykze
Ta en titt i databladet under kapitlet som heter något med Clock. Där står det vad "default" är.