PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Atmega N fach Servo Controller ?



stochri
09.11.2005, 18:19
Hat jemand schon mal einen mindestens 8 fach Servo Controller mit einem Atmega 8 programmiert oder weiss jemand, wo man sowas findet ?

Besten Dank,
stochri

Kjion
09.11.2005, 21:37
Moin,

hab sowas mal mit einem AT90S2313 programmiert:
http://www.kreatives-chaos.com/index.php?seite=rnkc10_quelltext

MfG Kjion

stochri
10.11.2005, 18:39
Hallo Fabian,

/* Interrupt wird bei einem Überlauf von Timer0 ausgelöst ( alle 2,2 ms )
* Es werden nacheinander die 10 Servos ausgewählt und angesteuert
* Dauer : 17,5 µS @ 4 MHz
*/

Wieso alle 2,2ms ? Du meinst spätestens nach 2,2 ms. Oder ?

Gruss,
stochri

Kjion
11.11.2005, 11:56
ne, die Servos werden alle nacheinander angesteuert. Alle 2,2 ms wird also das nächste Servo ausgewählt. Die Impulserzeugung wird der Einfachheit halber in dem Programm mit Timer1 gemacht.

MfG Kjion

millioneer
11.11.2005, 15:01
prinzipiell kann man mit einem Mega8 auch 20 Servos gleichzeitig ansteuern, guckst du hier:

http://www.roboter-teile.de/Shop/themes/kategorie/detail.php?artikelid=14&kategorieid=17&source=1

stochri
18.11.2005, 21:53
Hier noch mal der Vollständigkeithalber einen weiteren Link auf den Code eines Servocontrollprogramms, welches über die serielle Schnittstelle angesteuert wird:

http://www.mikrocontroller.net/attachment.php/91553/servo.c

stochri
20.11.2005, 10:07
Irgendwie sind alle Servocontrollerprogramme, die ich bis jetzt gerfunden habe, einigermassen umständlich programmiert. Deshalb habe ich beschlossen, das ganze selber zu machen. Hier das Ergebnis:


/************************************************** **********************

SERVO Controller for up to 10 Servos

controlled by serial line
default: 2400 Baud 8N1

Processor: ATMEGA 8
CLOCK: 8MHZ, no prescaler set config bits of Atmega 8 correctly !

Compiler: AVR-GCC


This code is licensed under the GPL.
You may modify, redistribute the code .. blabla, you know what I mean ...

Copyright stochri (c.hab@gmx.net) Nov.2005

************************************************** *************************/
#include <stdlib.h>
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>

typedef unsigned char byte;

#define SYSCLK 8000000 // timer clock 8Mhz
#define MAXPULSFREQ 500 // 2ms => 500HZ

#define TIMER_MAXPULS SYSCLK/MAXPULSFREQ // Timer1 value for a 2ms Puls

#define MINPULS TIMER_MAXPULS/4 // min pulslength = 0.5ms
#define MAXPULS TIMER_MAXPULS // max pulslength=2ms

// port pin definitions
// you may redefine the pins to suit your application
// tale a look at the interrupt routine and enable the cases for your servo

#define LOW_SERVO0 PORTD&=~(1<<6)
#define HIGH_SERVO0 PORTD|=(1<<6)

#define LOW_SERVO1 PORTB&=~(1<<0)
#define HIGH_SERVO1 PORTB|=(1<<0)

#define LOW_SERVO2 PORTB&=~(1<<1)
#define HIGH_SERVO2 PORTB|=(1<<1)

#define LOW_SERVO3
#define HIGH_SERVO3

#define LOW_SERVO4
#define HIGH_SERVO4

#define LOW_SERVO5
#define HIGH_SERVO5

#define LOW_SERVO6
#define HIGH_SERVO6

#define LOW_SERVO7
#define HIGH_SERVO7

#define LOW_SERVO8
#define HIGH_SERVO8

#define LOW_SERVO9
#define HIGH_SERVO9


uint16_t Pulslength[20]; // array for all delays

/************************************************** **********************

SIGNAL(SIG_OVERFLOW1)
timer1 interrupt, generates the high and low pulses for each servo

************************************************** *************************/
SIGNAL(SIG_OVERFLOW1)
{
static byte servoindex_half=0;

switch (servoindex_half)
{
case 0: HIGH_SERVO0; break;
case 1: LOW_SERVO0; break;
case 2: HIGH_SERVO1; break;
case 3: LOW_SERVO1; break;
case 4: HIGH_SERVO2; break;
case 5: LOW_SERVO2; break;
// case 6: HIGH_SERVO3; break;
// case 7: LOW_SERVO3; break;
// case 8: HIGH_SERVO4; break;
// case 9: LOW_SERVO4; break;
// case 10: HIGH_SERVO5; break;
// case 11: LOW_SERVO5; break;
// case 12: HIGH_SERVO6; break;
// case 13: LOW_SERVO6; break;
// case 14: HIGH_SERVO7; break;
// case 15: LOW_SERVO7; break;
// case 16: HIGH_SERVO8; break;
// case 17: LOW_SERVO8; break;
// case 18: HIGH_SERVO9; break;
// case 19: LOW_SERVO9; break;
}


TCNT1 =Pulslength[servoindex_half]; // set time for next interrupt

servoindex_half++; // increment timervalue index
if(servoindex_half==20)servoindex_half=0; // reset index
}
/************************************************** **********************

void setservo(byte index, byte value)

Set servo position
value: 0..255

************************************************** *************************/

void setservo(byte index, byte value)
{
uint16_t wert;

wert=MINPULS+(MAXPULS-MINPULS)/256*value;

// callculate hightime
Pulslength[index<<1]=0-wert;

// sume of low and hightime for one servo is 2ms
Pulslength[(index<<1)+1]=0-(TIMER_MAXPULS-wert);

// 10 servos give you 10*2ms=20ms total cycle time
}

/************************************************** **********************

void init_servos()

initialize all servos to the start position
************************************************** *************************/
void init_servos()
{
byte n;
for(n=0;n<10;n++) setservo(n,128);
}

/************************************************** **********************

void init(void)
initialize the prozessor registers
************************************************** *************************/

void init(void)
{
// prepare RS232
UCSRA = 0x00;
UCSRB = 0x00;
UCSRC = 0x86; // No Parity | 1 Stop Bit | 8 Data Bit
UBRRL = 0xCF; // 2400bps @ 8.00MHz
// UBRRL = 51; // 9600bps @ 8.00MHz
// UBRRL = 25; // 19200bps @ 8.00MHz

/* initialize ports */
DDRB = 0xFF;
DDRC = 0xFF;
DDRD = 0xFF;
PORTB = 0x00;
PORTC = 0x00;
PORTD = 0x00;

// init timer1
TCNT1 = 0-16000;
TCCR1A=0;
TCCR1B=0x01;
TIMSK |= _BV(TOIE2) | _BV(TOIE1);

/* allow interrupts */
sei();
}

/************************************************** **********************

serial communication

************************************************** *************************/

byte chgetchar()
{
UCSRB = 0x10; // enable receiver
while(!(UCSRA & 0x80)); // wait for received byte
return UDR;
}
void chputchar(byte zeichen)
{
UCSRB = 0x08; // enable transmitter
UCSRA|=0x40; // clear transmitter flag
while (!(UCSRA & 0x20)); // wait for empty transmit buffer
UDR = zeichen;
while (!(UCSRA & 0x40)); // Wait for transmit complete flac (TXC)
}
void chSerPrint(unsigned char *data)
{
unsigned char i = 0;
while(data[i]!=0x00) chputchar(data[i++]);
}

/************************************************** **********************

main programm

servo controll by RS232 interface

************************************************** *************************/

