JTAGEN Fuse kontrollieren (muss aus sein).Zitat:
aber ich bekomm den Port C nicht zum laufen
Druckbare Version
JTAGEN Fuse kontrollieren (muss aus sein).Zitat:
aber ich bekomm den Port C nicht zum laufen
@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 :-)
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.
Kompilert einwandfrei, habs allerdings nicht testen können. Die Änderungen habe ich mit //!!! markiert. Könnte sein, dass ich noch was übersehen habe...Code:/************************************************************************
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]); //!!!
}
}
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).
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.
Code:/************************************************************************
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]);
}
}
Vielen Dank erstmal für den Code ;)
Habe ihn mal auf meine bedürfnisse gekürzt ;)
Code:
/************************************************************************
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 :)
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
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.
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
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.