Forum: Mikrocontroller und Digitale Elektronik Timer1 Arduino Uno


von Johann (Gast)


Lesenswert?

Hi,

Ich habe bisher immer an einem ATMEGA8 rumgebastelt und habe mir nun 
einen Arduino Uno gekauft mit dem ATMEGA328P. Ich möchte nun für den 
Timer1 den fast-pwm Modus verwenden um damit eine Servo zu steuern und 
möchte das ganze ohne irgendwelche Arduino Libs machen. Doch leider tut 
sich am PIN3 überhaupt nichts:
1
int val1 = 1250;//20 ms
2
int val2 = 100;//between 0.5 ms (val=31) and 2.5 ms (val=156) for SERVO
3
volatile int is_toggled = LOW;//set right OCR1AH Value @Interrupt
4
5
void setup() {
6
  //I/O
7
  pinMode(3,OUTPUT);
8
  digitalWrite(3,LOW);
9
  
10
  //timer
11
  TCCR1A |= (1<<COM1A1)+(1<<COM1B1)+(1<<WGM11)+(1<<WGM10); //fast PWM 
12
  TCCR1B |= (1<<WGM13)+(1<<WGM12)+(1<<CS12); //256 prescaler -> 16us cycles
13
  TIMSK1 |= (1<<ICIE1)+(1<<OCIE1A); //Enables Interrupts
14
  OCR1AH = val1>>8 ;//Set initial TOP Timer value
15
  OCR1AL = val1;
16
  
17
}
18
19
ISR(TIMER1_COMPA_vect) {
20
  if(!is_toggled) {
21
    is_toggled = HIGH;
22
    /*OCR1AH = val2>>8;
23
    OCR1AL = val2;*/
24
    digitalWrite(3,HIGH);
25
  } else {
26
    is_toggled = LOW;
27
    /*OCR1AH = val1>>8;
28
    OCR1AL = val1;*/
29
    digitalWrite(3,LOW);
30
  }
31
}
32
33
34
void loop() {
35
36
}

von Stefan F. (Gast)


Lesenswert?

Ich habe mal gelesen, dass dei digitalWrite Routinen unglaub langsam 
sind. Vielleicht sogar langsamer, als das Timer-Intervall. Vielliecht 
verträgt sich diese Funktion auch aus anderen Gründen nicht mit 
Interrupt-Routinen

Versuche das mal:
1
ISR(TIMER1_COMPA_vect) {
2
  PORTB ~= (1<<4);   // Schalte PB4 um
3
}

Du musst noch herausfinden, wie der Pin3 bei AVR genannt wird. PB4 habe 
ich hier nur als Beispiel genannt.

Du hast da aber noch andere Fehler. Im Fast PWM Modus soll der Timer 
einen I/O Pin direkt ansteuern. Nicht indirekt durch eine Interrupt 
Routine. Außerdem stimmt die Signalform nicht.

Schau mal: http://stefanfrings.de/servocontroller/index.html

von Johann (Gast)


Lesenswert?

Danke, werde das mal ändern, hatte irgendwie fast-pwm anders im Kopf.

von m.n. (Gast)


Lesenswert?

Wenn Du beim Arduino UNO setup(), loop() oder sonstige vorgefertigte 
Funktionen verwendest, verbaust Du Dir damit u.U auch die Timer. Bleibe 
bei reiner Programmierung in C oder prüfe ganz genau, welche Hardware 
blockiert wird!

von Johann (Gast)


Lesenswert?

Ich kann ja beim Interrupt über OCR1A den neuen TOP value setzen um so 
das PWM Signal am OC1A PIN zu erzeugen, doch anscheinend wird kein 
Interrupt ausgelöst. Mit sei() aktiviere ich doch die globalen 
Interrupts.
1
int val1 = 1250;//20 ms
2
int val2 = 100;//between 0.5 ms (val=31) and 2.5 ms (val=156) for SERVO
3
volatile int is_toggled = LOW;//set right OCR1AH Value @Interrupt
4
5
void setup() {
6
  //I/O
7
  pinMode(3,OUTPUT);
8
  digitalWrite(3,LOW);
9
  
10
  //timer
11
  TCCR1A |= (1<<COM1A0)+(1<<WGM11)+(1<<WGM10); //fast pwm directly on port pins! OC1A ->toggled @ compare match
12
  TCCR1B |= (1<<WGM13)+(1<<WGM12)+(1<<CS12); //256 prescaler -> 16us cycles
13
  TIMSK1 |= (1<<OCIE1A); //Enable Interrupts
14
  OCR1AH = val1>>8 ;//Set initial TOP Timer value
15
  OCR1AL = val1;
16
  sei();
17
  
18
}
19
20
ISR(TIMER1_COMPA_vect) { 
21
  if(!is_toggled) {
22
    is_toggled = HIGH;
23
    OCR1AH = val2>>8;
24
    OCR1AL = val2;
25
    digitalWrite(3,HIGH);
26
  } else {
27
    is_toggled = LOW;
28
    OCR1AH = val1>>8;
29
    OCR1AL = val1;
30
    digitalWrite(3,LOW);
31
  }
32
}
33
34
35
void loop() {
36
 
37
}

von Johann (Gast)


Lesenswert?

m.n. schrieb:
> Wenn Du beim Arduino UNO setup(), loop() oder sonstige
> vorgefertigte
> Funktionen verwendest, verbaust Du Dir damit u.U auch die Timer. Bleibe
> bei reiner Programmierung in C oder prüfe ganz genau, welche Hardware
> blockiert wird!

Du hattest recht, Timer1 wurde tatsächlich für die loop() Funktion 
verwendet!

von Johann (Gast)


Lesenswert?

Leider funktioniert aber der OC1A Ausgang nicht, der laut mapping beim 
Arduino Uno der PIN9 ist. Was genau bedeutet im Datenblatt "update of 
OCR1A at BOTTOM"? Ich dachte, man müsste OCR1A im Interrupt updaten, der 
durch setzen des TOV1 flags ausgelöst wird oder kann man OCR1A auch 
anders updaten?
1
int val1 = 1250;//20 ms
2
int val2 = 100;//between 0.5 ms (val=31) and 2.5 ms (val=156) for SERVO
3
volatile int is_toggled = LOW;//set right OCR1AH Value @Interrupt
4
5
//prototype
6
void init();
7
8
int main(void) {
9
  init();
10
  while(1) {
11
  }
12
}
13
14
void init() {
15
  //I/O
16
  pinMode(3,OUTPUT);  
17
  //timer
18
  TCCR1A |= (1<<COM1A0)+(1<<WGM11)+(1<<WGM10); //fast pwm directly on port pins! OC1A ->toggled @ compare match
19
  TCCR1B |= (1<<WGM13)+(1<<WGM12)+(1<<CS12); //256 prescaler -> 16us cycles
20
  TIMSK1 |= (1<<OCIE1A); //Enable Interrupts
21
  OCR1AH = val1>>8 ;//Set initial TOP Timer value
22
  OCR1AL = val1;
23
  sei();
24
  
25
}
26
27
ISR(TIMER1_COMPA_vect) { //Interrupt nur, um OCR1A zu updaten
28
  if(!is_toggled) {
29
    is_toggled = HIGH;
30
    OCR1AH = val2>>8;
31
    OCR1AL = val2;
32
  } else {
33
    is_toggled = LOW;
34
    OCR1AH = val1>>8;
35
    OCR1AL = val1;
36
  }
37
}

von Johann (Gast)


Lesenswert?

Ok, blöder Fehler, hatte PIN9 gar nicht als Ausgang gesetzt.

Gruss und Danke Johann

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.