int main(void)
{
char c;
byte n;
byte servos[10];

init();
init_servos();

chSerPrint("\n\r-- Atmega8 servo controller V1.0 --\n\r");
chSerPrint("Connection OK\n\r");

while(1)
{

// get key from terminal
c=chgetchar();

if(c=='q') servos[0] += 10;
if(c=='w') servos[0] -= 10;
if(c=='a') servos[1] += 10;
if(c=='s') servos[1] -= 10;
if(c=='y') servos[2] += 10;
if(c=='x') servos[2] -= 10;

// set to default position, if space is pressed
if(c==' ')
{
servos[0] = 128;
servos[1] = 128;
servos[2] = 128;
}

for(n=0;n<10;n++) setservo(n,servos[n]);
}
}


Maximale Zahl Servos: 10
Steuerung: serielle Schnittstelle 2400Baud

Prozessor: Atmega8 8Mhz

Es wird nur Timer 1 verwendet.

geforce
14.05.2008, 19:06
also wo mein problem leigt ist einfach, das ich nicht wirklich weiß, wie so eine steuerung funktioneirt, also was die einzelnen befehle bedeuten usw.

was ich mit einem tutorial meinte, ist eine auflistung der benötigten befehle, was bei welchem befehl passiert und wie ich vorgehen muss, um ein solches programm zu schreiben...

ge

oberallgeier
14.05.2008, 23:27
https://www.roboternetz.de/wissen/index.php/C-Tutorial

https://www.roboternetz.de/wissen/index.php/C-Tutorial

http://www.mikrocontroller.net/articles/AVR-Tutorial:_IO-Grundlagen

Funkrusha
16.06.2008, 21:27
Hi, ich habe mal eine Frage zum Code von "stochri"
Ich habe ein kleines Problem den Code für einen Atmega8515L anzupassen.

Wenn ich versuche den Code zu kompilieren kommt die Fehlermeldung
das TOIE1 und TOIE2 nicht definiert sind. (SYSCLK habe ich angepasst auf 4MHz)

Dem Datenblatt kann ich nur TOIE1 entnehmen allerdings nicht TOIE2.
Ich habe auch mal versuch ein paar Werte aus einem in Assembler geschriebenen UART zu ersetzen. Allerdings komme ich gerade nicht wirklich weiter.

Kann mir vielleicht jemand weiterhelfen?
Oder hat vielleicht jemand einen Ansatz wo ich Lösungen finden könnte?
(Ich arbeite mit dem AVR-Studio und entwickle auf dem STK-500)

Vielen Dank im Vorraus

Gruß
Martin

HannoHupmann
12.08.2008, 15:29
Der schöne Code funktioniert bei mir auch nicht. Das AVR Studio meckert die ganze Zeit herum, dass signal.h eine obsolete Funktion sei und ich dafür interrupt.h verwenden soll. Nehm ich also die signal.h raus, dann bekomm ich immer Fehlermeldungen, dass
"../Test_Serial.c:159: error: 'UCSRB' undeclared (first use in this function)" und so weiter. Jemand ne Idee woran das liegen kann?

uwegw
12.08.2008, 15:41
Bei mir komplierert der Code von stochri, bloß mit etlichen Warnungen. Die lassen sich aber beseitigen:

"This header file is obsolete. Use <avr/interrupt.h>."
#include <avr/signal.h> löschen.

warning: function declaration isn't a prototype
In dem beiden Funktionen fehlt in der Runden Klammer des Funktionskopfes ein void.

warning: pointer targets in passing argument 1 of 'chSerPrint' differ in signedness
In der Funktion 'chSerPrint' das unsigned vom übergebenen Datentyp löschen.



/************************************************** **********************

SERVO Controller for up to 10 Servos

controlled by serial line
default: 2400 Baud 8N1

Processor: ATMEGA 8
CLOCK: 8MHZ, no prescaler set config bits of Atmega 8 correctly !

Compiler: AVR-GCC


This code is licensed under the GPL.
You may modify, redistribute the code .. blabla, you know what I mean ...

Copyright stochri (c.hab@gmx.net) Nov.2005

Warnungen beiseitigt von uwegw

************************************************** *************************/
#include <stdlib.h>
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>

typedef unsigned char byte;

#define SYSCLK 8000000 // timer clock 8Mhz
#define MAXPULSFREQ 500 // 2ms => 500HZ

#define TIMER_MAXPULS SYSCLK/MAXPULSFREQ // Timer1 value for a 2ms Puls

#define MINPULS TIMER_MAXPULS/4 // min pulslength = 0.5ms
#define MAXPULS TIMER_MAXPULS // max pulslength=2ms

// port pin definitions
// you may redefine the pins to suit your application
// tale a look at the interrupt routine and enable the cases for your servo

#define LOW_SERVO0 PORTD&=~(1<<6)
#define HIGH_SERVO0 PORTD|=(1<<6)

#define LOW_SERVO1 PORTB&=~(1<<0)
#define HIGH_SERVO1 PORTB|=(1<<0)

#define LOW_SERVO2 PORTB&=~(1<<1)
#define HIGH_SERVO2 PORTB|=(1<<1)

#define LOW_SERVO3
#define HIGH_SERVO3

#define LOW_SERVO4
#define HIGH_SERVO4

#define LOW_SERVO5
#define HIGH_SERVO5

#define LOW_SERVO6
#define HIGH_SERVO6

#define LOW_SERVO7
#define HIGH_SERVO7

#define LOW_SERVO8
#define HIGH_SERVO8

#define LOW_SERVO9
#define HIGH_SERVO9


uint16_t Pulslength[20]; // array for all delays

/************************************************** **********************

SIGNAL(SIG_OVERFLOW1)
timer1 interrupt, generates the high and low pulses for each servo

************************************************** *************************/
SIGNAL(SIG_OVERFLOW1)
{
static byte servoindex_half=0;

switch (servoindex_half)
{
case 0: HIGH_SERVO0; break;
case 1: LOW_SERVO0; break;
case 2: HIGH_SERVO1; break;
case 3: LOW_SERVO1; break;
case 4: HIGH_SERVO2; break;
case 5: LOW_SERVO2; break;
// case 6: HIGH_SERVO3; break;
// case 7: LOW_SERVO3; break;
// case 8: HIGH_SERVO4; break;
// case 9: LOW_SERVO4; break;
// case 10: HIGH_SERVO5; break;
// case 11: LOW_SERVO5; break;
// case 12: HIGH_SERVO6; break;
// case 13: LOW_SERVO6; break;
// case 14: HIGH_SERVO7; break;
// case 15: LOW_SERVO7; break;
// case 16: HIGH_SERVO8; break;
// case 17: LOW_SERVO8; break;
// case 18: HIGH_SERVO9; break;
// case 19: LOW_SERVO9; break;
}


TCNT1 =Pulslength[servoindex_half]; // set time for next interrupt

servoindex_half++; // increment timervalue index
if(servoindex_half==20)servoindex_half=0; // reset index
}
/************************************************** **********************

void setservo(byte index, byte value)

Set servo position
value: 0..255

************************************************** *************************/

void setservo(byte index, byte value)
{
uint16_t wert;

wert=MINPULS+(MAXPULS-MINPULS)/256*value;

// callculate hightime
Pulslength[index<<1]=0-wert;

// sume of low and hightime for one servo is 2ms
Pulslength[(index<<1)+1]=0-(TIMER_MAXPULS-wert);

// 10 servos give you 10*2ms=20ms total cycle time
}

/************************************************** **********************

void init_servos()

initialize all servos to the start position
************************************************** *************************/
void init_servos(void)
{
byte n;
for(n=0;n<10;n++) setservo(n,128);
}

/************************************************** **********************

void init(void)
initialize the prozessor registers
************************************************** *************************/

