Đặt tần số PWM thành 25 kHz


12

Hiện tại tôi có thể đặt bốn chân PWM ở khoảng 31 kHz với mã sau:

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
}

Tôi đã tìm thấy thiết lập này ở đâu đó, nhưng tôi không biết làm thế nào tôi có thể đặt bốn chân PWM này ở khoảng 25 kHz. Làm thế nào là có thể?


3
Bạn có hiểu làm thế nào các bộ định thời AVR hoạt động?
Ignacio Vazquez-Abrams


1
@ IgnacioVazquez-Abrams Tôi không quen và tôi cần đặt bốn chân đó vào khoảng 25kHz lúc đầu. Tôi đã nhanh chóng hoàn thành một dự án và tôi sẽ vui mừng với bất kỳ sự giúp đỡ nào. Mã tôi đã đặt thành 31kHz. Tôi có thể sửa đổi nó thành 25kHz không? Động cơ DC yêu cầu freq đó.
dùng16307

1
@NickGammon Cảm ơn nhưng tôi thực sự không có đủ thời gian để nghiên cứu những thứ này vào lúc này. Bạn có thể cung cấp cho tôi phần mã để thiết lập 25kHz. Tôi bị mất
dùng16307

2
Tôi cần điều chỉnh vòng quay chính xác của họ để chu kỳ nhiệm vụ của họ sẽ hơi khác nhau. Làm thế nào về việc có thể chỉ đặt 2 chân thành 25kHz?
dùng16307

Câu trả lời:


10

Tôi đang đăng câu trả lời thứ hai này vì tôi nhận ra rằng có thể có 4 kênh PWM ở 25 kHz với 161 bước trên một Arduino Uno. Điều này liên quan đến việc thay đổi tần số xung nhịp chính thành 8 MHz , có một số tác dụng phụ vì toàn bộ chương trình sẽ chạy nhanh bằng một nửa. Nó cũng liên quan đến việc cấu hình lại ba giờ, mà có nghĩa là mất chức năng Arduino thời gian ( millis(), micros(), delay()delayMicroseconds()). Nếu những sự đánh đổi này được chấp nhận, thì đây là cách nó diễn ra:

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
}

Không giống như câu trả lời khác , điều này không cần một phiên bản sửa đổi: phiên bản analogWrite()tiêu chuẩn sẽ hoạt động tốt. Chỉ nên cẩn thận rằng:

  1. Giá trị được viết phải nằm trong khoảng từ 0 (có nghĩa là luôn THẤP) và 160 (luôn luôn CAO).
  2. Chỉ có chân 3, 5, 9 và 10 có sẵn. Cố gắng đến analogWrite() các chân 6 hoặc 11 sẽ không chỉ không cung cấp đầu ra PWM, mà còn thay đổi tần số trên chân 5 hoặc 3 tương ứng.

Đã rất lâu và bây giờ tôi bị mắc kẹt với điều tương tự với Arduino Do sử dụng bộ xử lý khác. Tôi sẽ rất vui nếu bạn lôi
user16307 14/07/19

11

Bạn có thể định cấu hình Timer 1 để quay vòng ở 25 kHz ở chế độ PWM đúng pha và sử dụng hai đầu ra trên các chân 9 và 10 như sau:

// 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
}

Viết giá trị bằng 0 có analogWrite25k()nghĩa là pin sẽ luôn ở mức THẤP, trong khi 320 có nghĩa là luôn CAO. Thông thường analogWrite() sẽ gần như hoạt động, nhưng nó sẽ diễn giải 255 giống như 320 (tức là luôn luôn CAO).

Mã này giả định một Arduino Uno hoặc bảng tương tự (ATmega168 hoặc 328 @ 16 MHz). Phương thức được sử dụng ở đây yêu cầu bộ định thời 16 bit và do đó, nó sử dụng Timer 1 vì đây là phương thức duy nhất có sẵn trên Uno; đó là lý do tại sao chỉ có hai đầu ra có sẵn. Phương pháp này có thể được điều chỉnh phù hợp với các bo mạch dựa trên AVR khác với bộ hẹn giờ 16 bit. Như Gerben đã lưu ý, bộ đếm thời gian đó nên có một thanh ghi ICRx tương ứng. Có 4 bộ tính giờ như vậy trên Arduino Mega, mỗi bộ có 3 đầu ra.


1
Có thể hữu ích để giải thích rằng phương pháp này chỉ hoạt động cho timer1, vì các bộ định thời khác không có ICRxđăng ký. Nhiều nhất, bạn chỉ có thể có một chân PWM cho mỗi bộ hẹn giờ, cho bộ định thời 0 và 2.
Gerben

1
@Gerben: Không phải tất cả các bộ định thời 16 bit có đăng ký đó? Ít nhất là trên Mega họ làm.
Edgar Bonet

1
Có, nhưng chỉ có timer1 là 16 bit trên ATMega328. Phần còn lại là 8 bit. Và OP muốn có 4 đầu ra PWM, và giải pháp của bạn chỉ cung cấp 2. Hay tôi nhầm?
Gerben

1
@Gerben: Không, bạn đúng. Tôi chỉ nói rằng yêu cầu ICRx dường như là dư thừa với yêu cầu bộ định thời là 16 bit. Đối với Uno và Mega ít nhất, không chắc chắn về các Arduinos dựa trên AVR khác. OP hiểu điều này chỉ cung cấp 2 kênh PWM: xem nhận xét của tôi về câu hỏi của anh ấy và câu trả lời của anh ấy.
Edgar Bonet

2
@techniche: 1. Làm việc cho tôi. Có lẽ bạn đã quên thiết lập COM4C1trong TCCR4A? 2. Nếu đó không phải là vấn đề, thì hãy đọc Làm thế nào để tôi hỏi một câu hỏi hay? , sau đó cập nhật câu hỏi của bạn bằng cách bao gồm mã nguồn đầy đủ của bạn và nêu rõ những gì bạn mong đợi chương trình sẽ làm và thay vào đó (Thay vào đó tôi không thấy bất kỳ thành công nào.
Edgar Bonet
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.