Servoansteuerung mit Timer (ATmega32)

OP #2629129
Lesenswert?

Hallo

ich möchte mit meinem uC ein Servo ansteuern, per Timer / Interrupt

Der Code ist folgendermaßen:
Alle 20ms wird ein Interrupt ausgelöst der dann das Signal, je nach 
Einstellung zw. 1 und 2ms lang einschaltet
1
/*
2
 * servo_timer.c
3
 *
4
 * Created: 09.04.2012 22:13:40
5
 *  Author: Thomas
6
 */ 
7

8
///////////////////////////////////////////////////////////////////
9
//
10
// Servo Steuerung mit Timer / Interrupts
11
//
12
///////////////////////////////////////////////////////////////////
13

14
#ifndef F_CPU
15
  #define F_CPU 16000000      //CPU Taktfrequenz
16
#endif
17

18
#define PWM_MIN 1000        //Min. PWM Zeit in US
19
#define PWM_NULL 1500        //Neutralposition - PWM Zeit in US
20
#define PWM_MAX  2000        //Max- PWM Zeit in US
21
#define PWM_LOOP 10          //Signal Widerholungen
22

23
#include <avr/io.h>
24
#include <avr/interrupt.h>
25
#include "rncontrol.h"
26

27
int pwm_time=PWM_NULL;              //Globale Variable für PWM HIGH Time
28

29
int main(void)
30
{  
31
  sei();                    //Interrupts aktivieren
32
  
33
  DDRC |= 1 << PINC0;              //Status LED 1 aktivieren          
34
  PORTC &= ~(1<<PINC0);
35
  
36
  TCCR1B |= 1<<CS11 | 1<<WGM12;        //Prescaler: -> 50Hz
37
  OCR1A =  0x9C40;                 //Prescaler Settings
38
  TIMSK |= 1<<OCIE1A;              
39
  
40
  DDRB |= 1<<PINB0;              //Ausgang für Servo aktivieren
41
  
42

43
    while(1)
44
    {
45
        if (button()==1)
46
      pwm_time=PWM_MAX;
47
    else if(button()==2)
48
      pwm_time=PWM_NULL;
49
    else if(button()==3)
50
      pwm_time=PWM_MIN;
51
      
52
    
53
    }
54
}
55

56
ISR(TIMER1_COMPA_vect)      //ISR für Servo PWM - durch Timerinterrupt kann während den ca. 20 ms Wartezeit etwas anderes gemacht werden
57
{
58
  int i;
59
  
60
  PORTC ^= 1<<PINC0;
61
  
62
  PORTB |= 1<<PINB0;      //PWM HIGH Signal
63
      
64
  for(i=0;i<pwm_time;i++)
65
    _delay_us(1);      //PWM Time warten
66
        
67
  PORTB &= ~(1<<PINB0);    //PWM LOW Signal
68
        
69
}

Doch das Servo fährt nur bis zum Endanschlag und will dann noch 
weiterdrehen. Was mache ich falsch?

mfg thomas
OP #2629141
Lesenswert?

Funktioniert ohne Probleme...habs schon mit folgendem Programm getestet:
1
#include <avr/io.h>
2
#include <util/delay.h>
3

4
#define POS 1500           //1000 <--> 2000 (1500 neutral)
5

6
void main()
7
{
8
DDRB |= 1<<PIND0;
9

10
    while(1)
11
    {
12
        PORTB |= 1<<PIND0;
13
        _delay_us(POS);
14
        PORTB &= ~(1<<PIND0);
15
        _delay_ms(18);
16
    }
17
}



ok, mal versuchen ;)

mfg thomas
#2629148
Lesenswert?

>   TCCR1B |= 1<<CS11 | 1<<WGM12;        //Prescaler: -> 50Hz

Was ist das für ein Vorteiler

>  OCR1A =  0x9C40;                 //Prescaler Settings

Schreibs doch dezmal hin! Dann braucht man nicht lange umrechnen, damit 
man deine Einstellung kontrollieren kann. Oder bist du so gut im 
Hex-Rechnen?

  OCR1A = 40000;
#2629166
Lesenswert?

Thomas P. schrieb:
> Ne, hab kein Oszi :(
> Aber ja, CPU läuft mit 16 MHz

Woher weißt du das?

Mit dem Programm
Beitrag "Re: Servoansteuerung mit Timer (ATmega32)"

Nö. Wenn das hier funktioniert und du nicht die 16 Mhz in den Project 
Settings angegeben hast (was ich bezweifle, denn dann wüsstest du wo man 
den Optimizer einschaltet, ist gleich darunter), dann nicht. Dann läuft 
dein µC mit 1Mhz
#2629170
Lesenswert?

Thomas P. schrieb:
> Ja ich weiß, ich bin Anfänger....
>
> Ja, wie könnte man das sonst lösen? Denn _delay_us bzw _ms lässt keine
> variablen zu, nur konstanten und meine PWM Ausgänge am µC kann ich nicht
> verwenden, da bereits ein Motortriber verwendet wird...

Du hast noch einen 2-ten Compare Match zur Verfügung.

Aber erst mal solltest du dich darum kümmern, ob die 16Mhz tatsächlich 
stimmen. Bis jetzt hab ich da aus der Ferne noch kein Vertrauen dazu.
#2629182
Lesenswert?

Thomas P. schrieb:
> Ja, weißt eh, war mit reiner Absicht ;)
>
> Ok, aber die Interrupts kann ich dann ja auf Ausänge legen oder?