void init(void)
{
// prepare RS232
UCSRA = 0x00;
UCSRB = 0x00;
UCSRC = 0x86; // No Parity | 1 Stop Bit | 8 Data Bit
UBRRL = 0xCF; // 2400bps @ 8.00MHz
// UBRRL = 51; // 9600bps @ 8.00MHz
// UBRRL = 25; // 19200bps @ 8.00MHz

/* initialize ports */
DDRB = 0xFF;
DDRC = 0xFF;
DDRD = 0xFF;
PORTB = 0x00;
PORTC = 0x00;
PORTD = 0x00;

// init timer1
TCNT1 = 0-16000;
TCCR1A=0;
TCCR1B=0x01;
TIMSK |= _BV(TOIE2) | _BV(TOIE1);

/* allow interrupts */
sei();
}

/************************************************** **********************

serial communication

************************************************** *************************/

byte chgetchar(void)
{
UCSRB = 0x10; // enable receiver
while(!(UCSRA & 0x80)); // wait for received byte
return UDR;
}

void chputchar(byte zeichen)
{
UCSRB = 0x08; // enable transmitter
UCSRA|=0x40; // clear transmitter flag
while (!(UCSRA & 0x20)); // wait for empty transmit buffer
UDR = zeichen;
while (!(UCSRA & 0x40)); // Wait for transmit complete flac (TXC)
}
void chSerPrint(char *data)
{
unsigned char i = 0;
while(data[i]!=0x00) chputchar(data[i++]);
}

/************************************************** **********************

main programm

servo controll by RS232 interface

************************************************** *************************/

int main(void)
{
char c;
byte n;
byte servos[10];

init();
init_servos();

chSerPrint("\n\r-- Atmega8 servo controller V1.0 --\n\r");
chSerPrint("Connection OK\n\r");

while(1)
{

// get key from terminal
c=chgetchar();

if(c=='q') servos[0] += 10;
if(c=='w') servos[0] -= 10;
if(c=='a') servos[1] += 10;
if(c=='s') servos[1] -= 10;
if(c=='y') servos[2] += 10;
if(c=='x') servos[2] -= 10;

// set to default position, if space is pressed
if(c==' ')
{
servos[0] = 128;
servos[1] = 128;
servos[2] = 128;
}

for(n=0;n<10;n++) setservo(n,servos[n]);
}
}

HannoHupmann
12.08.2008, 15:52
Hi Uwegw
mhm ich hab jetzt mal deinen neuen Code ausprobiert aber bei mir funktioniert der immer noch nicht. Auch wenn ich die Änderungen entsprechend mache, kommt immernoch die Fehlermeldung:


../Test_Serial.c:160: error: 'UCSRA' undeclared (first use in this function)
../Test_Serial.c:160: error: (Each undeclared identifier is reported only once
../Test_Serial.c:160: error: for each function it appears in.)
../Test_Serial.c:161: error: 'UCSRB' undeclared (first use in this function)
../Test_Serial.c:162: error: 'UCSRC' undeclared (first use in this function)
../Test_Serial.c:163: error: 'UBRRL' undeclared (first use in this function)

und für alle anderen in der init Funktion deklarierten UCSx

Irgendwo fallen die raus durch das löschen der signal.h

PS: Du hast nicht zufällig nen Code für nen simplen L298 bzw. wenn das nicht dann wenigstens für nen schlichten PWM bei nem Mega32?

sternst
12.08.2008, 16:06
und für alle anderen in der init Funktion deklarierten UCSx
Irgendwo fallen die raus durch das löschen der signal.h

Dann hast du vergessen, die <avr/io.h> einzubinden.
Und du hast anscheinend auch die <avr/interrupt.h> statt der signal.h nicht eingebunden.

uwegw
12.08.2008, 18:07
Da die io.h und interrupt.h im Code enthalten sind, denke ich eher, dass im makefile kein Mega8 angegeben ist, sondern ein anderer AVR, der andere Registernamen fürs uart besitzt...

sternst
12.08.2008, 18:20
Da die io.h und interrupt.h im Code enthalten sind,
Ja, in deinem, aber auch in seinem?
Er sagt zwar "deinen neuen Code ausprobiert", aber er sagt auch "wenn ich die Änderungen entsprechend mache, kommt immernoch die Fehlermeldung".
Also beziehen sich die Fehlermeldungen wohl auf seinen eigenen (geänderten) Code.


denke ich eher, dass im makefile kein Mega8 angegeben ist, sondern ein anderer AVR, der andere Registernamen fürs uart besitzt...
Wie erklärst du dir dann das:

Irgendwo fallen die raus durch das löschen der signal.h
Die Register müssten dann ja auch mit dem signal.h unbekannt sein.

HannoHupmann
12.08.2008, 19:11
@uwegw hat recht ich hab keinen Mega8 sondern ne Mega32 hier im Einsatz und entsprechendes natürlich auch angegeben.

Der neue Code ist der von Uwegw und die Änderung sind die, die er darüber geschrieben hat. Ansonsten hab ich am Code nix verändert, da er ja nicht funktioniert. Der Code ist wirklich 1 zu 1 der vom Post um 16:41.

Bin wirklich etwas verwundert, was muss ich den anpassen um es doch noch entsprechend zum laufen zu bekommen?

sternst
12.08.2008, 19:35
Poste doch einfach mal Code und Makefile, ansonsten ist das doch nur "im Trüben fischen".
Und wenn es zusätzlich zu den Fehlermeldungen auch noch weitere Warnungen gibt, dann die auch nicht vergessen.

HannoHupmann
12.08.2008, 23:36
@sternest der Code ist genau der gleiche wie der oben. Ich habe kein Zeichen verändert sondern nur strg c und dann strg v gemacht.



/************************************************** **********************

SERVO Controller for up to 10 Servos

controlled by serial line
default: 2400 Baud 8N1

Processor: ATMEGA 8
CLOCK: 8MHZ, no prescaler set config bits of Atmega 8 correctly !

Compiler: AVR-GCC


This code is licensed under the GPL.
You may modify, redistribute the code .. blabla, you know what I mean ...

Copyright stochri (c.hab@gmx.net) Nov.2005

Warnungen beiseitigt von uwegw

************************************************** *************************/
#include <stdlib.h>
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>

typedef unsigned char byte;

#define SYSCLK 8000000 // timer clock 8Mhz
#define MAXPULSFREQ 500 // 2ms => 500HZ

#define TIMER_MAXPULS SYSCLK/MAXPULSFREQ // Timer1 value for a 2ms Puls

#define MINPULS TIMER_MAXPULS/4 // min pulslength = 0.5ms
#define MAXPULS TIMER_MAXPULS // max pulslength=2ms

// port pin definitions
// you may redefine the pins to suit your application
// tale a look at the interrupt routine and enable the cases for your servo

#define LOW_SERVO0 PORTD&=~(1<<6)
#define HIGH_SERVO0 PORTD|=(1<<6)

#define LOW_SERVO1 PORTB&=~(1<<0)
#define HIGH_SERVO1 PORTB|=(1<<0)

#define LOW_SERVO2 PORTB&=~(1<<1)
#define HIGH_SERVO2 PORTB|=(1<<1)

#define LOW_SERVO3
#define HIGH_SERVO3

#define LOW_SERVO4
#define HIGH_SERVO4

#define LOW_SERVO5
#define HIGH_SERVO5

#define LOW_SERVO6
#define HIGH_SERVO6

#define LOW_SERVO7
#define HIGH_SERVO7

#define LOW_SERVO8
#define HIGH_SERVO8

#define LOW_SERVO9
#define HIGH_SERVO9


uint16_t Pulslength[20]; // array for all delays

