Arduino Nano - 20 kHz PWM an OC1A/OC1B

Gast #5010475
Lesenswert?

Hallo,

ich benötige an einem Arduino Nano an den Pins OC1A und OC1B jeweiles 
ein PWM-Signal mit 20kHz.

Der Arduino läuft mit 16 MHz.
Den Prescaler setzte ich auf 1.
Als Top-Value schreibe ich 800 in das ICR1-Register.

=> 16 MHz  1  800 = 20 kHz

Folgenden Code verwende ich um Timer 1 zu initialisieren:
1
  pinMode(9, OUTPUT);
2
  pinMode(10, OUTPUT);
3
  
4
  TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11) | (1 << WGM10);
5
  TCCR1B = (1 << WGM12)  | (1 << CS10) ;
6
  ICR1L  = (800 >> 0) & 0xFF;
7
  ICR1H  = (800 >> 8) & 0xFF;
8
  
9
  OCR1A  = 1023 / 2; /* 50% DC */
10
  OCR1B  = 1023 / 3; /* 33% DC */

Die Frequenz der Pins messe ich mit einem Oszi. Diese liegt allerdings 
nur bei 15,625 kHz.

Sieht jemand einen Fehler?

Danke
Beitrag #5011589 wurde von einem Moderator gelöscht.
Gast #5011593
Lesenswert?

Hallo, danke für Eure Hilfe!
Mittlerweile läuft das ganze.

Hier der Code:
1
  pinMode( 9, OUTPUT);
2
  pinMode(10, OUTPUT);
3
  
4
  TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11);
5
  TCCR1B = (1 << WGM13)  | (1 << WGM12)  | (1 << CS10);
6
  ICR1   = (800- 1);
7
  
8
  OCR1A  = (800 - 1) / 2;
9
  OCR1B  = (800 - 1) / 3;
Gast #5011628
Lesenswert?

Nachtrag: der letzte Fehler war exakt der von Carl Drexler beschriebene 
Fall, "compare never": ICR1 wurde nur auf den low-Wert von 800 gesetzt, 
also 32, und damit waren die OCR1_ weit drüber und wurden nie erreicht.
#5016662
Lesenswert?

YamA schrieb:
> Hallo, danke für Eure Hilfe!
> Mittlerweile läuft das ganze.
>
> Hier der Code:
>
1
>   pinMode( 9, OUTPUT);
2
>   pinMode(10, OUTPUT);
3
> 
4
>   TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11);
5
>   TCCR1B = (1 << WGM13)  | (1 << WGM12)  | (1 << CS10);
6
>   ICR1   = (800- 1);
7
> 
8
>   OCR1A  = (800 - 1) / 2;
9
>   OCR1B  = (800 - 1) / 3;
10
>

Danke für die Informationen. Gibt es dazu eine Art Anleitung? Ist dies 
der vollständige Code? Muss der Pin nicht irgendwo noch auf HIGH gesetzt 
werden?
 Würde gerne ähnliches mit dem Arduin Mega 2560 durchführen und 
unterschiedliche Freqeunzen ausgeben...
Leider kenne ich mich fast gar nicht damit aus. Würde mich über 
deine/eure Hilfe freuen.
Gast #5016757
Lesenswert?

Hallo,
du musst Dich im Datenblatt mit den Unterschiedlichen Timer Modi 
auseinander setzen und dann die zugehörige Beschreibung lesen und 
verstehen.
Dort findet man auch unterschiedliche Formeln, je nach Modi, für das 
TOP-Register.

Don P. schrieb:
> Würde gerne ähnliches mit dem Arduin Mega 2560 durchführen und
> unterschiedliche Freqeunzen ausgeben...
> Leider kenne ich mich fast gar nicht damit aus. Würde mich über
> deine/eure Hilfe freuen.
Gast #5016780
Lesenswert?

YamA schrieb:
...
>   pinMode(10, OUTPUT);
>
>   TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11);
...
Schöner Mix aus Ardu'ino' und echtem 'C' :-/

Mal blöd gefragt, warum verwendest Du nicht die Arduino-Funktion 'tone'?
https://www.arduino.cc/en/reference/tone

Ich würde mir den Code noch kommentieren,
damit man später auch ohne Blick ins Datenblatt sieht, was gemacht wird:
1
    // Waveform generator mode 14 (Table 20-6)
2
    // Fast PWM, TOP = ICR1 
3
    //
4
    // Clear OC1A/OC1B on compare match, (Table 20-4)
5
    // Set   OC1A/OC1B at bottom
6
    //
7
    // Prescaler = 1 (Table 20-7) 
8
    TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11);
9
    TCCR1B = (1 << WGM13)  | (1 << WGM12)  | (1 << CS10);
10

11
    ICR1   = (800- 1);
12
 
13
    OCR1A  = (800 - 1) / 2;
14
    OCR1B  = (800 - 1) / 3;


Zusätzlich lasse mir gerne die Zählerendwerte vom Präprozessor 
ausrechnen.
Hier ein aktuelles Beispiel, nur für einen anderen Timer:
1
static void
2
timer0_init( const uint16_t frequency) 
3
{
4
#define TIMER0_PRESCALER    256 
5

6
    TCCR0A  |= ( 1 << WGM01);     // CTC mode, Table 19-9
7
    TCCR0A  |= ( 1 << COM0B0);    // Toggle OC0B on Compare Match, Tab. 19-6
8

9
#if TIMER0_PRESCALER == 1
10
    TCCR0B  |= ( 1 << CS00);
11
#elif TIMER0_PRESCALER == 8
12
    TCCR0B  |= ( 1 << CS01);
13
#elif TIMER0_PRESCALER == 64
14
    TCCR0B  |= ( 1 << CS01) | ( 1 << CS00);
15
#elif TIMER0_PRESCALER == 256
16
    TCCR0B  |= ( 1 << CS02);
17
#elif TIMER0_PRESCALER == 1024
18
    TCCR0B  |= ( 1 << CS02) | ( 1 << CS00);
19
#else
20
    #error "TIMER 0 PRESCALER undefined"
21
#endif
22

23
    OCR0A   = ( F_CPU / 2 / TIMER0_PRESCALER / frequency) - 1;
24
    OCR0B   = 0;
25
}

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