In den Interrupts kannst du dann ganz normal die Pins schalten, so wie 
du das jetzt auch machst.

In der Zwischenzeit hab ich mir im Datenblatt die Prescaler 
Einstellungen gesucht. CS11 ist ein Prescaler von 8, mit den 40000 
ergibt das die 20ms (eigentlich sollten das 39999 sein, spielt aber 
keine Rolle, die 20ms sind sowieso nicht wichtig).


Mach doch in deiner ISR erst mal einfach nur ein _delay_ms(1.5) zwischen 
den Port Operationen um zu sehen, ob die for-Schleife dir das Timing so 
weit versaut.
#2629795
Lesenswert?

Thomas P. schrieb:
> Jep...es ist die for Schleife...
> mit _delay_us(1500); fährts wunderbar in die Mitte ;)
>
> Was könntn wir da machen?

anstatt eines 1µs delays erst mal ein 10µs delay.
Dafür die Schleifenwiederholungen entsprechend reduzieren.


(Der ganze Ansatz mit dem _delay in der ISR ist nicht zielführend. Da 
kannst du dir die ganze ISR auch gleich sparen.)
#2629823
Lesenswert?

Hier

  OCR1A =  0x9C40;
  TIMSK |= 1<<OCIE1A;

hast du den Compare Match für den Compare A eingerichtet.
Jetzt schaust du ins Datenblatt, ob das für den Comparematch B genauso 
geht und rechnest dir den Wert aus für 1.5ms

Hier

ISR(TIMER1_COMPA_vect)
{

hast du für den Compare Match A die ISR eingerichtet.
Wie wird das dann wohl für Compare Match B aussehen?

In der A setzt du den Pin auf 1, in der B wieder auf 0.

Einfacher als einem Baby den Schnuller klauen.
Gast #2630179
Lesenswert?

Karl Heinz Buchegger schrieb:
> Einfacher als einem Baby den Schnuller klauen.
Das ist nicht Schnuller klauen, sondern Pferd von hinten durch's Auge 
erschießen :D

Das ist Schnuller klauen:
1
// ATMega32@16MHz
2

3
#include <avr/io.h>
4

5
int main(void)
6
{
7
  DDRD = (1<<PD5)|(1<<PD4);  // Servo 1 an PD5, Servo 2 an PD4
8
  TCCR1B = (1<<WGM13)|(1<<WGM12)|(1<<CS11);     // Prescaler 8
9
  TCCR1A = (1<<COM1A1)|(1<<COM1B1)|(1<<WGM11);  // Mode 14, ICR = Top
10
  ICR1 = 39999;     // Wiederholrate 50Hz
11
  OCR1A = 2000;     // Servoposition Servo 1, 2000 = 1.0ms
12
  OCR1B = 3000;     // Servoposition Servo 2, 3000 = 1.5ms
13
    while(1)
14
    {
15
       // Steuere Servos
16
    }
17
}
Persönliche Seite #2630308
Lesenswert?

Karl Heinz Buchegger schrieb:
> MWS schrieb:
>> Karl Heinz Buchegger schrieb:
>>> Einfacher als einem Baby den Schnuller klauen.
>> Das ist nicht Schnuller klauen, sondern Pferd von hinten durch's Auge
>> erschießen :D
>
[ ] Ich hab weiter oben gelesen, dass er die Pins nicht frei hat, ist
    mir aber Wurscht, ich geb meinen Senf trotzdem dazu.
[x] Ich habs nicht gelesen und muss mich trotzdem einbringen

Ist doch klar...
OP #2630320
Lesenswert?

Eben..Pins sind bereits belegt

Also wie soll ich das ganze angehen?
Denn so funktionierts mal nicht ;)
1
/*
2
 * servo_timer.c
3
 *
4
 * Created: 09.04.2012 22:13:40
5
 *  Author: Thomas
6
 */ 
7

8
///////////////////////////////////////////////////////////////////
9
//
10
// Servo Steuerung mit Timer / Interrupts
11
//
12
///////////////////////////////////////////////////////////////////
13

14
#ifndef F_CPU
15
  #define F_CPU 16000000      //CPU Taktfrequenz
16
#endif
17