/************************************************** **********************

SIGNAL(SIG_OVERFLOW1)
timer1 interrupt, generates the high and low pulses for each servo

************************************************** *************************/
SIGNAL(SIG_OVERFLOW1)
{
static byte servoindex_half=0;

switch (servoindex_half)
{
case 0: HIGH_SERVO0; break;
case 1: LOW_SERVO0; break;
case 2: HIGH_SERVO1; break;
case 3: LOW_SERVO1; break;
case 4: HIGH_SERVO2; break;
case 5: LOW_SERVO2; break;
// case 6: HIGH_SERVO3; break;
// case 7: LOW_SERVO3; break;
// case 8: HIGH_SERVO4; break;
// case 9: LOW_SERVO4; break;
// case 10: HIGH_SERVO5; break;
// case 11: LOW_SERVO5; break;
// case 12: HIGH_SERVO6; break;
// case 13: LOW_SERVO6; break;
// case 14: HIGH_SERVO7; break;
// case 15: LOW_SERVO7; break;
// case 16: HIGH_SERVO8; break;
// case 17: LOW_SERVO8; break;
// case 18: HIGH_SERVO9; break;
// case 19: LOW_SERVO9; break;
}


TCNT1 =Pulslength[servoindex_half]; // set time for next interrupt

servoindex_half++; // increment timervalue index
if(servoindex_half==20)servoindex_half=0; // reset index
}
/************************************************** **********************

void setservo(byte index, byte value)

Set servo position
value: 0..255

************************************************** *************************/

void setservo(byte index, byte value)
{
uint16_t wert;

wert=MINPULS+(MAXPULS-MINPULS)/256*value;

// callculate hightime
Pulslength[index<<1]=0-wert;

// sume of low and hightime for one servo is 2ms
Pulslength[(index<<1)+1]=0-(TIMER_MAXPULS-wert);

// 10 servos give you 10*2ms=20ms total cycle time
}

/************************************************** **********************

void init_servos()

initialize all servos to the start position
************************************************** *************************/
void init_servos(void)
{
byte n;
for(n=0;n<10;n++) setservo(n,128);
}

/************************************************** **********************

void init(void)
initialize the prozessor registers
************************************************** *************************/

void init(void)
{
// prepare RS232
UCSRA = 0x00;
UCSRB = 0x00;
UCSRC = 0x86; // No Parity | 1 Stop Bit | 8 Data Bit
UBRRL = 0xCF; // 2400bps @ 8.00MHz
// UBRRL = 51; // 9600bps @ 8.00MHz
// UBRRL = 25; // 19200bps @ 8.00MHz

/* initialize ports */
DDRB = 0xFF;
DDRC = 0xFF;
DDRD = 0xFF;
PORTB = 0x00;
PORTC = 0x00;
PORTD = 0x00;

// init timer1
TCNT1 = 0-16000;
TCCR1A=0;
TCCR1B=0x01;
TIMSK |= _BV(TOIE2) | _BV(TOIE1);

/* allow interrupts */
sei();
}

/************************************************** **********************

serial communication

************************************************** *************************/

byte chgetchar(void)
{
UCSRB = 0x10; // enable receiver
while(!(UCSRA & 0x80)); // wait for received byte
return UDR;
}

void chputchar(byte zeichen)
{
UCSRB = 0x08; // enable transmitter
UCSRA|=0x40; // clear transmitter flag
while (!(UCSRA & 0x20)); // wait for empty transmit buffer
UDR = zeichen;
while (!(UCSRA & 0x40)); // Wait for transmit complete flac (TXC)
}
void chSerPrint(char *data)
{
unsigned char i = 0;
while(data[i]!=0x00) chputchar(data[i++]);
}

/************************************************** **********************

main programm

servo controll by RS232 interface

************************************************** *************************/

int main(void)
{
char c;
byte n;
byte servos[10];

init();
init_servos();

chSerPrint("\n\r-- Atmega8 servo controller V1.0 --\n\r");
chSerPrint("Connection OK\n\r");

while(1)
{

// get key from terminal
c=chgetchar();

if(c=='q') servos[0] += 10;
if(c=='w') servos[0] -= 10;
if(c=='a') servos[1] += 10;
if(c=='s') servos[1] -= 10;
if(c=='y') servos[2] += 10;
if(c=='x') servos[2] -= 10;

// set to default position, if space is pressed
if(c==' ')
{
servos[0] = 128;
servos[1] = 128;
servos[2] = 128;
}

for(n=0;n<10;n++) setservo(n,servos[n]);
}
}


aber hier auch nochmal alle Fehlermeldungen dazu



