Forum: Mikrocontroller und Digitale Elektronik Veränderung von OCR1A und OCR1B über Taster


von Steffen K. (steffenkeller)


Lesenswert?

Hallo Forum,

ich möchte über vier Taster zwei Servos unabhängig voneinander steuern 
(Servo1 rechts/links; Servo2 rechts/links). Dabei verwende ich vom 
ATMega8 den Timer 1 mit den beiden Compare Matches OCR1A und OCR1B im 
Fast PWM Modus, bei dem die Obergrenze durch ICR1 gegeben ist. OC1A und 
OC1B werden zu Beginn gesetzt und bei OCR1A und OCR1B gelöscht 
(-->Servoimpuls).
ICR1 ist so gewählt, dass ein Zählzyklus bei CPU-Frequenz 4MHz 20ms 
dauert.

Zwei Variablen Position1 und Position2 geben die Impulslänge für die 
jeweilige Servostellung an.

Mein bisheriger Code:
1
volatile static unsigned int Impuls1;        //Impulslänge Servo2
2
volatile static unsigned int Impuls2;        //Impulslänge Servo2
3
const unsigned int Periodendauer = 10000;    //Periodendauer
4
5
unsigned int Position1;                      //Impulszählerstand Servo1
6
                                             //generell
7
unsigned int Mittelstellung1 = 400;          //Impulszählerstand
8
                                             //Mittelstellung Servo1
9
10
unsigned int Position2;                      //Impulszählerstand Servo2 
11
                                             //generell
12
unsigned int Mittelstellung2 = 1000;         //Impulszählerstand 
13
                                             //Mittelstellung Servo2