18
#define PWM_MIN 700        //Min. PWM Zeit in US
19
#define PWM_NULL 1500        //Neutralposition - PWM Zeit in US
20
#define PWM_MAX  2300        //Max- PWM Zeit in US
21
#define PWM_LOOP 10          //Signal Widerholungen
22

23
#include <avr/io.h>
24
#include <avr/interrupt.h>
25
#include <util/delay.h>
26
#include "rncontrol.h"
27

28
volatile int pwm_time=PWM_NULL;          //Globale Variable für PWM HIGH Time
29

30
int main(void)
31
{  
32
 
33
  DDRC |= 1 << PINC0;          //Status LED 1 aktivieren          
34
  PORTC &= ~(1<<PINC0);
35
  DDRC |= 1 << PINC1;          //Status LED 2 aktivieren
36
  PORTC |= 1<< PINC1;
37
  
38
  //Timer 1 - 20ms
39
  TCCR1B |= 1<<CS11 | 1<<WGM12;      //Prescaler: -> 50Hz
40
  OCR1A =  40000;            //Prescaler Settings
41
  TIMSK |= 1<<OCIE1A;    
42
  
43
  //Timer 2 - 1.5 ms
44
  TCCR1B |= 1<<CS10 | 1<<WGM12;      //Prescaler -> 666Hz
45
  OCR1B = 24000;  
46
  TIMSK |= 1<<OCIE1B;
47
  
48
  DDRB |= 1<<PINB0;            //Ausgang für Servo aktivieren
49
  
50
  sei();                //Interrupts aktivieren
51
  
52
    while(1)
53
    {
54
        if (button()==1)
55
      pwm_time=PWM_MAX;
56
    else if(button()==2)
57
      pwm_time=PWM_NULL;
58
    else if(button()==3)
59
      pwm_time=PWM_MIN;
60
      
61
    
62
    }
63
}
64

65
ISR(TIMER1_COMPA_vect)      //ISR für Servo PWM - durch Timerinterrupt kann während den ca. 20 ms Wartezeit etwas anderes gemacht werden
66
{  
67
  PORTB |= 1<<PINB0;      //PWM HIGH Signal
68
  PORTC ^= 1<<PINC0;
69
}
70

71
ISR(TIMER1_COMPB_vect)    //ISR für Timer B
72
{
73
  PORTB &= ~(1<<PINB0);  //PWM LOW Signal
74
    PORTC ^= 1<<PINC1;
75
}

Das Servo tickert nur, bewegt sich aber nicht

mfg thomas
Gast #2630321
Lesenswert?

Karl Heinz Buchegger schrieb:
> [ ] Du hast weiter oben gelesen, dass er die Pins nicht frei hat

Nein, war versteckt, tatsächlich nicht gelesen, wäre vom Eingangspost 
her auch nicht davon ausgegangen. Die OC1A..B hängen am LM298 und dienen 
dort zur PWM-Steuerung, Timer1 wäre also nicht verfügbar, sollte man die 
vernünftig nutzen wollen.

> [X] Ich habs nicht gelesen und muss mich trotzdem einbringen

Hab' ich doch gern gemacht :D
#2630345
Lesenswert?

> //Timer 1 - 20ms
  TCCR1B |= 1<<CS11 | 1<<WGM12;      //Prescaler: -> 50Hz
  OCR1A =  40000;            //Prescaler Settings
  TIMSK |= 1<<OCIE1A;

  //Timer 2 - 1.5 ms
  TCCR1B |= 1<<CS10 | 1<<WGM12;      //Prescaler -> 666Hz
  OCR1B = 24000;



Ähm. Du hast da was falsch verstanden.
Du hast nur EINEN Timer 1.
Der hat aber 2 Stück Compare Match Register (A und B). Wenn der 
Timerzählerstand identisch mit dem jeweiligen Compare Match Register 
ist, dann wird die ISR ausgelöst.

Zusätzlich hast du dann noch den Timer in den CTC Modus geschaltet, 
sodass er beim Compare Match A wieder bei 0 zu zählen anfängt. (Was ja 
auch in Ordnung ist)


Das ist dein Setup mit dem du arbeiten musst.
Mit dem A-Compare Match machst du dir deine 20ms und setzt den Pin auf 
1. Und irgendwann, während der Timer von 0 bis 40000 zählt, schaltet der 
Compare Match B den Pin wieder auf 0. Der Timer zählt aber weiterhin bis 
40000.
OP #2630392
Lesenswert?

Ohhh :D

Also ich hab das jetzt mal so umgesetzt:
Timersettings:
1
  //Timer Compare Match A - 20ms
2
  TCCR1B |= 1<<CS11 | 1<<WGM12;      //Prescaler: -> 50Hz
3
  OCR1A =  40000;              //Prescaler Settings
4
  TIMSK |= 1<<OCIE1A;
5
  
