เพิ่มความละเอียดบิต PWM


10

ฉันต้องการเพิ่มความละเอียดบิต PWM ของ Arduino Uno ในขณะนี้มันมี 8 บิตซึ่งฉันถือว่าต่ำเกินไป เป็นไปได้โดยไม่สูญเสียความสามารถในการขัดจังหวะและล่าช้าหรือไม่

Koen

แก้ไขการตั้งค่านี้ให้ผลลัพธ์แบบ 16 บิต

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

คำตอบ:


16

Arduino Uno ใช้ไมโครคอนโทรลเลอร์ ATmega382P ชิปนี้มีตัวจับเวลา 8 บิตสองตัวขับสองช่องสัญญาณ PWM แต่ละช่องและตัวจับเวลา 16 บิตหนึ่งช่องขับสองช่องทางสุดท้าย

คุณไม่สามารถเพิ่มความละเอียดของตัวจับเวลา 8 บิตได้ อย่างไรก็ตามคุณสามารถใส่ตัวจับเวลา 16 บิตในโหมด 16 บิตแทนโหมด 8 บิตที่ใช้โดยไลบรารีหลักของ Arduino สิ่งนี้จะช่วยให้คุณมีช่องสัญญาณ PWM 16 บิตสองช่องด้วยความถี่ที่ลดลง 244 Hz (สูงสุด) คุณอาจจะต้องกำหนดค่าตัวจับเวลาด้วยตนเองและจะไม่ได้รับประโยชน์จากanalogWrite()ฟังก์ชั่นที่ใช้งานง่าย ดูรายละเอียดในส่วนที่เกี่ยวกับเวลา 1 ในในแผ่นข้อมูล ATmega328P

อัพเดท : ที่นี่คือการดำเนินการ analogWrite()16 ใช้งานได้กับพิน 9 และ 10 เท่านั้นเนื่องจากเป็นพินเท่านั้นที่เชื่อมต่อกับตัวจับเวลา 16 บิต

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

คุณอาจสังเกตเห็นว่ามีการกำหนดค่าลำดับบนสุดของเคาน์เตอร์อย่างชัดเจน คุณสามารถเปลี่ยนเป็นค่าที่น้อยลงเพื่อทำให้ PWM เร็วขึ้นโดยที่ค่าความละเอียดลดลง

และนี่คือตัวอย่างภาพร่างที่แสดงถึงการใช้งาน:

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);
}

ว้าวขอบคุณมากนี่คือสิ่งที่ฉันต้องการ ฉันต้องการผลลัพธ์ PWM ของฉันจะเหมือนกับความละเอียดเซ็นเซอร์ของฉัน หากฉันเปลี่ยนรหัสของคุณเป็น <ดูการแก้ไขของฉัน> มันจะเป็นผลลัพธ์แบบ 13 บิตหรือไม่ ถ้าเป็นเช่นนั้นความถี่จะเป็นอย่างไร ฉันจะขับมอเตอร์ DC ด้วยดังนั้น 244Hz จะน้อยกว่านี้ฉันเดา
KoenR

@KenR: ไม่พรีสเกลเลอร์ไม่มีผลต่อความละเอียดจึงมีวัตถุประสงค์เพื่อชะลอการนับ การตั้งค่าพรีสเกลเลอร์เป็น 8 จะให้ความถี่ PWM เท่ากับ 30.5 Hz หากคุณต้องการความละเอียด 13 บิตตั้งไว้ICR1ที่0x1fffความถี่ของคุณจะเป็น 1,953 Hz (F_CPU / (สูงสุด + 1)) โดยมีพรีสเกลเลอร์ที่ 1
Edgar Bonet

ขอบคุณสำหรับคำอธิบาย แก้ไขคำถามของฉันเพื่อให้ครอบคลุมข้อผิดพลาดเหล่านี้ ดังนั้นคนอื่น ๆ สามารถดูได้โดยตรง ขอบคุณ!
KoenR

1
@Edgar Bonet อันนี้ยอดเยี่ยม แต่ฉันไม่สามารถปิดไฟ LED ได้อย่างสมบูรณ์ ฉันกำลังใช้งานอยู่ICR1 = 0x03FFและที่ 0 ฉันเห็นพัลส์เล็ก ๆ บนขอบเขตเพียงพอที่จะส่องนำ ความคิดใด ๆ
davivid

1
@davivid: ใช่คุณไม่มีรอบการทำงานเป็นศูนย์ analogWrite16(pin, val)ให้รอบการทำงานของ (val + 1) / ICR1 เป็นวิธีแก้ปัญหา, Arduino ของไม่analogWrite() if (val == 0) digitalWrite(pin, LOW); else if (val == 255) digitalWrite(pin, HIGH);แต่คุณจะไม่สามารถรับรอบหน้าที่ 1 / ICR1 ...
เอ็ดการ์

3

ด้วยการปรับเทียบบางอย่างคุณสามารถรวมเอาท์พุทของสองช่องสัญญาณ PWM กับตัวต้านทานน้ำหนักที่แตกต่างกัน ที่สุดขีดคุณสามารถใช้งานหนึ่งเอาต์พุตเพื่อให้ความละเอียด 8 บิตและปรับเพิ่มอีกหนึ่งถึงระดับ 1/255 และเพิ่มเข้าไปดังนั้นช่องที่ 2 ครอบคลุมช่วงหนึ่งบิตและคุณ (อีกครั้งที่คิด) รับความละเอียด 16 บิต หากไม่มีการดูแลและปรับอย่างเต็มที่สิ่งที่คุณจะได้รับก็คือความยุ่งเหยิง
อย่างไรก็ตามโดยการหารช่องที่ 2 ด้วย 16 หรือ 32 คุณสามารถเพิ่มความละเอียด PWM เพิ่มเติมได้หลายบิต เพียงแค่เพิ่มเอาต์พุตแบบอะนาล็อกที่กรอง 2 ช่องแบบอะนาล็อกคุณจะเพิ่มบิตพิเศษ
Notionally (อีกครั้ง) สำหรับทุก ๆ การหารด้วย 2 คุณจะได้รับความละเอียดเพิ่มขึ้นเล็กน้อย แต่สามารถทำได้สำหรับบิตพิเศษ 4 หรือ 5 หรือ 6 เท่านั้นโดยเพิ่มความต้องการความแม่นยำของตัวต้านทานการปรับขนาดและการสอบเทียบที่ยากขึ้น .