14
15
int main(void)
16
{
17
    //Allgemeine Initialisierungen
18
    DDRB = 0xFF;                             //PORTB Ausgang für Servos
19
    DDRD = 0x00;                             //PORTD Eingang für Taster
20
    PORTD = 0xFF;                            //PORTD Pullup-Widerstände
21
    
22
    
23
    //Positionskonfiguration
24
    Impuls1 = Mittelstellung1;               //Servo1 Mittelstellung
25
    Impuls2 = Mittelstellung2;               //Servo2 Mittelstellung
26
27
    //Timer1-Konfiguration
28
    ICR1 = Periodendauer;
29
    
30
    OCR1A = Impuls1;
31
    OCR1B = Impuls2;
32
    
33
    TCCR1A |= (1 << COM1A1);                 //OCR1A bei Compare Match 
34
                                             //setzen und bei ICR1
35
                                             //löschen
36
    TCCR1A |= (1 << COM1B1);                 //OCR1B bei Compare Match 
37
                                             //setzen und bei ICR1
38
                                             //löschen
39
    
40
    TCCR1A |= (1 << WGM11);
41
    TCCR1B |= (1 << WGM12);
42
    TCCR1B |= (1 << WGM13);                  //WGM11:13 für Fast PWM mit 
43
                                             //Obergrenze ICR1
44
    
45
    TCCR1B |= (1 << CS10);                   //Timer1 Vorteiler 1
46
    
47
    sei();                                   //Interrupts werden zugelassen
48
    
49
    //mainloop;
50
    while(1)
51
    {
52
    }
53
    return(1);

Meine Frage nun:
Wo muss die Tasterabfrage für die vier Taster an PD2:5 hin, damit ich 
das Programm nicht störe, bzw. wie sieht die Abfrage dann aus?

Gruß Steffen

von STK500-Besitzer (Gast)


Lesenswert?

Steffen Keller schrieb:
> Wo muss die Tasterabfrage für die vier Taster an PD2:5 hin, damit ich
> das Programm nicht störe, bzw. wie sieht die Abfrage dann aus?

Du setzt bei jedem Timer-Overflow ein Flag, das du in der 
main-while-Schleife auswertest und da setzt du dann auch - wenn das 
Tastersignal ausreichend lange stabil ist - die Capturewerte neu.

von Thomas E. (thomase)


Lesenswert?

Steffen Keller schrieb:
> while(1)
>
>     {
>
>     }

Steffen Keller schrieb:
> Meine Frage nun:
> Wo muss die Tasterabfrage für die vier Taster an PD2:5 hin, damit ich
> das Programm nicht störe, bzw. wie sieht die Abfrage dann aus?
Dein Programm macht überhaupt nichts. Du hast ja praktisch gar kein 
Programm. Sondern dein Controller trampelt auf der Stelle und langweilt 
sich. Denn deine Pwm erledigt die Timerhardware ganz alleine. Ohne sich 
stören zu lassen oder irgendwen anders zu stören.
Also hat dein Controller alle Zeit der Welt die Tasten abzufragen.
Sinnvollerweise nimmst du dazu einen zweiten Timer und lässt diesen jede 
Millisekunde deine Tasten pollen. Weiterhin brauchst du noch eine 
Entprellung. Die Tastenauswertung machst du dann in der Hauptschleife 
oder auch im Timerinterrupt. Das ist ja nur inkrementieren oder 
dekrementieren und kontrollieren ob der Wert im richtigen Bereich 
bleibt.


mfg.

von Steffen K. (steffenkeller)


Lesenswert?

STK500-Besitzer schrieb:

> Du setzt bei jedem Timer-Overflow ein Flag, das du in der
> main-while-Schleife auswertest

Ich habe mich bis jetzt nur mit der Auswertung Signalen in ISRs 
beschäftigt. Wie kann ich eine Flag in der main-while-Schleife 
auswerten? Hole ich mir den Wert von ICF1 und dann in einer weiteren 
Schleife?


Thomas Eckmann schrieb:

>Sinnvollerweise nimmst du dazu einen zweiten Timer und lässt diesen jede
>Millisekunde deine Tasten pollen. Weiterhin brauchst du noch eine
>Entprellung. Die Tastenauswertung machst du dann in der Hauptschleife
>oder auch im Timerinterrupt.

Ich muss gestehen, dass mich der Begriff "pollen" bis jetzt gemieden hat 
...bitte um kurze Erläuterung

Das heißt ich löse jede 1ms mit einem anderen Timer einen Interrupt aus, 
in dem dann die Tasten abgefragt werden und neue Werte geschrieben 
werden?

Gruß Steffen

von STK500-Besitzer (Gast)


Lesenswert?

Steffen Keller schrieb:
> Ich habe mich bis jetzt nur mit der Auswertung Signalen in ISRs
> beschäftigt. Wie kann ich eine Flag in der main-while-Schleife
> auswerten? Hole ich mir den Wert von ICF1 und dann in einer weiteren
> Schleife?

Such mal bitte nach volatile im Forum.

Steffen Keller schrieb:
> Ich muss gestehen, dass mich der Begriff "pollen" bis jetzt gemieden hat
> ...bitte um kurze Erläuterung

https://www.google.com/url?q=http://de.wikipedia.org/wiki/Polling_(Informatik)&sa=U&ei=GXdHUZ7HNIKnhAe424CgBw&ved=0CAcQFjAA&client=internal-uds-cse&usg=AFQjCNHwov93vHcJf6PR4PDAe9_L5LUXfQ

von Steffen K. (steffenkeller)


Lesenswert?

So, nun weiß ich, was Pollen bedeutet, habe aber noch keinen Plan, wie 
ich das realisieren kann
Da steht was von zyklisch, heißt des dass ich wie beschrieben nen 
zweiten Timer dafür nehm?

Und welche Variable definier ich dann volatile? Eigentlich ja dann die 
beiden Impulsvariablen oder (was sie ja schon sind)?

Und nun weiß ich noch nicht, wie ich ICF1 in main auswerte...

Gruß Steffen

von holger (Gast)


Lesenswert?


von Steffen K. (steffenkeller)


Lesenswert?

Ich habe nochmal rumprobiert und ein paar Versionen geschrieben:
Version 1:
Bei Compare Match A und B werden Interrupts ausgelöst, die die neuen 
Werte in den Timer übernehmen sollen:
1
ISR(TIMER1_COMPA_vect)
2
{
3
     OCR1A = Impuls1;                  //neuen Impulszählerstand nehmen
4
}
5
6
//Interrupts
7
TIFR |= TCF1A;                         //Compare Match A Interrupt
8
TIFR |= OCF1B;                         //Compare Match B Interrupt

Der Mainloop enthält die Tasterabfrage:
1
while(1)
2
    {
3
  if (!(PIND & (1<<PD2)))
4
  {
5
       Impuls1+=5;
6
  }
7
  else if (!(PIND & (1<<PD3)))
8
  {
9
       Impuls1-=5;
10
  }    
11
    }

Das Servo rührt sich aber kein bisschen...

Nächster Versuch:
Timer 0 zählt bis Höchststand und löst OVF aus. Darin die Tasterabfrage
1
//Servosteuerung Drehleiter
2
//Servo 1 an PB1 (OC1A)
3
//Servo 2 an PB2 (OC1B)
4
5
#define F_CPU 3686400
6
7
#include <avr/io.h>
8
#include <avr/interrupt.h>
9
10
volatile static unsigned int Impuls1;          //Impulslänge Servo2
11
volatile static unsigned int Impuls2;        //Impulslänge Servo2
12
const unsigned int Periodendauer = 10000;        //Periodendauer
13
14
unsigned int Position1;                 //Impulszählerstand Servo1 generell
15
unsigned int Mittelstellung1 = 1000;           //Impulszählerstand Mittelstellung Servo1
16
17
unsigned int Position2;                //Impulszählerstand Servo2 generell
18
unsigned int Mittelstellung2 = 1000;           //Impulszählerstand Mittelstellung Servo2
19
20
ISR(TIMER0_OVF_vect)
21
{
22
  if (!(PIND & (1<<PD2)))
23
  {
24
    Impuls1+=15;
25
  }
26
  else if (!(PIND & (1<<PD3)))
27
  {
28
    Impuls1-=15;
29
  }
30
  OCR1A = Impuls1;                //neuen Impulszählerstand für Servo1 nehmen
31
  
32
  if (!(PIND & (1<<PD4)))
33
  {
34
    Impuls2+=15;
35
  }
36
  else if (!(PIND & (1<<PD5)))
37
  {
38
    Impuls2-=15;
39
  }
40
  OCR1B = Impuls2;                //neuen Impulszählerstand für Servo2 nehmen
41
}
42
43
int main(void)
44
{
45
    //Allgemeine Initialisierungen
46
  DDRB = 0xFF;                              //PORTB Ausgang für Servos
47
  DDRD = 0x00;                  //PORTD Eingang für Taster
48
    PORTD = 0xFF;                    //PORTD Pullup-Widerstände
49
    
50
    
51
    //Positionskonfiguration
52
    Impuls1 = Mittelstellung1;            //Servo1 Mittelstellung
53
    Impuls2 = Mittelstellung2;            //Servo2 Mittelstellung
54
55
    //Timer1-Konfiguration
56
    ICR1 = Periodendauer;
57
    
58
    TCCR1B |= (1 << CS10);                //Timer1 Vorteiler 1
59
    
60
    TCCR1A |= (1 << COM1A1);              //OCR1A bei Compare Match setzen und bei ICR1
61
                            //löschen
62
    TCCR1A |= (1 << COM1B1);              //OCR1B bei Compare Match setzen und bei ICR1
63
                            //löschen
64
    
65
    TCCR1A |= (1 << WGM11);
66
    TCCR1B |= (1 << WGM12);
67
    TCCR1B |= (1 << WGM13);              //WGM11:13 für Fast PWM mit Obergrenze ICR1
68
    
69
    OCR1A = Impuls1;                //OC1A geht low bei Zählerstand von Impuls1
70
  OCR1B = Impuls2;                //OC1B geht low bei Zählerstand von Impuls2
71
  
72
  //Timer0-Konfiguration
73
  TCCR0 |= (1<<CS02);                //Timer0 Vorteiler 1
74
  TIMSK |= (1<<TOIE0);              //Interrupt bei Timer0 Overflow
75
    
76
    sei();                      //Interrupts werden zugelassen
77
    
78
    //mainloop;
79
    while(1)
80
    {
81
    
82
    }
83
    return(1);

Das Servo 2 an PB2 (OCR1B) funktioniert gut.
Allerdings gibt es beim rechten Anschlag das Problem, dass der Servo 
kurz davor noch in den regulären Schritten "fährt", dann jedoch 
plötzlich unkontrolliert 20° weiterspringt.
Servo 1 rührt sich aber garnicht...

Gruß Steffen

von Peter D. (peda)


Lesenswert?

Steffen Keller schrieb:
> Ich habe nochmal rumprobiert und ein paar Versionen geschrieben:

Was kann man mit Rumprobieren erreichen?

Richtig, garnichts!

Du wirst solange nicht weiterkommen, bis Du nicht das Problem in seine 
Teilaufgaben zerlegst und diese einzeln implementierst.

Mach erstmal eine funktionierende Tastentprellung:
2 Tasten + 2 LEDs, jede Taste toggled ihre LED zuverlässig.

von Steffen K. (steffenkeller)


Lesenswert?

Peter Dannegger schrieb:
> Was kann man mit Rumprobieren erreichen?
> Richtig, garnichts!

Rumprobieren bedeutet für mich Hard- und Software verändern. 
Dementsprechend lag es zum einen an den Servos, die Neuen laufen nämlich 
super.
Zum anderen habe ich nur dadurch gesehen, dass mir PortD Schwierigkeiten 
gebracht hat. Ich vermute, dass ich mit den beiden Tastern an PD2..3 die 
beiden externen INT0 und INT1 ausgelöst habe und dadurch das Problem 
kam. Zu genauer Analyse fehlt mir aber die Erfahrung/KnowHow. Mit PortC 
läufts.

Natürlich muss man bei einem Problem erst die gegebene Situation 
auseinander nehmen, keine Frage. Aber hin und wieder passt doch der 
Spruch: "Probieren geht über Studieren"

Gruß Steffen

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.