6
  //Timer Compare Match B - 1.5 ms
7
  TCCR1B |= 1<<CS10 | 1<<WGM12;      //Prescaler -> 666Hz
8
  OCR1B = 24000;
9
  TIMSK |= 1<<OCIE1B;

Und die Interrupts:
1
ISR(TIMER1_COMPA_vect)      //ISR für Servo PWM - durch Timerinterrupt kann während den ca. 20 ms Wartezeit etwas anderes gemacht werden
2
{  
3
  PORTB |= 1<<PINB0;      //PWM HIGH Signal
4
  PORTC ^= 1<<PINC0;
5
}
6

7
ISR(TIMER1_COMPB_vect)    //ISR für Timer B
8
{
9
  PORTB &= ~(1<<PINB0);  //PWM LOW Signal
10
    PORTC ^= 1<<PINC1;
11
}
Trotzdem tut sich nix :(
Das Servo zuckt nur herum, bewegt sich aber nicht und die LEDs blinken 
gemächlich (ca 2 - 3 Hz)

mfg thomas
Gast #2630409
Lesenswert?

Nachtrag
Der von mir gezeigte Code lässt sich übrigens problemlos umzustellen, 
hab's mal gemacht und das läuft hier mit 2 Servokanälen auf beliebigen 
Ports.

Aber ich denke einmal wenigstens Dir, Karl-Heinz, ist das aufgefallen, 
Du wolltest wohl lediglich nicht von Deinem Konzept ablenken, kein 
Problem für mich.

Karl Heinz Buchegger schrieb:
> In der A setzt du den Pin auf 1, in der B wieder auf 0.

Warum verschwendest Du einen Kanal, wenn Du ICR als Top nehmen kannst ? 
Reicht dem TO ein Kanal ?
#2630425
Lesenswert?

Thomas P. schrieb:


> Also ich hab das jetzt mal so umgesetzt:
> Timersettings:

>   //Timer Compare Match A - 20ms
>   TCCR1B |= 1<<CS11 | 1<<WGM12;      //Prescaler: -> 50Hz
>   OCR1A =  40000;              //Prescaler Settings
>   TIMSK |= 1<<OCIE1A;
>
>   //Timer Compare Match B - 1.5 ms
>   TCCR1B |= 1<<CS10 | 1<<WGM12;      //Prescaler -> 666Hz

gratuliere.
Damit sind deine 20ms zur Makulatur geworden. Und .... 1.5ms sind das 
auch nicht.

Du hast nur EINEN Timer. Also willst du den Vorteiler auch nur EINMAL 
einstellen! Der Vorteiler gehört zum Timer und nicht zum Compare Match. 
Der Compare Match schreit nur "Hier", wenn der Timer einen bestimmten 
Zählerstand erreicht hat. Aber die Compare Match Register haben nichts 
damit zu tun, wie schnell der Timer zählt.

(Jetzt ist es natürlich blöd, dass du bisher immer deinen Timer-Rechner 
zur Berechnung der Konstanten herangezogen hast. Sorry ... aber jetzt 
musst du selber ran und dir den Wert für OCR1B ausrechnen. Auf Dauer ist 
es immer besser, wenn man versteht was man da tut.)
#2630441
Lesenswert?

MWS schrieb:

> Aber ich denke einmal wenigstens Dir, Karl-Heinz, ist das aufgefallen,
> Du wolltest wohl lediglich nicht von Deinem Konzept ablenken, kein
> Problem für mich.

Spätestens nachdem ich auf die Frage nach dem Vorteiler als Antwort 
einen Link zu einem Timer-Rechner gekriegt habe, war mir klar, dass der 
TO von Timer, sagen wir mal, wenig Ahnung hat.

> Karl Heinz Buchegger schrieb:
>> In der A setzt du den Pin auf 1, in der B wieder auf 0.
>
> Warum verschwendest Du einen Kanal, wenn Du ICR als Top nehmen kannst ?
> Reicht dem TO ein Kanal ?

Keine Ahnung. Lass uns erst mal das Ding so wie es ist, über die Bühne 
bringen. Er hat schon genug damit zu tun, 2 OCR Register an einem Timer 
zu akzeptieren.
OP #2630457
Lesenswert?

Ok...das heißt...ich komm nicht mit ;)

Also wie muss ich das Ganze jetzt machen?
Also ich erzeug mit OCR1A einen Interrupt alle 20ms mit dem ich den Pin 
auf HIGH ziehe....
Und mit OCR1B einen der alle 1.5ms (1...2 ms) den Pin auf LOW legt...

also muss es so passen?
1
  //Timer Compare Match A - 20ms
2
  TCCR1B |= 1<<CS11 | 1<<WGM12;      //Prescaler: -> 50Hz
3
  OCR1A =  40000;              //Prescaler Settings
4
  TIMSK |= 1<<OCIE1A;