rm -rf Test_Serial.o Test_Serial.elf dep/* Test_Serial.hex Test_Serial.eep Test_Serial.lss Test_Serial.map
Build succeeded with 0 Warnings...
avr-gcc.exe -mmcu=atmega128 -Wall -gdwarf-2 -Os -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT Test_Serial.o -MF dep/Test_Serial.o.d -c ../Test_Serial.c
../Test_Serial.c: In function 'init':
../Test_Serial.c:160: error: 'UCSRA' undeclared (first use in this function)
../Test_Serial.c:160: error: (Each undeclared identifier is reported only once
../Test_Serial.c:160: error: for each function it appears in.)
../Test_Serial.c:161: error: 'UCSRB' undeclared (first use in this function)
../Test_Serial.c:162: error: 'UCSRC' undeclared (first use in this function)
../Test_Serial.c:163: error: 'UBRRL' undeclared (first use in this function)
../Test_Serial.c: In function 'chgetchar':
../Test_Serial.c:193: error: 'UCSRB' undeclared (first use in this function)
../Test_Serial.c:194: error: 'UCSRA' undeclared (first use in this function)
../Test_Serial.c:195: error: 'UDR' undeclared (first use in this function)
../Test_Serial.c: In function 'chputchar':
../Test_Serial.c:200: error: 'UCSRB' undeclared (first use in this function)
../Test_Serial.c:201: error: 'UCSRA' undeclared (first use in this function)
../Test_Serial.c:203: error: 'UDR' undeclared (first use in this function)
make: *** [Test_Serial.o] Error 1
Build failed with 12 errors and 0 warnings...


achja und noch das Makefile



################################################## #############################
# Makefile for the project Test_Serial
################################################## #############################

## General Flags
PROJECT = Test_Serial
MCU = atmega128
TARGET = Test_Serial.elf
CC = avr-gcc.exe

## Options common to compile, link and assembly rules
COMMON = -mmcu=$(MCU)

## Compile options common for all C compilation units.
CFLAGS = $(COMMON)
CFLAGS += -Wall -gdwarf-2 -Os -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d

## Assembly specific flags
ASMFLAGS = $(COMMON)
ASMFLAGS += $(CFLAGS)
ASMFLAGS += -x assembler-with-cpp -Wa,-gdwarf2

## Linker flags
LDFLAGS = $(COMMON)
LDFLAGS += -Wl,-Map=Test_Serial.map


## Intel Hex file production flags
HEX_FLASH_FLAGS = -R .eeprom

HEX_EEPROM_FLAGS = -j .eeprom
HEX_EEPROM_FLAGS += --set-section-flags=.eeprom="alloc,load"
HEX_EEPROM_FLAGS += --change-section-lma .eeprom=0 --no-change-warnings


## Objects that must be built in order to link
OBJECTS = Test_Serial.o

## Objects explicitly added by the user
LINKONLYOBJECTS =

## Build
all: $(TARGET) Test_Serial.hex Test_Serial.eep Test_Serial.lss size

## Compile
Test_Serial.o: ../Test_Serial.c
$(CC) $(INCLUDES) $(CFLAGS) -c $<

##Link
$(TARGET): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) $(LINKONLYOBJECTS) $(LIBDIRS) $(LIBS) -o $(TARGET)

%.hex: $(TARGET)
avr-objcopy -O ihex $(HEX_FLASH_FLAGS) $< $@

%.eep: $(TARGET)
-avr-objcopy $(HEX_EEPROM_FLAGS) -O ihex $< $@ || exit 0

%.lss: $(TARGET)
avr-objdump -h -S $< > $@

size: ${TARGET}
@echo
@avr-size -C --mcu=${MCU} ${TARGET}

## Clean target
.PHONY: clean
clean:
-rm -rf $(OBJECTS) Test_Serial.elf dep/* Test_Serial.hex Test_Serial.eep Test_Serial.lss Test_Serial.map


## Other dependencies
-include $(shell mkdir dep 2>/dev/null) $(wildcard dep/*)



ich danke auf jedenfall schon mal für die Hilfe

sternst
13.08.2008, 11:19
ich hab keinen Mega8 sondern ne Mega32 hier im Einsatz und entsprechendes natürlich auch angegeben

MCU = atmega128

PS: uwegw hatte dann also doch Recht.
Damit stimmt dann deine eine Aussage aber nicht, denn du bekommst mit Sicherheit diese Fehler auch, wenn du signal.h verwendest.

HannoHupmann
13.08.2008, 12:30
ok möglich, so genau weis ich es nimmer. Die Frage für mich ist viel mehr, was kann ich tun damit der Code trotzdem funktioniert. Sprich wo muss ich den Code ändern um diesen auf meinen Mega32 anzupassen.

sternst
13.08.2008, 12:47
Du musst zuerst mal das Makefile ändern.

uwegw
13.08.2008, 16:35
Der M128 hat zwei uarts, daher haben die ganzen Register noch ne Nummer dahinter.... aber wenn ich im makefile den M32 angebe, kann ichs imemr noch einwandfrei kompilieren.

HannoHupmann
14.08.2008, 11:46
mhm dann ist wohl irgendwas "verstellt" bei mir und ich weis leider nicht was und wo ich es entsprechen zurück stellen kann. Ich kann doch nur den Chip beim der Projekt erstellung auswählen und da müsste ich Mega32 haben. Helfen würde mir auch, wenn es nicht nur immer die Bröckchen wären die mir hingeworfen werden. Aber ich bin ja schon dankbar für jede Hilfe :-)

sternst
14.08.2008, 12:59
Helfen würde mir auch, wenn es nicht nur immer die Bröckchen wären die mir hingeworfen werden.

Ach ja, ist doch immer "schön", wenn sich Leute beschweren, dass die Hilfe nicht ausführlich genug ist. So nach dem Motto:
"Gebt mir keine Denkanstöße, sondern löst das Problem gefälligst komplett für mich."

Außerdem ist das Einstellen des korrekten µC-Typs so elementar (und auch nicht wirklich schwer zu finden), dass ich schlicht immer davon ausgehe, dass das jeder, der das AVR-Studio benutzt, kann. Man kann doch nicht jedesmal, wenn der genaue Kenntnisstand des Fragenden nicht bekannt ist, automatisch alles bei Null angefangen erklären. Da würde man dann ja etliches unnötigerweise schreiben.

Also:

Project -> Configuration Options -> Device

Und dann auch gleich darauf achten, dass kein Häkchen bei "Use External Makefile" ist. Es sei denn natürlich, du willst/musst ein vorgegebenes Makefile verwenden, dann musst du aber auch die Änderung des µC-Typs direkt im Makefile vornehmen.

HannoHupmann
15.08.2008, 08:17
@Sternst, ich weis solche Kritik darf man nicht äußern und ich habs trotzdem getan. Ich hab aber schon erwähnt, dass ich mich in dem Bereich (noch) nicht besonders auskenne und dann hilft ein Denkanstoss leider nicht viel. Ich hoffe dir ist jetzt kein Zacken aus der Krone gefallen, weil du ein bischen mehr geschrieben hast und auch ein Anfänger wie ich es versteht.
Ich hab aber nicht nur aus reinem Eigennutz nochmal nachgefragt. Der Beitrag hier ist in der RN-Wiki verlinkt und es ist gut möglich, dass andere Anfänger darüber stolpern und die freuen sich jetzt auch über deine ausführlichere Erklärung.

Was für euch der AVR, ist für mich die Mechanik und in den Beiträgen, geb ich auch ausführliche Hilfestellungen und werf auch möglichst nicht nur ein: "das hält nicht" oder "das geht nicht" hin sondern versuch auch gleich ne Lösung mit zu geben.

Ich hab mich jetzt auf jedenfall gefreut und hoffe auf weitere gute zusammenarbeit.

PS: Jetzt funktioniert es auch wieder mit dem Compilieren.

sternst
15.08.2008, 11:54
Ich hoffe dir ist jetzt kein Zacken aus der Krone gefallen, weil du ein bischen mehr geschrieben hast
Danke auch. Es geht nicht darum, dass ich faul wäre, sondern darum, dass ich ja nicht riechen kann, was genau du alles nicht weißt.

Wenn du jemanden was mechanisches erklärst, und darin taucht der Terminus "festschrauben" auf, dann beinhaltet deine Erklärung sicherlich auch nicht automatisch eine Erklärung, welches Werkzeug er für welche Schraube braucht, und wie man es benutzt. Du setzt es als Grundwissen voraus und erklärst es nur bei Bedarf (also bei konkreter Nachfrage).
Und genau so ist es hier. Das Einstellen des µC-Typs ist elementares Grundwissen bei der AVR-Studio-Benutzung. Wenn jemand schreibt "ich benutze AVR-Studio", dann setze ich voraus, dass er das schon weiß und erkläre es daher nur bei Bedarf.
Das als "Bröckchen hinwerfen" zu bezeichnen, finde ich reichlich unangebracht.

HannoHupmann
15.08.2008, 14:50
@strernst gut dann nehm ich das zurück, ich will hier auf keinen Fall böses Blut erzeugen.

(wenn mich jemand dann aber fragt wie ich das mit "festschrauben" meine, bin ich mich nicht zu schade es ihm auch zu erklären, aber das war ja hier auch so).

HannoHupmann
27.08.2008, 15:42
Der Code lässt sich, wie schon geschrieben, problemlos kompelieren. Leider bekomm ich das mit der RS232 Schnittstelle trotzdem nicht hin. D.h. ich kann den Code aufspielen aber eine Verbindung über Terminal bekommen ich trotzdem nicht mit dem PC.

HannoHupmann
23.09.2008, 16:28
Nochmal eine Frage dazu, ich hab gerade versuche die Servos aus dem Programm anzusteuer, aber ich bekomm den Port C nicht zum laufen, bzw. die Servos die ich dort anschliesse wollen nicht wackeln.
Ich vermute ich muss noch irgendwo einen Interrupt frei schalten oder aktivieren, weis aber leider nicht wo.
Kann mir bitte jemand helfen?

Achja und wie kann ich die Code auf 11 Servos erweitern?

sternst
23.09.2008, 17:07
aber ich bekomm den Port C nicht zum laufen
JTAGEN Fuse kontrollieren (muss aus sein).

HannoHupmann
23.09.2008, 18:04
@Sternst danke das wars, ich hatte nämlich letzte woche nen neuen Mega32 eingebaut und der hatte noch die alten Fuses und nicht wie der vorgänger die neuen. Nur an sowas hab ich mich nimmer erinnert.

Bleibt die Frage wie ich den Code auf 11 Servos erweitern kann :-)

uwegw
23.09.2008, 18:28
Die Beschränkung auf 10 Servos kommt daher, dass die Steuerinmpulse 1 bis 2ms lang sind, und im 20ms-Rhythmus wiederholt werden. Es werden daher die einzelnen Impulse nacheinander ausgegeben, und nach zehn Impulsen mit Maximallänge + Pause ist man automatisch bei dem 20ms.

Die meisten Servos sehen das mit den 20ms aber nicht allzu eng. Du könntest also erst mal versuchen, alle Arrays und Variablen von 10 auf 11 anzupassen. Die Neutrallage der übrigen Servos könnte sich minimal verschieben, aber ansonsten stehen die Chancen gut, dass es klappt.



/************************************************** **********************

SERVO Controller for up to 10 Servos

controlled by serial line
default: 2400 Baud 8N1

Processor: ATMEGA 8
CLOCK: 8MHZ, no prescaler set config bits of Atmega 8 correctly !

Compiler: AVR-GCC


This code is licensed under the GPL.
You may modify, redistribute the code .. blabla, you know what I mean ...

Copyright stochri (c.hab@gmx.net) Nov.2005

Warnungen beiseitigt von uwegw

************************************************** *************************/
#include <stdlib.h>
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>

