Ustaw częstotliwość PWM na 25 kHz


12

Obecnie mogę ustawić cztery styki PWM na około 31 kHz za pomocą następującego kodu:

void setup()
{
    TCCR1B = TCCR1B & B11111000 | B00000001; // Set PWM frequency for D9 & D10:
    pinMode(pwmPin9, OUTPUT); // Sets the pin as output
    pinMode(pwmPin10, OUTPUT); // Sets the pin as output


    TCCR2B = TCCR2B & B11111000 | B00000001; // Set PWM for D3 & D11
    pinMode(pwmPin3, OUTPUT); // Sets the pin as output
    pinMode(pwmPin11, OUTPUT); // Sets the pin as output
}

Gdzieś znalazłem tę konfigurację, ale nie wiem, jak zamiast tego ustawić te cztery piny PWM na około 25 kHz. Jak to możliwe?


3
Czy rozumiesz, jak działają liczniki AVR?
Ignacio Vazquez-Abrams


1
@ IgnacioVazquez-Abrams Nie jestem zaznajomiony i na początku muszę ustawić te cztery piny na około 25 kHz. Spieszy mi się z ukończeniem projektu i chętnie udzielę pomocy. Kod mam ustawiony na 31 kHz. Czy mogę go zmienić na 25kHz? Silniki prądu stałego wymagają tej częstotliwości.
user16307

1
@NickGammon Dzięki, ale tak naprawdę nie mam wystarczająco dużo czasu, aby je studiować w tej chwili. Czy możesz podać mi część kodu do konfiguracji 25kHz. Zgubiłem
16307

2
Muszę dostroić ich dokładne obroty, aby ich cykle robocze były nieco inne. Co powiesz na to, że można ustawić 2 piny tylko na 25 kHz?
user16307

Odpowiedzi:


10

Piszę tę drugą odpowiedź, ponieważ zdałem sobie sprawę, że możliwe jest posiadanie 4 kanałów PWM przy 25 kHz z 161 krokami na jednym Arduino Uno. Wymaga to zmiany głównej częstotliwości zegara na 8 MHz , co ma pewne skutki uboczne, ponieważ cały program będzie działał o połowę szybciej. To również wymaga rekonfiguracji trzech liczników, czyli utraty funkcji Ciężki rozrządu ( millis(), micros(), delay()i delayMicroseconds()). Jeśli te kompromisy są dopuszczalne, oto jak to wygląda:

void setup()
{
    // Set the main system clock to 8 MHz.
    noInterrupts();
    CLKPR = _BV(CLKPCE);  // enable change of the clock prescaler
    CLKPR = _BV(CLKPS0);  // divide frequency by 2
    interrupts();

    // Configure Timer 0 for phase correct PWM @ 25 kHz.
    TCCR0A = 0;           // undo the configuration done by...
    TCCR0B = 0;           // ...the Arduino core library
    TCNT0  = 0;           // reset timer
    TCCR0A = _BV(COM0B1)  // non-inverted PWM on ch. B
        | _BV(WGM00);  // mode 5: ph. correct PWM, TOP = OCR0A
    TCCR0B = _BV(WGM02)   // ditto
        | _BV(CS00);   // prescaler = 1
    OCR0A  = 160;         // TOP = 160

    // Same for Timer 1.
    TCCR1A = 0;
    TCCR1B = 0;
    TCNT1  = 0;
    TCCR1A = _BV(COM1A1)  // non-inverted PWM on ch. A
        | _BV(COM1B1)  // same on ch. B
        | _BV(WGM11);  // mode 10: ph. correct PWM, TOP = ICR1
    TCCR1B = _BV(WGM13)   // ditto
        | _BV(CS10);   // prescaler = 1
    ICR1   = 160;

    // Same for Timer 2.
    TCCR2A = 0;
    TCCR2B = 0;
    TCNT2  = 0;
    TCCR2A = _BV(COM2B1)  // non-inverted PWM on ch. B
        | _BV(WGM20);  // mode 5: ph. correct PWM, TOP = OCR2A
    TCCR2B = _BV(WGM22)   // ditto
        | _BV(CS20);   // prescaler = 1
    OCR2A  = 160;
}

void loop()
{
    analogWrite( 3,   1);  // duty cycle = 1/160
    analogWrite( 5,  53);  // ~ 1/3
    analogWrite( 9, 107);  // ~ 2/3
    analogWrite(10, 159);  // 159/160
}