5
  
6
  //Timer Compare Match B - 1.5 ms
7
  OCR1B = 24000;
8
  TIMSK |= 1<<OCIE1B;

mfg thomas
#2630464
Lesenswert?

Thomas P. schrieb:

> also muss es so passen?

Ohne das ich rechne.

Wenn das ...
>   OCR1A =  40000;              //Prescaler Settings
... 20 Millisekunden sind, dann können ...
>   OCR1B = 24000;
... keine 1.5 Millisekunden sein. 24-tausend ist etwas mehr als die 
Hälfte von 40-tausend. 1.5 ist aber sicher nicht etwas mehr als die 
Hälfte von 20.

Der Timer zählt in 20 Millisekunden von 0 bis 40000. Wie weit kann er 
daher in 1.5 Millisekunden zählen? Bzw. Umgekehrt: wie weit muss er 
zählen, damit er dafür 1.5ms braucht?
#2630496
Lesenswert?

Thomas P. schrieb:
> Nja einfache Schlussrechnung:
> 20ms .... 40000
> 1.5ms ... 3000
>
> Also so läuft das Ganze ab ;)
> Und jetzt funktioniert das auch :D

Jetzt setzt du noch anstelle der 40000 die Zahl 39999 ein, dann stimmts 
auch in diesem Detail noch.

Der Timer zählt (am Beispiel '8')

 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2,

Zähl nach, wieviele Zählvorgänge wurden gemacht, um einmal von 0 bis 
wieder zur 0 zu kommen? Auch das 'Rücksetzen' von 8 auf 0 ist ein 
Zählvorgang. 9 Stück. Also immer um 1 mehr als die größte Zahl. Der 
Compare Match muss bei 39999 auslösen, damit für einmal 'Rundum' 40000 
Zählvorgänge benötigt werden. OK, der Fehler ist nicht gewaltig groß und 
wie gesagt, dem Servo sind die 20ms ziemlich Wurscht.

> Also so läuft das Ganze ab ;)

Genau so läuft das mit einem Timer. Die nächste Stufe wäre das was MWS 
vorgeschlagen hat. Die Timerhardware kann nämlich 'ihren' Pin auch ganz 
alleine ohne ISR schalten. Aber leider, leider, hast du dir die Pins mit 
denen das möglich wäre bereits anderweitig verbaut.


Nichts desto trotz hab ich das Gefühl, dass du jetzt ein bischen besser 
verstehst, was man mit einem Timer machen kann und wie man das macht.
OP #2630520
Lesenswert?

Nja, ich habs mi nicht verbaut - hab das RN Control Board, und da werden 
diese Pins schon für den Motortreiber verwendet, und den möchte ich auch 
nutzen ;)

Ja, um einiges besser :D

Wie versprochen das Programm mit Links/Mitte/Rechts Steuerung fürs RN 
Control Board:
1
/*
2
 * servo_timer.c
3
 *
4
 * Created: 09.04.2012 22:13:40
5
 *  Author: Thomas
6
 */ 
7

8
///////////////////////////////////////////////////////////////////
9
//
10
// Servo Steuerung mit Timer / Interrupts
11
//
12
///////////////////////////////////////////////////////////////////
13

14
#ifndef F_CPU
15
  #define F_CPU 16000000      //CPU Taktfrequenz
16
#endif
17

18
#define PWM_MIN 700        //Min. PWM Zeit in US
19
#define PWM_NULL 1500        //Neutralposition - PWM Zeit in US
20
#define PWM_MAX  2300        //Max- PWM Zeit in US
21

22
#include <avr/io.h>
23
#include <avr/interrupt.h>
24
#include <util/delay.h>
25
#include "rncontrol.h"
26

27
volatile int pwm_time=PWM_NULL;          //Globale Variable für PWM HIGH Time
28

29
int main(void)
30
{    
31
  //Timer Compare Match A - 20ms
32
  TCCR1B |= 1<<CS11 | 1<<WGM12;      //Prescaler: -> 50Hz
33
  OCR1A =  39999;              //Timer zählt bis da - 0 Setzung und Interrrupt - Größte Zahl - 1 weil Rücksetzung auch Zählvorgang
34
  TIMSK |= 1<<OCIE1A;            //Interrupt durh Timer 1 A
35
  
36
  //Timer Compare Match B - 1.5 ms
37
  OCR1B = 3000;              //Timer zählt bis da - Interrupt - KEINE 0 Setzung
38
  TIMSK |= 1<<OCIE1B;            //Interrupt durch Timer 1 B
39
   
40
  DDRB |= 1<<PINB0;            //Ausgang für Servo aktivieren
41
  
42
  sei();                     //Interrupts aktivieren
43
  
44
    while(1)
45
    {
46
    OCR1B = (39999/20000)*pwm_time;    //Positionsberechnung
47
    
48
        if (button()==1)
49
      pwm_time=PWM_MAX;
50
    else if(button()==2)
51
      pwm_time=PWM_NULL;
52
    else if(button()==3)
53
      pwm_time=PWM_MIN;
54
      
55
    
56
    }
57
}
58