typedef unsigned char byte;

#define SYSCLK 8000000 // timer clock 8Mhz
#define MAXPULSFREQ 500 // 2ms => 500HZ

#define TIMER_MAXPULS SYSCLK/MAXPULSFREQ // Timer1 value for a 2ms Puls

#define MINPULS TIMER_MAXPULS/4 // min pulslength = 0.5ms
#define MAXPULS TIMER_MAXPULS // max pulslength=2ms

// port pin definitions
// you may redefine the pins to suit your application
// tale a look at the interrupt routine and enable the cases for your servo

#define LOW_SERVO0 PORTD&=~(1<<6)
#define HIGH_SERVO0 PORTD|=(1<<6)

#define LOW_SERVO1 PORTB&=~(1<<0)
#define HIGH_SERVO1 PORTB|=(1<<0)

#define LOW_SERVO2 PORTB&=~(1<<1)
#define HIGH_SERVO2 PORTB|=(1<<1)

#define LOW_SERVO3
#define HIGH_SERVO3

#define LOW_SERVO4
#define HIGH_SERVO4

#define LOW_SERVO5
#define HIGH_SERVO5

#define LOW_SERVO6
#define HIGH_SERVO6

#define LOW_SERVO7
#define HIGH_SERVO7

#define LOW_SERVO8
#define HIGH_SERVO8

#define LOW_SERVO9
#define HIGH_SERVO9


uint16_t Pulslength[22]; // !!! // array for all delays

/************************************************** **********************

SIGNAL(SIG_OVERFLOW1)
timer1 interrupt, generates the high and low pulses for each servo

************************************************** *************************/
SIGNAL(SIG_OVERFLOW1)
{
static byte servoindex_half=0;

switch (servoindex_half)
{
case 0: HIGH_SERVO0; break;
case 1: LOW_SERVO0; break;
case 2: HIGH_SERVO1; break;
case 3: LOW_SERVO1; break;
case 4: HIGH_SERVO2; break;
case 5: LOW_SERVO2; break;
// case 6: HIGH_SERVO3; break;
// case 7: LOW_SERVO3; break;
// case 8: HIGH_SERVO4; break;
// case 9: LOW_SERVO4; break;
// case 10: HIGH_SERVO5; break;
// case 11: LOW_SERVO5; break;
// case 12: HIGH_SERVO6; break;
// case 13: LOW_SERVO6; break;
// case 14: HIGH_SERVO7; break;
// case 15: LOW_SERVO7; break;
// case 16: HIGH_SERVO8; break;
// case 17: LOW_SERVO8; break;
// case 18: HIGH_SERVO9; break;
// case 19: LOW_SERVO9; break;
// case 20: HIGH_SERVO10; break; // !!!
// case 21: LOW_SERVO10; break; // !!!
}


TCNT1 =Pulslength[servoindex_half]; // set time for next interrupt

servoindex_half++; // increment timervalue index
if(servoindex_half==22)servoindex_half=0; // reset index /!!!
}
/************************************************** **********************

void setservo(byte index, byte value)

Set servo position
value: 0..255

************************************************** *************************/

void setservo(byte index, byte value)
{
uint16_t wert;

wert=MINPULS+(MAXPULS-MINPULS)/256*value;

// callculate hightime
Pulslength[index<<1]=0-wert;

// sume of low and hightime for one servo is 2ms
Pulslength[(index<<1)+1]=0-(TIMER_MAXPULS-wert);

// 1 servos give you 1*2ms=22ms total cycle time /!!!
}

/************************************************** **********************

void init_servos()

initialize all servos to the start position
************************************************** *************************/
void init_servos(void)
{
byte n;
for(n=0;n<11;n++) setservo(n,128); //!!!
}

/************************************************** **********************

void init(void)
initialize the prozessor registers
************************************************** *************************/

void init(void)
{
// prepare RS232
UCSRA = 0x00;
UCSRB = 0x00;
UCSRC = 0x86; // No Parity | 1 Stop Bit | 8 Data Bit
UBRRL = 0xCF; // 2400bps @ 8.00MHz
// UBRRL = 51; // 9600bps @ 8.00MHz
// UBRRL = 25; // 19200bps @ 8.00MHz

/* initialize ports */
DDRB = 0xFF;
DDRC = 0xFF;
DDRD = 0xFF;
PORTB = 0x00;
PORTC = 0x00;
PORTD = 0x00;

// init timer1
TCNT1 = 0-16000;
TCCR1A=0;
TCCR1B=0x01;
TIMSK |= _BV(TOIE2) | _BV(TOIE1);

/* allow interrupts */
sei();
}

/************************************************** **********************

serial communication

************************************************** *************************/

byte chgetchar(void)
{
UCSRB = 0x10; // enable receiver
while(!(UCSRA & 0x80)); // wait for received byte
return UDR;
}

void chputchar(byte zeichen)
{
UCSRB = 0x08; // enable transmitter
UCSRA|=0x40; // clear transmitter flag
while (!(UCSRA & 0x20)); // wait for empty transmit buffer
UDR = zeichen;
while (!(UCSRA & 0x40)); // Wait for transmit complete flac (TXC)
}
void chSerPrint(char *data)
{
unsigned char i = 0;
while(data[i]!=0x00) chputchar(data[i++]);
}

/************************************************** **********************

main programm

servo controll by RS232 interface

************************************************** *************************/

int main(void)
{
char c;
byte n;
byte servos[10];

init();
init_servos();

chSerPrint("\n\r-- Atmega8 servo controller V1.0 --\n\r");
chSerPrint("Connection OK\n\r");

while(1)
{

// get key from terminal
c=chgetchar();

if(c=='q') servos[0] += 10;
if(c=='w') servos[0] -= 10;
if(c=='a') servos[1] += 10;
if(c=='s') servos[1] -= 10;
if(c=='y') servos[2] += 10;
if(c=='x') servos[2] -= 10;

// set to default position, if space is pressed
if(c==' ')
{
servos[0] = 128;
servos[1] = 128;
servos[2] = 128;
}

for(n=0;n<11;n++) setservo(n,servos[n]); //!!!
}
}

Kompilert einwandfrei, habs allerdings nicht testen können. Die Änderungen habe ich mit //!!! markiert. Könnte sein, dass ich noch was übersehen habe...

HannoHupmann
02.12.2008, 11:34
Gibt es eigentlich noch eine einfache Möglichkeit, den Code so zu erweitern, dass sich die Geschwindigkeit der Servos regeln lässt? Ich möchte meine Servos nicht immer mit maximaler Geschwindigkeit laufen lasen, sondern auch mal langsam anfahren und stoppen (Massenträgheit und sowas).

Maquis.
10.12.2008, 12:04
Habe den Code jetzt selber auf meinem Atmega8 getestet, kompilieren lässt er sich ohne Probleme, der gewünschte Effekt wurde jedoch nicht erzielt.