ตัวอย่างสั้น ๆ
หากหนึ่ง PWM ถูกย่อขนาดลงเพื่อให้ 0 - 255 mV ในขั้นตอนที่ 1 mV จากนั้นการรวมสอง PWM ที่มีแอมพลิจูดเท่ากันจะให้ช่วง 0 - 510 mV ใน 1 mV step
หากหนึ่ง PWM ถูกลดขนาดลงด้วยปัจจัย 32 แล้วแทนที่จะเพิ่ม 255 mV ไปยังช่วง PWM เริ่มต้นมันจะเพิ่มเพียง 8 mV ไปที่ปลายด้านบน (0.256.32 = 8 mV แต่ความละเอียดจะอยู่ที่ 0.03125 (1 / 32nd) ) ขั้นตอน mV

ในขณะที่สิ่งนี้อาจทำได้ด้วยการรวมตัวต้านทานและการกรอง RC อย่างสมบูรณ์การใช้ op amp ฤดูร้อนจะช่วยปรับปรุงผลลัพธ์อย่างมาก

นอกจากนี้ยังสามารถกรองระลอก PWM ด้วยตัวกรอง RC แบบง่าย ๆ แต่ใช้หนึ่ง opamp เป็นบัฟเฟอร์ (หรือแม้แต่ทรานซิสเตอร์เดียวในฐานะผู้ติดตาม emitter) จะให้ 3 หรือ 5 ขั้วของการกรองผ่านต่ำและโอกาสที่ดีกว่าในการบรรลุ PWM เพิ่มเติม ความละเอียด ฉันไม่ได้ตรวจสอบ "phase coherence" ของเอาต์พุต PWM แต่คาดว่าพวกมันจะเคลื่อนที่เป็นล๊อคสัมพัทธ์ดังนั้นคุณจะไม่ได้รับข้อได้เปรียบที่ราบรื่นในการเพิ่มรูปคลื่นสองอันที่ไม่เกี่ยวข้อง

ความคิดเห็นเพิ่มเติมสามารถทำได้ถ้าจำเป็น ถามว่าสนใจ


นี่มันฉลาด! ดูเหมือนว่าห้องสมุดการสังเคราะห์เสียง Mozziใช้เคล็ดลับนี้เพื่อเรียกว่าโหมด "ไฮไฟ"
Edgar Bonet

นั่นคือเราที่ยอดเยี่ยมของ PWM แต่สิ่งนี้จะทำให้รูปคลื่นไม่ราบรื่นหรือไม่? ฉันถามสิ่งนี้เพราะคุณใช้ตัวกรอง RC ยังไม่ได้พูดถึงเรื่องนี้ในคำถามของฉัน แต่ฉันกำลังขับมอเตอร์ DC ด้วย <รู้สึกละอายใจ> ขอบคุณสำหรับการป้อนข้อมูล!
KoenR

@KenR (fwiw: ฉันไม่เห็นว่าจะละอายอะไร) ฉันไม่รู้ว่าการตอบสนองความถี่ / อัตราการเปลี่ยนแปลงที่คุณต้องการในเอาต์พุต ADC ของคุณคืออะไร หรือทำไมคุณต้องการ N บิตหรือว่าใหญ่พอ โดยปกติแล้วมอเตอร์จะไม่ถูกควบคุมอย่างเป็นประโยชน์มากกว่า 8 บิตขึ้นอยู่กับความแม่นยำของแอปพลิเคชันที่คุณมี มอเตอร์ทำหน้าที่เป็นส่วนหนึ่งของตัวกรองที่ปรับให้เรียบเนื่องจากการเหนี่ยวนำ คุณต้องบอกว่ามอเตอร์ประเภทไหนและขับเคลื่อนอย่างไร และวงจรไดอะแกรมนั้นสำคัญมาก ยกเว้นว่ามอเตอร์มีขนาดเล็กคุณก็มีไดรเวอร์ มอเตอร์ที่ป้อนแปรงแล้ว PWM จะต้องมีไดโอดตรวจจับเพื่อส่งกระแสมอเตอร์เมื่อปิด PWM กำลังเพิ่มสอง ...
รัสเซลแม็คมาฮอน

... PWM ที่นี่สามารถทำได้อย่างเป็นทางการ แต่ต้องทราบรายละเอียดของวงจร
รัสเซลแม็คมาฮอน

ระวัง! ในบางกรณีการปรับ PWM ให้ราบรื่นโดยใช้ low pass RC นั้นไม่เป็นที่ต้องการ ตัวอย่างเช่นถ้าคุณเสียบเอาท์พุท Arduino เข้ากับเกทของ MOSFET MOSFET จะเย็นลงตราบใดที่มันถูกขับเคลื่อนด้วย PWM ที่สะอาด แต่ถ้าคุณปรับให้เรียบ MOSFET จะเริ่มกระจายความร้อนมากขึ้น บางครั้งนั่นไม่ใช่สิ่งที่ดี
Florin Andrei
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.