59
ISR(TIMER1_COMPA_vect)      //ISR für Servo PWM - durch Timerinterrupt kann während den ca. 20 ms Wartezeit etwas anderes gemacht werden
60
{  
61
  PORTB |= 1<<PINB0;      //PWM HIGH Signal
62
}
63

64
ISR(TIMER1_COMPB_vect)    //ISR für Timer B
65
{
66
  PORTB &= ~(1<<PINB0);  //PWM LOW Signal
67
}

DANKE noch mal!

mfg thomas
#2630534
Lesenswert?

>  OCR1B = (39999/20000)*pwm_time;    //Positionsberechnung

Das ist schlecht.
erstens: du hast wirklich 40000 Zählvorgänge. Also musst du auch mit 
40000 rechnen.

zweitens 39999 / 20000 ergibt 1
und nicht 1.99995

d.h. bei der danach folgenden Multiplikation hast du durch die fehlenden 
Kommastellen einen gewaltigen Fehler. Wenn pwm_time den Wert 1500 hat, 
dann kommt bei deiner Rechnung 1500 raus, wo eigentlich 2999 rauskommen 
sollte!

Divisionen immer so weit es geht im Rechenprozess nach rechts 
verschieben. Dabei aber mögliche Overflows im Auge behalten! Und in 
deinem Fall: kürzen!

 ->   4 * pwm_time / 2
 ->   2 * pwm_time

das ist dann sogar insofern Spitze, weil eine Multiplikation mit 2 für 
den µC ein Klacks ist.

Bei deinen Zahlen geht sich das jetzt gut aus, denn 40000/20000 hätte 
auch eine glatte 2 ergeben. Aber bei anderen Zahlen schauts da dann 
schon schlechter aus.
Gast #2630553
Lesenswert?

Thomas P. schrieb:
> hab das RN Control Board, und da werden
> diese Pins schon für den Motortreiber verwendet, und den möchte ich auch
> nutzen ;)

Und wie machst Du das ? Denn die OC1A..B gehen an den EN-Eingänge des 
L239, damit wird offenbar die Leistungsregelung der Motoren über HW-PWM 
gemacht.

Dafür würde aber zwingend Timer1 benötigt, den Du ja jetzt anders 
verwurstet hast. Wenn Du die Leistung der Motoren noch regeln willst, 
müsstest Du also eine Soft-PWM über PD4..5 an den Motortreiber 
randengeln. Die dürfte aber anspruchsvoller und vor allem 
Leistungs-hungriger als diese Sache hier sein.
Gast #2630607
Lesenswert?

Thomas P. schrieb:
> Ich will das Programm auch sozusagen Robotertauglich machen indem ich es
> auf die 8 Bit Timer umprogrammiere - und somit sind die Pins ja wieder
> frei, oder nicht?

Das bedeutet jetzt übersetzt was ? Das Programm oben ? Bekommst Du 
direkt übersetzt nicht auf 'nen 8Bit Timer, geht allein von der 
Auflösung nicht.

Du hast 3000 für 1.5ms bei 16Bit, bei 8Bit wären's bei gleichen 
Bedingungen 3000 durch 256 gleich 12, bei 'nem theoretischen Prescaler 
von 2048. Der höchste ist 1024, damit hättest Du ca. 16 Stufen für 180 
Grad Servodrehung, bist aber mit der Wiederholrate zu schnell, die 
meisten Servos packen das. Aber dieser Ansatz wird Dich nicht glücklich 
machen.
Gast #2630636
Lesenswert?

Thomas P. schrieb:
> Direkt schon klar, aber es wird ja wohl möglich sein die ca 180° auf 128
> bzw am besten wären 256 Schritte auszudehnen, oder?

Dann versuch doch mal zu rechnen, es gibt Beschränkungen bezüglich der 
möglichen Prescaler und schau auch mal was an Wiederholrate raus kommt 
und ob Deine Servos da noch mitmachen. Das Beste, was Du direkt bekommen 
kannst sind so um die 60 Schritte bei ca. 240Hz Wiederholrate.
Gast #2630686
Lesenswert?

Nur so als Anhaltspunkt, das Konzept wie oben lässt sich auf Timer0 
umsetzen, 65 Schritte (93-125) von 1-2ms, Wiederholrate ~49Hz, Prescaler 
dazu immer während des Betriebs zwischen 256 auf 1024 umschalten. Der 
Code dazu ist noch recht einfach, also frisch an's Werk ;-)
Gast #2633590
Lesenswert?

Thomas P. schrieb:
> Wie muss ich den Code denn ungefähr aufbauen?