Möchte einfach nur zu Testzwecken 2 Servos ansteuern, egal welche Position.
Der Servo bewegt sich jedoch immer nur in eine Richtung bis zum Anschlag. Bei meinen Messungen habe ich gemerkt das ich ein durchgehendes Signal bekomme und keine 1-2ms Signale.

Wenn ich im AVR Studio debugge wird immer nur "SIGNAL(SIG_OVERFLOW1)" durchlaufen, "setservo(X,X)" eigentlich nie...

In der Makefile habe ich die 8Mhz angegeben, sprich "-DF_CPU=8000000UL" und bei den Fuses muss ich ja glaube ich keine großen Änderungen vornehmen, verwenden den "Int. RC Osc. 8 MHz; Start-up time: 6 CK + 0 ms".

Hier der Code, freue mich über jede Hilfe.



/************************************************** **********************

SERVO Controller for up to 10 Servos

Processor: ATMEGA 8

************************************************** *************************/
#define F_CPU 8000000UL

#include <stdlib.h>
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>

typedef unsigned char byte;

#define SYSCLK 8000000 // timer clock
#define MAXPULSFREQ 500 // 2ms 4Mhz => 1024HZ

#define TIMER_MAXPULS SYSCLK/MAXPULSFREQ // Timer1 value for a 2ms Puls

#define MINPULS TIMER_MAXPULS/4 // min pulslength = 0.5ms
#define MAXPULS TIMER_MAXPULS // max pulslength=2ms

// port pin definitions

#define LOW_SERVO0 PORTD&=~(1<<2)
#define HIGH_SERVO0 PORTD|=(1<<2)

#define LOW_SERVO1 PORTB&=~(1<<1)
#define HIGH_SERVO1 PORTB|=(1<<1)

#define LOW_SERVO3
#define HIGH_SERVO3

#define LOW_SERVO4
#define HIGH_SERVO4

#define LOW_SERVO5
#define HIGH_SERVO5

#define LOW_SERVO6
#define HIGH_SERVO6

#define LOW_SERVO7
#define HIGH_SERVO7

#define LOW_SERVO8
#define HIGH_SERVO8

#define LOW_SERVO9
#define HIGH_SERVO9

uint16_t Pulslength[20]; // array for all delays

/************************************************** **********************

SIGNAL(SIG_OVERFLOW1)
timer1 interrupt, generates the high and low pulses for each servo

************************************************** *************************/
SIGNAL(SIG_OVERFLOW1)
{
static byte servoindex_half=0;

switch (servoindex_half)
{
case 0: HIGH_SERVO0; break;
case 1: LOW_SERVO0; break;
case 2: HIGH_SERVO1; break;
case 3: LOW_SERVO1; break;
// case 4: HIGH_SERVO2; break;
// case 5: LOW_SERVO2; break;
// case 6: HIGH_SERVO3; break;
// case 7: LOW_SERVO3; break;
// case 8: HIGH_SERVO4; break;
// case 9: LOW_SERVO4; break;
// case 10: HIGH_SERVO5; break;
// case 11: LOW_SERVO5; break;
// case 12: HIGH_SERVO6; break;
// case 13: LOW_SERVO6; break;
// case 14: HIGH_SERVO7; break;
// case 15: LOW_SERVO7; break;
// case 16: HIGH_SERVO8; break;
// case 17: LOW_SERVO8; break;
// case 18: HIGH_SERVO9; break;
// case 19: LOW_SERVO9; break

}


TCNT1 =Pulslength[servoindex_half]; // set time for next interrupt

servoindex_half++; // increment timervalue index
if(servoindex_half==20)servoindex_half=0; // reset index
}
/************************************************** **********************

void setservo(Set servo position, value: 0..255)

************************************************** *************************/

void setservo(byte index, byte value)
{
uint16_t wert;

wert=MINPULS+(MAXPULS-MINPULS)/256*value;

// callculate hightime
Pulslength[index<<1]=0-wert;

// sume of low and hightime for one servo is 2ms
Pulslength[(index<<1)+1]=0-(TIMER_MAXPULS-wert);

// 10 servos give you 10*2ms=20ms total cycle time
}

void init_servos() //initialize all servos to the start position
{
setservo(0,128);
setservo(1,128);
}

/************************************************** **********************

void init(void)
initialize the prozessor registers

************************************************** *************************/

void init(void)
{

// init timer1
TCNT1 = 0-16000;
TCCR1A=0;
TCCR1B=0x01;
TIMSK |= _BV(TOIE2) | _BV(TOIE1);

/* allow interrupts */
sei();
}

/************************************************** **********************

main programm

************************************************** *************************/

int main(void)
{
byte servos[2];

init();
init_servos();

while(1)
{

servos[0] = 20;
servos[1] = 130;

setservo(0,servos[0]);
setservo(1,servos[1]);
}
}

Somebuddy
11.05.2009, 10:51
Vielen Dank erstmal für den Code ;)

Habe ihn mal auf meine bedürfnisse gekürzt ;)




/************************************************** **********************

SERVO Controller for up to 10 Servos

controlled by serial line
default: 2400 Baud 8N1

Processor: ATMEGA 8
CLOCK: 8MHZ, no prescaler set config bits of Atmega 8 correctly !

Compiler: AVR-GCC


This code is licensed under the GPL.
You may modify, redistribute the code .. blabla, you know what I mean ...

Copyright stochri (c.hab@gmx.net) Nov.2005

************************************************** *************************/
#include <stdlib.h>
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>

typedef unsigned char byte;

#define SYSCLK 8000000 // timer clock 8Mhz
#define MAXPULSFREQ 500 // 2ms => 500HZ

#define TIMER_MAXPULS SYSCLK/MAXPULSFREQ // Timer1 value for a 2ms Puls

#define MINPULS TIMER_MAXPULS/4 // min pulslength = 0.5ms
#define MAXPULS TIMER_MAXPULS // max pulslength=2ms

// port pin definitions
// you may redefine the pins to suit your application
// tale a look at the interrupt routine and enable the cases for your servo

#define LOW_SERVO0 PORTA&=~(1<<4)
#define HIGH_SERVO0 PORTA|=(1<<4)

#define LOW_SERVO1 PORTA&=~(1<<5)
#define HIGH_SERVO1 PORTA|=(1<<5)

#define LOW_SERVO2 PORTA&=~(1<<6)
#define HIGH_SERVO2 PORTA|=(1<<6)

#define LOW_SERVO3 PORTA&=~(1<<7)
#define HIGH_SERVO3 PORTA|=(1<<7)

#define LOW_SERVO4
#define HIGH_SERVO4

#define LOW_SERVO5
#define HIGH_SERVO5

#define LOW_SERVO6
#define HIGH_SERVO6

#define LOW_SERVO7
#define HIGH_SERVO7

#define LOW_SERVO8
#define HIGH_SERVO8

#define LOW_SERVO9
#define HIGH_SERVO9


uint16_t Pulslength[20]; // array for all delays

/************************************************** **********************

SIGNAL(SIG_OVERFLOW1)
timer1 interrupt, generates the high and low pulses for each servo

************************************************** *************************/
SIGNAL(SIG_OVERFLOW1)
{
static byte servoindex_half=0;

switch (servoindex_half)
{
case 0: HIGH_SERVO0; break;
case 1: LOW_SERVO0; break;
case 2: HIGH_SERVO1; break;
case 3: LOW_SERVO1; break;
case 4: HIGH_SERVO2; break;
case 5: LOW_SERVO2; break;
case 6: HIGH_SERVO3; break;
case 7: LOW_SERVO3; break;
// case 8: HIGH_SERVO4; break;
// case 9: LOW_SERVO4; break;
// case 10: HIGH_SERVO5; break;
// case 11: LOW_SERVO5; break;
// case 12: HIGH_SERVO6; break;
// case 13: LOW_SERVO6; break;
// case 14: HIGH_SERVO7; break;
// case 15: LOW_SERVO7; break;
// case 16: HIGH_SERVO8; break;
// case 17: LOW_SERVO8; break;
// case 18: HIGH_SERVO9; break;
// case 19: LOW_SERVO9; break;
}


TCNT1 =Pulslength[servoindex_half]; // set time for next interrupt

servoindex_half++; // increment timervalue index
if(servoindex_half==20)servoindex_half=0; // reset index
}
/************************************************** **********************

void setservo(byte index, byte value)

Set servo position
value: 0..255

************************************************** *************************/

