เพิ่มความละเอียดบิต 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.