Tăng độ phân giải bit PWM


9

Tôi muốn tăng độ phân giải bit PWM của Arduino Uno. Tại thời điểm này, nó là 8 bit mà tôi cho là quá thấp. Đây có phải là có thể mà không mất khả năng của sự gián đoạn và chậm trễ?

Koen

EDIT Thiết lập này cung cấp khả năng phục hồi 16 bit

void setupPWM16() {
    DDRB |= _BV(PB1) | _BV(PB2);        /* set pins as outputs */
    TCCR1A = _BV(COM1A1) | _BV(COM1B1)  /* non-inverting PWM */
        | _BV(WGM11);                   /* mode 14: fast PWM, TOP=ICR1 */
    TCCR1B = _BV(WGM13) | _BV(WGM12)
        | _BV(CS11);                    /* prescaler: clock / 8 */
    ICR1 = 0xffff;                      /* TOP counter value (freeing OCR1A*/
}
/* Comments about the setup
Changing ICR1 will effect the amount of bits of resolution.
ICR1 = 0xffff; (65535) 16-bit resolution
ICR1 = 0x7FFF; (32767) 15-bit resolution
ICR1 = 0x3FFF; (16383) 14-bit resolution etc....

Changing the prescaler will effect the frequency of the PWM signal.
Frequency[Hz}=CPU/(ICR1+1) where in this case CPU=16 MHz
16-bit PWM will be>>> (16000000/8)/(65535+1)=30.5175Hz
*/

/* 16-bit version of analogWrite(). Works only on pins 9 and 10. */
void analogWrite16(uint8_t pin, uint16_t val)
{
    switch (pin) {
        case  9: OCR1A = val; break;
        case 10: OCR1B = val; break;
    }
}

Câu trả lời:


15

Arduino Uno dựa trên bộ vi điều khiển ATmega382P. Con chip này có hai bộ định thời 8 bit, mỗi kênh có hai kênh PWM và một bộ hẹn giờ 16 bit, điều khiển hai kênh cuối cùng.

Bạn không thể tăng độ phân giải của bộ định thời 8 bit. Tuy nhiên, bạn có thể đặt bộ hẹn giờ 16 bit ở chế độ 16 bit, thay vì chế độ 8 bit được sử dụng bởi thư viện lõi Arduino. Điều này sẽ cung cấp cho bạn hai kênh PWM 16 bit, với tần số giảm là 244 Hz (tối đa). Bạn có thể sẽ phải tự cấu hình bộ hẹn giờ và sẽ không được hưởng lợi từ analogWrite()chức năng dễ sử dụng . Để biết chi tiết, xem phần trên Timer 1 trong bảng dữ liệu ATmega328P .

Cập nhật : Đây là một triển khai của 16 bit analogWrite(). Nó chỉ hoạt động trên các chân 9 và 10, vì đây là các chân duy nhất được kết nối với bộ hẹn giờ 16 bit.

/* Configure digital pins 9 and 10 as 16-bit PWM outputs. */
void setupPWM16() {
    DDRB |= _BV(PB1) | _BV(PB2);        /* set pins as outputs */
    TCCR1A = _BV(COM1A1) | _BV(COM1B1)  /* non-inverting PWM */
        | _BV(WGM11);                   /* mode 14: fast PWM, TOP=ICR1 */
    TCCR1B = _BV(WGM13) | _BV(WGM12)
        | _BV(CS10);                    /* no prescaling */
    ICR1 = 0xffff;                      /* TOP counter value */
}

/* 16-bit version of analogWrite(). Works only on pins 9 and 10. */
void analogWrite16(uint8_t pin, uint16_t val)
{
    switch (pin) {
        case  9: OCR1A = val; break;
        case 10: OCR1B = val; break;
    }
}

Bạn có thể nhận thấy rằng đỉnh của chuỗi bộ đếm được cấu hình rõ ràng. Bạn có thể thay đổi giá trị này thành một giá trị nhỏ hơn để làm cho PWM nhanh hơn, với chi phí giảm độ phân giải.

Và đây là một ví dụ phác họa minh họa việc sử dụng nó:

void setup() {
    setupPWM16();
}

/* Test: send very slow sawtooth waves. */
void loop() {
    static uint16_t i;
    analogWrite16(9, i);
    analogWrite16(10, 0xffff - i);
    i++;
    delay(1);
}

Wow cảm ơn bạn rất nhiều, đây chính xác là những gì tôi cần. Tôi muốn khả năng phục hồi PWM của mình giống với Độ phân giải cảm biến. Nếu tôi thay đổi mã của bạn thành <nhìn vào bản chỉnh sửa của tôi> thì đó có phải là bản chỉnh sửa 13 bit không? Nếu vậy, tần số sẽ là gì? Tôi sẽ lái một động cơ DC với nó vì vậy tôi đoán là
tần

@KoenR: Không, bộ đếm gộp không ảnh hưởng đến độ phân giải, mục đích của nó là làm chậm quá trình đếm. Đặt bộ đếm gộp thành 8 sẽ cung cấp cho bạn tần số PWM là 30,5 Hz. Nếu bạn muốn độ phân giải 13 bit, được đặt ICR1thành 0x1fff, thì tần số của bạn sẽ là 1953 Hz (F_CPU / (TOP + 1)) với bộ đếm trước ở 1.
Edgar Bonet

Cám ơn vì đã giải thích. Chỉnh sửa câu hỏi của tôi để nó bao gồm những sai lầm. Vì vậy, những người khác có thể nhìn thấy nó trực tiếp. Cảm ơn bạn!
KoenR

1
@Edgar Bonet Điều này thật tuyệt, tuy nhiên tôi dường như không thể tắt hoàn toàn đèn LED. Tôi đang sử dụng ICR1 = 0x03FFvà ở 0 Tôi thấy một xung nhỏ trên phạm vi đủ để làm sáng đèn led. Có ý kiến ​​gì không?
chia tay