void setservo(byte index, byte value)
{
uint16_t wert;

wert=MINPULS+(MAXPULS-MINPULS)/256*value;

// callculate hightime
Pulslength[index<<1]=0-wert;

// sume of low and hightime for one servo is 2ms
Pulslength[(index<<1)+1]=0-(TIMER_MAXPULS-wert);

// 10 servos give you 10*2ms=20ms total cycle time
}

/************************************************** **********************

void init_servos()

initialize all servos to the start position
************************************************** *************************/
void init_servos()
{
byte n;
for(n=0;n<10;n++) setservo(n,128);
}

/************************************************** **********************

void init(void)
initialize the prozessor registers
************************************************** *************************/

void init(void)
{


/* initialize ports */
DDRA = 0xFF;

PORTA = 0x00;

// init timer1
TCNT1 = 0-16000;
TCCR1A=0;
TCCR1B=0x01;
TIMSK |= _BV(TOIE2) | _BV(TOIE1);

/* allow interrupts */
sei();
}



/************************************************** **********************

main programm

servo controll by RS232 interface

************************************************** *************************/

int main(void)
{
char c;
byte n;
byte servos[10];

init();
init_servos();



while(1)
{






servos[0] = 128;
servos[1] = 100;
servos[2] = 128;
servos[3] = 128;

for(n=0;n<10;n++) setservo(n,servos[n]);
}
}




jetzt funktionieren die Servos allerdings nur sollange ich den befehl servos[0..3] in der while(1) schleife lasse. :(

wie schaffe ich es mit hilfe dieses codes aus meinem eigentlich hauptprogramm herraus die servos zu steuern.. sodass er nicht immer in der while schleife hängen muss !? oder ist das mit diesem code nicht ohne weiteres möglch ?

also das ich in meinem hauptprogramm nur einen befehl wie servo[5]=255 oder ähnlich ausgeben muss der rest von allein passiert ich es also nicht in eine endlosschleife packen muss...

das wäre das erste problem.
Es läuft im Moment auf meinem Atmega32 mit 8 Mhz.
Würde es gerne auf 16Mhz portieren.. schaffe es aber leider nicht :(
habe schon mit den werten experimentiert. aber es läuft leider nicht.. vielleicht habt ihr ja einen tipp für einen anfänger.

danke :)

mws-h
16.12.2009, 15:06
Hallo Leute,

ich muss diesen Beitrag noch mal hoch holen, denn ich kämpfe grade mit den gleichen Problemen wie Somebuddy.

Auch ich habe einen Mega32 mit 16MHz der einen Servocontroller ergeben soll und bekomme den Code nicht richtig ans fliegen.

Weiterhin soll das Board Daten vom UART entgegennehmen mit den Befehlen für die Servos und dann soll er noch die Schritte der Servos berechnen, und zwar so, dass alle Servos zum gleicne Zeitpunkt am Ziel ankommen, egal wie viele Impulse sie dafür benötigen.

Beispiel: Servo 1 soll 200 Schritte machen, Servo 2 nur 50 Schritte also muss das so aufgeteilt werden, dass Servo 2 nur alle 4 Schritte von Servo1 einen Schritt macht.

Wenn ich mir die Routine in der ISR so ansehe, dann bleibt für solche Dinge irgendwie gar keine Zeit mehr zumal die Daten der Seriellen Schnittstelle ja auch mit Interrupts arbeiten und ggf noch Berechnungen ausgeführt werden müssen.

mws

Besserwessi
16.12.2009, 15:42
Irgendwie paßt das nicht zusammen: Servos und Schrittmotoren. Die normalen Modelbauservos haben keine schritte, sondern arbeiten mit einer analogen Positionsrückmeldung. Schritte gäbe es bei Servomotoren, also Motoren mit Drehgeben die so geregelt werden. Da kann es schon mal Passieren das ein µC nur 1-2 Motoren schaft.

Wenn das Program gut gemacht ist, können viele Dinge gleichzeitig gehen. Es können also durch aus mehrere Interrupts aktiv sein. Solange die einzelenen ISRs schnell bleiben kann das recht gut gehen. Etwas Planung gehört aber dazu.

Das Schwierigste dürfte das reagieren auf die Befehle per UART. HIer kommen die Bytes ja einzeln. Man muß erstmal die Daten nur puffern und kann dann erst reagieren wenn der Befehl vollständig übertragen sind. Dazwischen muß man die ISR immer wieder beenden.

mws-h
16.12.2009, 15:58
OK, es sind keine wirklichen Schritte wie bei Schrittmotoren aber es gibt nur eine endliche Zahl an Positionen die mit einem Controller erzeugt werden. Diese kann man als "Schritte" bezeichnen. Elektor hate mal so ein Projekt aber in Forth geschrieben :-(

Wenn ich mir die ISR für die Servos so anschaue, dann sind die nicht wirklich kurz. Da muss es doch noch was anderes geben.

Und das mit dem Puffern hatte ich mir auch so gedacht. So lange puffern bis ein "CR" gesendet wird und dann die Verarbeitung des Strings durchführen. (In Bascom wird das auch so gemacht und das gefiel mir gut.)

mwsh

Besserwessi
16.12.2009, 16:35
Die Servos sind eher geächliche Motoren. Da sollte die Rechenzeit nicht so knapp werden. Wenn man mehr als 2 Servos hat, erzeugt man die pulse ohnehin am besten in einem Interrupt. Dann muß man schon aufpassen das keine andere ISR zu lange braucht. Das wäre hier vor allem die UART. Da sollte man in der ISR also nur das aller nötigste tun. Vermutlich also so etwas wie ein Puffer zum einlesen, mehr nicht.

Das anpassen der sollpositionen kann man dann syncron mit den Servopulsen machen, also z.B. dann wenn man ohnehin die Pause zum auffüllen auf 10-20 ms macht. Das könnte dann sogar in der ISR passieren, denn da läuft dann ja gerade nichts wirklich Zeitkritisches, nur die UART. Fürs Haupt programm wäre dann die Befehlserkennung und das berechnen der Geschwindigkteiten übrig.
Da sollte man nichtmal die volle Geschwindigkeit des µc brauchen. Wenn man sich wirklich anstrengt, wäre vermutlich 1 MHz ausreichend, unter 100 kHz wird aber schwierig wegend er Auflösung.

mws-h
16.12.2009, 20:31
Na ich bin mal gespannt, ob ich das alles so hin bekomme :-)

Aber die frage mit dem Programm für einen 16MHz Mega32 bleibt im Raum stehen.

Wobei ich jetzt festgestellt habe, dass das Programm läuft aber die Servos drehen nur max 90 Grad obwohl sie eigentlich 180 Grad drehen können wie in Tests mit z.B. Bascom ermittelt.

Woran kann das liegen?

Ach ja, meine Einstellungen:


#define SYSCLK 16000000 // timer clock 8Mhz
#define MAXPULSFREQ 500 // 2ms => 500HZ

#define TIMER_MAXPULS SYSCLK/MAXPULSFREQ // Timer1 value for a 2ms Puls

#define MINPULS TIMER_MAXPULS/4 // min pulslength = 0.5ms
#define MAXPULS TIMER_MAXPULS // max pulslength=2ms


mws