Setz' es halt erstmal um den Timer0 herum so auf, dass die Pulslänge 
zwischen 1-2ms bei maximal möglicher Auflösung verschoben werden kann, 
unabhängig von der Wiederholrate. Kannst ja den Code dann zeigen.

Wenn das geht, dann schaltest Du nach jedem Overflow zwischen dem von 
Dir dafür verwendeten und dem maximalen Prescaler hin und her. Wobei der 
Pin nicht in der langen Prescalerphase gesetzt werden darf.

Hab's mal gezählt, in den ISR's befinden sich gerade 7 Zeilen aktiver 
Code, ist also nix Komplexes.
Gast #2633592
Lesenswert?

MWS schrieb:
> Wenn das geht, dann schaltest Du nach jedem Overflow zwischen dem von
> Dir dafür verwendeten und dem maximalen Prescaler hin und her. Wobei der
> Pin nicht in der langen Prescalerphase gesetzt werden darf.

Man könnte auch einfach in einer Variablen die Anzahl der Umläufe 
zählen...
OP #2636592
Lesenswert?

Hallo

Ich habs endlich geschaft :)

Der Code ist im Anhang, funktioniert mit einem Servo. Das ganze reicht 
im Moment mal für meinen kleinen "Ketten-Bot". Brauch ich nur zum hin 
und her Bewegen des US Moduls
Als nächstes möchte ich mir mit Hilfe eines AVR mit vielen Timern ein 
Servo Board realisieren, von dem werdet ihr dann natürlich hören!
Welcher AVR ist dazu am Besten geeignet?

Danke für eure Hilfe!!

mfg thomas
Angehängte Dateien:
Gast #2636662
Lesenswert?

Thomas P. schrieb:
> Als nächstes möchte ich mir mit Hilfe eines AVR mit vielen Timern ein
> Servo Board realisieren, von dem werdet ihr dann natürlich hören!
> Welcher AVR ist dazu am Besten geeignet?

Der gleiche. Nur die Software sieht etwas anders aus...
Du programmierst ein Schieberegister, das bei jedem Überlauf um einen 
Schritt weiter geschaltet wird.
Dann brauchst du auch die Umschaltung der beiden Prescaler-Werte nicht 
mehr zu realisieren...
(Firma: guloshop.de) #2636683
Lesenswert?

Thomas P. schrieb:
> Als nächstes möchte ich mir mit Hilfe eines AVR mit vielen Timern ein
> Servo Board realisieren, von dem werdet ihr dann natürlich hören!
> Welcher AVR ist dazu am Besten geeignet?

Es gibt zwar ATmegas mit 3, 4 oder 6 Timern, aber ich bin nicht sicher, 
ob das der richtige Weg ist. Ich glaube, ich würde nur einen Timer 
verwenden und in dessen ISR die Pins für die Servos selbst steuern. 
Also, PWM von Hand. Das ist gar nicht sooo kompliziert und läuft dann 
auch auf den billigsten Mikrocontrollern.
(Firma: guloshop.de) #2636696
Lesenswert?

Thomas P. schrieb:
> Inwieweit von Hand?
> Sozusagen:
> if(timer == 0) {alle Pins LOW}
> if(timer >= 15000) {PIN1 LOW}
> usw...
> ??

Im Prinzip ja. Aber natürlich nur im Prinzip, sonst schreibst du dir ja 
einen Wolf. :-)
Man kann sowas über Bitmasken machen, die in einer Tabelle stehen. Oder 
über Einzelabfragen mit Wertvergleichen. Ich kenn leider deine Anwendung 
zu wenig, als dass ich dir zu einer konkreten Strategie raten könnte.
Gast #2636743
Lesenswert?

Hallo zusammen,

sorry, wenn ich einfach so anonym dazwischen funke.

@ThomasP.: Professionell ist die Lösung mit Deinem Code überhaupt nicht.

Ein atmega32 kann im FastPWM Mode ohne(!) ISR-Routine ein PWM-Signal 
selbständig erzeugen, es frisst keinerlei Rechenzeit vom normalen 
Programmablauf!

Du schaltest im Setup auf FastPWM-Mode für z.B. Timer1 und setzt:

ICR1 --> Maximum Counter(=TOP), bis hierher wird gezählt
OCR1A --> MATCH, Umschalten von high auf low
TOIE --> abschalten, Interrupt wird nicht benötigt!

Prescaling und passende Werte für TOP und MATCH mußt Du Dir natürlich 
ausrechnen.
OC1A verwendet ausschliesslich Pin PD5 (siehe Datenblatt)!

Ablauf dann:
Count von 0 bis MATCH   -> PD5 = HIGH
Count von MATCH bis TOP -> PD5 = LOW
usw.

Um den Servo links/rechts drehen zu lassen, veränderst Du im normalen 
Programmablauf einfach den MATCH in OCR1A - fertig!