1
@davivid: Có, bạn không thể có chu kỳ nhiệm vụ bằng không. analogWrite16(pin, val)đưa ra chu kỳ nhiệm vụ là (val + 1) / ICR1. Như một cách giải quyết, Arduino là analogWrite()như vậy if (val == 0) digitalWrite(pin, LOW); else if (val == 255) digitalWrite(pin, HIGH);. Nhưng sau đó, bạn không thể có được chu kỳ thuế 1 / ICR1 ...
Edgar Bonet

3

Với một số hiệu chuẩn, bạn có thể tổng hợp các đầu ra của hai kênh PWM với các điện trở có trọng số khác nhau. Cuối cùng, bạn thường có thể sử dụng một đầu ra để cung cấp 8 bit độ phân giải và chia tỷ lệ còn lại thành 1/256 cấp độ và thêm chúng để kênh thứ 2 bao phủ một bit phạm vi và bạn (một lần nữa, thông thường) có được 16 bit độ phân giải. Nếu không có sự quan tâm và điều chỉnh to lớn, tất cả những gì bạn nhận được sẽ là một mớ hỗn độn.
Tuy nhiên, bằng cách chia kênh thứ 2 cho 16 hoặc 32, bạn có thể thêm một số bit có độ phân giải PWM. Chỉ bằng cách thêm 2 kênh đầu ra được lọc tương tự, bạn có thêm một bit (vì phạm vi tiềm năng được nhân đôi cho mV / bit không thay đổi).
Về mặt cảm xúc (một lần nữa) cho mỗi lần chia thêm 2 lần, bạn sẽ có thêm một chút độ phân giải, nhưng điều này chỉ có thể được thực hiện đối với khoảng 4 hoặc 5 hoặc 6 bit bổ sung, với yêu cầu độ chính xác tăng của điện trở tỷ lệ và hiệu chỉnh khó hơn và rõ ràng hơn đối với các lỗi .

Ví dụ ngắn gọn.
Nếu một PWM được thu nhỏ lại để đưa ra 0 - 255 mV trong bước 1 mV, thì tổng hai PWM với biên độ bằng nhau sẽ cho phạm vi 0 - 510 mV trong các bước 1 mV.
Nếu một PWM được thu nhỏ theo hệ số 32 thì thay vì thêm 255 mV vào phạm vi PWM ban đầu, nó sẽ chỉ thêm 8 mV vào đầu cuối (0,253,32 = 8 mV, nhưng độ phân giải sẽ ở mức 0,03125 (1/32 ) bước mV.

Trong khi điều này có lẽ có thể đạt được hoàn toàn với tổng điện trở và lọc RC, sử dụng một mùa hè op amp sẽ cải thiện rất nhiều kết quả.

Ngoài ra, Ripple PWM có thể được lọc bằng bộ lọc RC đơn giản nhưng sử dụng một opamp làm bộ đệm (hoặc thậm chí chỉ là một bóng bán dẫn như một người theo dõi phát) sẽ cung cấp cho bạn 3 hoặc 5 cực của bộ lọc thông thấp và cơ hội đạt được nhiều hơn nữa giải quyết. Tôi chưa kiểm tra "sự kết hợp pha" của các đầu ra PWM nhưng hy vọng rằng chúng di chuyển theo bước khóa tương đối để bạn không có được lợi thế làm mịn khi thêm hai dạng sóng không tương thích.

Thêm bình luận có thể được thực hiện nếu cần thiết. Hỏi nếu quan tâm.


Điều này thật thông minh! Có vẻ như thư viện tổng hợp âm thanh Mozzi sử dụng thủ thuật này cho chế độ được gọi là Chế độ Hifi .
Edgar Bonet

Đó là một chúng tôi tuyệt vời của PWM. Nhưng điều này sẽ không làm mịn dạng sóng? Tôi hỏi điều này vì bạn đang sử dụng bộ lọc RC. Không đề cập đến vấn đề này trong câu hỏi của tôi nhưng tôi đang lái một động cơ DC với nó <cảm thấy xấu hổ>. Cảm ơn bạn đã nhập!
KoenR

@KoenR (fwiw: Tôi không thấy có gì phải xấu hổ.) Tôi không biết đáp ứng tần số / tốc độ thay đổi nào bạn muốn trong đầu ra ADC của bạn. Hoặc tại sao bạn muốn N bit hoặc lớn như thế nào là đủ. Động cơ thường sẽ không được điều khiển hữu ích bởi hơn 8 bit - phụ thuộc vào độ chính xác của ứng dụng bạn có. Động cơ hoạt động như một phần của bộ lọc làm mịn do độ tự cảm. Bạn cần phải nói loại động cơ và cách lái. Và một sơ đồ mạch là về thiết yếu. Trừ khi động cơ là nhỏ bạn có một trình điều khiển. Một động cơ được cấp nguồn cho động cơ chải phải có một diode bắt aa để truyền dòng động cơ khi tắt PWM. Thêm hai ...
Russell McMahon

... Các PWM ở đây hoàn toàn có thể thực hiện được nhưng các chi tiết mạch cần phải được biết.
Russell McMahon

Coi chừng! Trong một số trường hợp, việc làm mịn PWM với RC thông thấp là không mong muốn. Ví dụ, nếu bạn cắm đầu ra Arduino vào cổng của MOSFET, MOSFET sẽ giữ lạnh miễn là nó được điều khiển bởi PWM sạch. Nhưng nếu bạn làm mịn nó ra, MOSFET sẽ bắt đầu tản nhiệt nhiều hơn. Đôi khi đó không phải là một điều tốt.
Florin Andrei
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.