W przeciwieństwie do drugiej odpowiedzi , nie wymaga to zmodyfikowanej wersji analogWrite(): standardowa będzie działać dobrze. Należy tylko zadbać o to, aby:

  1. Zapisana wartość powinna zawierać się w przedziale od 0 (co oznacza zawsze NISKI) do 160 (zawsze WYSOKI) włącznie.
  2. Dostępne są tylko piny 3, 5, 9 i 10. Próba analogWrite() użycia pinów 6 lub 11 nie tylko nie zapewni wyjścia PWM, ale także zmieni częstotliwość odpowiednio na pinach 5 lub 3.

Byłem bardzo długo i teraz utknąłem z tym samym z Arduino Due, który używa innego procesora. Byłbym zadowolony, gdybyś miał
uwagi

11

Możesz skonfigurować Timer 1 tak, aby pracował z częstotliwością 25 kHz w prawidłowym trybie PWM i używał dwóch wyjść na pinach 9 i 10 w taki sposób:

// PWM output @ 25 kHz, only on pins 9 and 10.
// Output value should be between 0 and 320, inclusive.
void analogWrite25k(int pin, int value)
{
    switch (pin) {
        case 9:
            OCR1A = value;
            break;
        case 10:
            OCR1B = value;
            break;
        default:
            // no other pin will work
            break;
    }
}

void setup()
{
    // Configure Timer 1 for PWM @ 25 kHz.
    TCCR1A = 0;           // undo the configuration done by...
    TCCR1B = 0;           // ...the Arduino core library
    TCNT1  = 0;           // reset timer
    TCCR1A = _BV(COM1A1)  // non-inverted PWM on ch. A
           | _BV(COM1B1)  // same on ch; B
           | _BV(WGM11);  // mode 10: ph. correct PWM, TOP = ICR1
    TCCR1B = _BV(WGM13)   // ditto
           | _BV(CS10);   // prescaler = 1
    ICR1   = 320;         // TOP = 320

    // Set the PWM pins as output.
    pinMode( 9, OUTPUT);
    pinMode(10, OUTPUT);
}

void loop()
{
    // Just an example:
    analogWrite25k( 9, 110);
    analogWrite25k(10, 210);
    for (;;) ;  // infinite loop
}

Zapis wartości 0 analogWrite25k()oznacza, że ​​pin będzie zawsze NISKI, zaś 320 oznacza zawsze WYSOKI. Regular analogWrite() powinien prawie działać, ale zinterpretuje 255 tak samo jak 320 (tj. Zawsze WYSOKI).

Ten kod zakłada kartę Arduino Uno lub podobną (ATmega168 lub 328 @ 16 MHz). Zastosowana tutaj metoda wymaga 16-bitowego timera, a zatem wykorzystuje Timer 1, ponieważ jest to jedyny dostępny na Uno; dlatego dostępne są tylko dwa wyjścia. Metodę można dostosować do innych płyt opartych na AVR z 16-bitowym zegarem. Jak zauważył Gerben, ten zegar powinien mieć odpowiedni rejestr ICRx. W Arduino Mega są 4 takie timery, każdy z 3 wyjściami.


1
Przydatne może być wyjaśnienie, że ta metoda działa tylko dla timera 1, ponieważ inne timery nie mają ICRxrejestru. Co najwyżej, możesz mieć tylko jeden pin PWM na timer, dla timerów 0 i 2.
Gerben

1
@Gerben: Czy wszystkie 16-bitowe timery nie mają tego rejestru? Przynajmniej na Mega.
Edgar Bonet

1
Tak, ale tylko timer1 jest 16-bitowy na ATMega328. Reszta to 8-bit. I OP chce wyjścia 4 PWM, a twoje rozwiązanie zapewnia tylko 2. Czy się mylę?
Gerben

1
@Gerben: Nie, masz rację. Mówię tylko, że wymaganie ICRx wydaje się zbędne z wymaganiem, aby zegar miał 16 bitów. Przynajmniej dla Uno i Mega, nie jestem pewien co do innych Arduinos opartych na AVR. OP rozumie, że zapewnia to tylko 2 kanały PWM: patrz mój komentarz do jego pytania i odpowiedzi.
Edgar Bonet

2
@techniche: 1. Działa dla mnie. Może zapomniałeś ustawić COM4C1w TCCR4A? 2. Jeśli to nie jest problem, przeczytaj Jak zadać dobre pytanie? , a następnie zaktualizuj swoje pytanie , dołączając pełny kod źródłowy i wyraźnie określając, czego oczekujesz od programu i co robi zamiast tego („Nie widzę żadnego sukcesu” nie jest uważane za prawidłowe oświadczenie o problemie).
Edgar Bonet,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.