Eleganter geht's nicht mehr!

Just my 2 cents ;)
Gast #2636783
Lesenswert?

Thomas P. schrieb:
> Aber welcher AVR ist am besten für ein Servo Board für ca 10 Servos
> geeignet?

"Am besten" ist immer so eine Sache. Die Steuerung mit dem 
Schieberegister ist nicht die schlechteste Idee (z.B. ATmega8 + 2x 
74HC595) oder wie wäre es mit einer Softwarelösung:
Beitrag "Servocontroller mit ATmega8 für 20 Servos"
http://www.4finger.net/cms/servomaster.html
OP #2637283
Lesenswert?

Hallo

@FastPWM:
1) Ich bin Anfänger und bin unheimlich stolz drauf gewesen, dass es so 
funktioniert hat ;)
2) Geht das nur für Timer1 odr auch für Timer0?
3) Wie soll ich das ohne ISR aufbauen?
4) Falls du es nicht gelesen, von dem ich ausgehe, bei mir ist Timer1 in 
verwendung für Motorensteuerung => somit ist auch OC1A und OC1B, also 
PD4/5 belegt

Ok, danke für die Tipps, ich werde mal Schaltplan und Grundstruktur 
anfertigen und posten!

mfg thomas
Gast #2637327
Lesenswert?

Du kannst Timer0 im FastPWM-Modus betreiben.
Ihn mit einer Spannweite von 20ms zu betreiben ist natürlich Unfug.
Wie ich oben schon beschrieben habe:
Betreibe den Timer so, dass du die 2ms am Höchsten auflöst.
Ob das Servo alle 20ms oder mehr oder weniger häufig angesprochen wird, 
war meinen Servos bis jetzt egal (je länger die Pause ist, umso 
schwächer wurde es).
Gast #2637344
Lesenswert?

Thomas P. schrieb:
> 1) keine Lust :b
Kenne ich von mir auch. Ich hab aber nicht gefragt...

> 2) Mein Programm läuft für ein Servo perfekt ;)
Bis zur ersten Erweiterung.

> 3) Bin ich im Moment nicht neugiereig drauf um auf 400 Seitn 3 Sätze rus
> zu suchen
Schon mal die Suchfunktion des Acrobat Reader's ausprobiert?
Schon mal das Inhaltverzeichnis angesehen?

Deine Entscheidung.
OP #2637407
Lesenswert?

Wieso solls dann nicht mehr funktionieren?
Mein Roboter soll folgendes können:
fahren und nicht anfahren - aus und fertig :b
so was wie Linienverfolgung, Kamera, Funk usw. soll erst später kommen, 
dannn aber auch miit anderen Funktionen wie Greifarm usw.. Aber dann 
muss sowieso eine komplett andere Elektronik her...aber das hat noch 
Zeit!

Ja die kenn ich ;)

mfg thomas
Gast #2638075
Lesenswert?

Thomas P. schrieb:
> @FastPWM:
> 1) Ich bin Anfänger und bin unheimlich stolz drauf gewesen, dass es so
> funktioniert hat ;)

Das ist doch auch völlig OK - jeder hat wahrscheinlich so mal 
angefangen.

> 2) Geht das nur für Timer1 odr auch für Timer0?

siehe Datenblatt - alles vorkauen möchte ich hier nicht, vielmehr möchte 
ich nur Tipps geben für eine evtl. in Frage kommende, bessere Lösung.

> 3) Wie soll ich das ohne ISR aufbauen?

Wie gesagt, für einige Servos lässt sich das einfacher und ohne ISR 
bewerkstelligen. Daß es möglich ist, habe ich skizzenhaft angedeutet, 
den Rest müsstest Du (aus meiner Sicht) selbst erarbeiten. Für mehrere, 
z.B. 10 Servos ist die Frage, welchen Microcontroller man verwenden 
will. Natürlich hat dann auch das bereits vorgeschlagene Software-PWM 
seine Berechtigung, wenn es nur ein kleinerer Controller sein soll.

> 4) Falls du es nicht gelesen, von dem ich ausgehe, bei mir ist Timer1 in
> verwendung für Motorensteuerung => somit ist auch OC1A und OC1B, also
> PD4/5 belegt

Es ist eine Designfrage: Muß PD4/5 unbedingt belegt werden oder kann 
dasselbe nicht auch an anderen Pins bewerkstelligt werden? Vor allen 
Dingen gibt es ja auch noch andere Timer (und Counter!). wobei zu prüfen 
wäre, was die jeweils können.

Grundsätzlich wollte ich lediglich auf die Möglichkeit der völlig 
eigenständig laufenden PWM hinweisen. Zu diskutieren gibt es da 
eigentlich nichts - es steht ja auch alles im Datenblatt. :)

... just my 0(!) cents. ;)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren