การเพิ่มความถี่ Arduino PWM เราเชี่ยวชาญเรื่อง PWM ในบริษัทอันอบอุ่นของ Arduino และ RGB LED คำแนะนำในการใช้ PWM ใน Arduino

และเรามาลองทำภารกิจใหม่ให้สำเร็จกันเถอะ ฉันคิดว่าทุกคนคงเคยเห็นมาลัยแสดงปีใหม่ซึ่งมีไฟ LED กระพริบอย่างราบรื่น สมมติว่าเราอยากทำสิ่งนี้
เราได้ดูฟังก์ชัน digitalWrite() แล้ว และรู้ว่าค่าที่ฟังก์ชันเขียนอาจมีได้สองตัวเลือก - สูงหรือ ระดับต่ำ- ใน ในกรณีนี้ฟังก์ชั่น analogWrite() จะช่วยเราได้ "สูตร" ของฟังก์ชันจะแตกต่างกันเฉพาะในส่วนนำหน้าเริ่มต้นเท่านั้น ดังนั้นจึงง่ายต่อการจดจำ

ฟังก์ชัน analogWrite() เช่นเดียวกับ digitalWrite() มีสองอาร์กิวเมนต์ในวงเล็บและทำงานบนหลักการทางวาจาเดียวกัน: “ที่ไหน อะไร” ความแตกต่างที่สำคัญคือความสามารถในการบันทึก หลากหลายค่าแทนที่จะเป็น LOW หรือ HIGH ปกติ ซึ่งจะทำให้เราสามารถปรับความสว่างของ LED ได้ ประเด็นหลักที่ต้องคำนึงถึงก็คือ ฟังก์ชั่นนี้ใช้งานได้เท่านั้น ผู้ติดต่อบางราย- หมุดเหล่านี้มีสัญลักษณ์ "~" กำกับอยู่ สัญลักษณ์นี้ระบุว่านี่คือหน้าสัมผัส PWM PWM (การปรับความกว้างพัลส์) เสียงเหมือน PWM (การปรับความกว้างพัลส์) ในภาษารัสเซีย หลักการทำงานขึ้นอยู่กับการเปลี่ยนระยะเวลาการเต้นของชีพจร ในเชิงกราฟิกสามารถอธิบายได้ดังนี้:

ลองหาวิธีทำงานโดยดูจากตัวอย่างง่ายๆ ในการดำเนินการนี้ คุณจะต้องเชื่อมต่อ LED เข้ากับหน้าสัมผัส PWM ผ่านตัวต้านทาน 150 โอห์ม และ "ฮาร์ดไวร์" เข้ากับ Arduino โปรแกรมง่ายๆ- แผนภาพการเชื่อมต่อและรหัสร่างมีดังต่อไปนี้:


การตั้งค่าเป็นโมฆะ ()
{
pinMode (นำ, เอาท์พุท);
}

เป็นโมฆะวน()
{
สำหรับ(int i=0; i<=255; i++)
{
อะนาล็อกเขียน (นำฉัน);
ล่าช้า(10);
}
สำหรับ(int i=255; i>=0; i--)
{
อะนาล็อกเขียน (นำฉัน);
ล่าช้า(10);
}
}


ฉันคิดว่าโดยทั่วไปแล้วรหัสมีความชัดเจน แต่ต้องให้ความสนใจเล็กน้อย สำหรับวง- มีสิ่งเช่นการอนุญาต เนื่องจากเรากำลังทำงานกับความละเอียด 8 บิต (จะมีการพูดคุยกันในภายหลัง) ค่าต่ำสุดจะตรงกับ 0 และค่าสูงสุดจะตรงกับ 255 เมื่อสิ้นสุดการวนซ้ำแต่ละครั้ง เราจะตั้งค่าการหน่วงเวลาเป็น 10ms

กลับไปที่ไดอะแกรมจากบทเรียนที่แล้วแล้วลองสร้างพวงมาลัยที่คล้ายกันโดยใช้ฟังก์ชัน analogWrite()


ปุ่ม intPin = 2;
พิน int = (3,5,6,9,10,11);

บูลีน LastButton = ต่ำ;
บูลีน currentButton = ต่ำ;
เปิดใช้งานบูลีน = เท็จ;

การตั้งค่าเป็นโมฆะ ()
{
pinMode(ปุ่มพิน, อินพุต);
สำหรับ (โหมด int = 0; mode<= 5; mode++) pinMode(pins, OUTPUT);
}

debounce บูลีน (บูลีนสุดท้าย)
{
บูลีนปัจจุบัน = digitalRead (buttonPin);
ถ้า (สุดท้าย! = ปัจจุบัน)
{
ล่าช้า(5);
ปัจจุบัน = digitalRead (buttonPin);
}
กลับปัจจุบัน;
}

เป็นโมฆะวน()
{
currentButton = debounce (ปุ่มสุดท้าย);
ถ้า (lastButton == ต่ำ && currentButton == สูง)
{
เปิดใช้งาน = !เปิดใช้งาน;
}

ถ้า (เปิดใช้งาน == จริง)
{
สำหรับ (int i=0; i<=5; i++)
{
สำหรับ (ความสว่าง int = 0; ความสว่าง<= 255; brightness++)
{
ล่าช้า(1);
}
ล่าช้า(40);
}
สำหรับ (int i=0; i<=5; i++)
{
สำหรับ (ความสว่าง int = 255; ความสว่าง >= 0; ความสว่าง--)
{
analogWrite (พิน [i] ความสว่าง);
ล่าช้า(1);
}
ล่าช้า(40);
}
}

ถ้า (เปิดใช้งาน == เท็จ)
{
สำหรับ(int i = 0; i<= 5; i++) digitalWrite(pins[i], LOW);
}

LastButton = ปุ่มปัจจุบัน;
}


สายตาภาพร่างค่อนข้างซับซ้อนมากขึ้น ที่จริงแล้วทุกอย่างเรียบง่ายที่นี่แล้วเรามาดูกันดีกว่า เราจำเป็นต้องระบุ LED ที่เชื่อมต่อทั้งหมด แต่แทนที่จะใช้ int led ตามปกติ เราจะใช้อาร์เรย์ ซึ่งแต่ละองค์ประกอบจะเป็นพิน PWM บน Arduino ในเนื้อหาของฟังก์ชัน void setup() เรายังดำเนินการอย่างมีไหวพริบอีกด้วย เรามอบ "รายการ" ของผู้ติดต่อทั้งหมดให้กับลูป for() โดยแต่ละครั้งจะมีการกำหนดค่าผู้ติดต่อที่เกี่ยวข้องบน OUTPUT มาดูฟังก์ชัน void loop() กันดีกว่า ฟังก์ชัน debounce() และเงื่อนไข if() เริ่มต้นยังคงไม่เปลี่ยนแปลง เรายังคงตรวจสอบระดับของตัวแปรสองตัว: ค่าก่อนหน้า (เริ่มแรกคือ LOW) และสถานะปัจจุบันของปุ่ม เมื่อตรงตามเงื่อนไขเหล่านี้ ค่าของตัวแปรเปิดใช้งานจะถูกกลับด้าน ด้วยเหตุนี้ เราจึงได้เพิ่มเงื่อนไข if() ที่เรียบง่ายอีกสองเงื่อนไข หากเปิดใช้งาน = จริง แสดงว่าพวงมาลัยเปิดอยู่ ความราบรื่นของ "โฟลว์" ซึ่งควบคุมโดยลูป for() หากเปิดใช้งาน = false ไฟ LED ทั้งหมดจะถูกปิด เมื่อสิ้นสุดเงื่อนไข ตัวแปร LastButton จะใช้สถานะปัจจุบันของปุ่ม
ขณะทดสอบโปรแกรมของเรา เราสังเกตเห็นว่าทุกอย่างไม่ทำงานตามที่คาดไว้ โปรดจำไว้ว่าในบทเรียนที่แล้วเราได้ทำการแก้ไขว่าหากการหน่วงเวลามีขนาดใหญ่ ปุ่มจะถูกทริกเกอร์หลังจากหมดอายุแล้ว ในตัวอย่างก่อนหน้านี้ เมื่อพวงมาลัยถูกเปิด ความล่าช้ารวมในร่างกายของฟังก์ชัน void loop() คือ 85ms สิ่งนี้ทำให้เรามีโอกาส "ไปถึงจุดนั้น" ภายในช่วงระยะเวลาหนึ่ง ในภาพร่างนี้ ภายใต้เงื่อนไขเดียวกัน ความล่าช้าจะต่างกันหลายครั้ง บางทีถ้าคุณต้องการปิดพวงมาลัยคำว่า "ขัดจังหวะ" ก็แนะนำตัวเอง นี่จะเป็นวิธีแก้ปัญหานี้!

ฉันหวังว่าบทความนี้จะเป็นประโยชน์กับคุณ ในบทช่วยสอนถัดไป เราจะดูการขัดจังหวะใน Arduino และบรรลุผลลัพธ์ที่ต้องการ

การมอดูเลตความกว้างพัลส์ (PWM) เป็นเรื่องสนุกและสนุกเป็นพิเศษเมื่อใช้ควบคุมเซอร์โว แต่วันนี้เราจะนำไปใช้กับ LED สามสี สิ่งนี้จะช่วยให้เราสามารถควบคุมสีของมันและสร้างรูปลักษณ์ที่สวยงามได้

พีเอ็มดับเบิลยู

คำจำกัดความของ PWM ได้รับการกำหนดขึ้นอย่างชาญฉลาดใน Wikipedia ดังนั้นฉันจะคัดลอกมันจากที่นั่น: "พีดับเบิลยูเอ็ม- การประมาณสัญญาณที่ต้องการ (หลายระดับหรือต่อเนื่อง) กับสัญญาณไบนารีจริง (มีสองระดับ -เปิด/ปิด ) ดังนั้นโดยเฉลี่ยในช่วงระยะเวลาหนึ่งค่าของมันจะเท่ากัน <...> IM เป็นสัญญาณพัลส์ที่มีความถี่คงที่และแปรผันรอบหน้าที่ นั่นคืออัตราส่วนของระยะเวลาการทำซ้ำของพัลส์ต่อระยะเวลา โดยกำหนดรอบการทำงาน (ระยะเวลาพัลส์)คุณสามารถเปลี่ยนแรงดันไฟฟ้าเฉลี่ยที่เอาต์พุต PWM. "


ตอนนี้เรามาดูกันว่านี่หมายถึงอะไร ให้มีสัญญาณสี่เหลี่ยมธรรมดาดังนี้




มีความถี่คงที่และรอบการทำงาน 50% ซึ่งหมายความว่าครึ่งหนึ่งของช่วงแรงดันไฟฟ้าสูงสุด และอีกครึ่งหนึ่งเป็นศูนย์ เมื่อรวมสัญญาณนี้เข้าด้วยกันในช่วงเวลาหนึ่ง เราจะเห็นว่าพลังงานของมันมีค่าเท่ากับครึ่งหนึ่งของค่าสูงสุด นี่จะเท่ากับถ้าเรา ตลอดเวลาใช้แรงดันไฟฟ้าครึ่งหนึ่ง


หากแรงดันไฟฟ้าสูงสุดของเราคือ 5 V แรงดันไฟฟ้าที่ได้รับที่เอาต์พุต PWM จะเท่ากับรอบการทำงานคูณด้วย 5 V (และหารด้วย 100% เพื่อไม่ให้พวกนาซีที่เป็นทางการติด):


Arduino อนุญาตให้คุณเขียนค่าตั้งแต่ 0 ถึง 255 ไปยังเอาต์พุต PWM ซึ่งหมายความว่าเราสามารถรับแรงดันไฟฟ้าที่มีความละเอียดประมาณ 20 mV


ไฟ LED สามสี

นี่เขาเป็นชายหนุ่มรูปหล่อสี่ขา:


ขาที่ยาวที่สุดคือขั้วบวกทั่วไปและส่วนที่เหลือทั้งหมดเป็นแคโทดซึ่งแต่ละอันรับผิดชอบสีของตัวเอง: (ดูภาพ) ด้านล่างเป็นสีแดง ขาที่สองจากด้านบนเป็นสีเขียว ด้านบนเป็นสีน้ำเงิน

หากคุณใช้ +5V กับขายาวและ 0V กับขาอื่นๆ ทั้งหมด คุณจะได้แสงสีขาว (ฉันขอร้องล่ะ ป้องกันตัวเอง - ติดตั้งตัวต้านทานแบบจำกัด!) ความขาวแค่ไหนสามารถตัดสินได้จากวิดีโอต่อไปนี้:


แต่การได้สีขาวนั้นไม่น่าสนใจเลย มาดูวิธีทำให้มีชิมเมอร์เป็นสีต่างๆ กัน

PWM บน Arduino

ความถี่ PWM บน Arduino อยู่ที่ประมาณ 490 Hz บนบอร์ด Arduino UNO พินที่สามารถใช้สำหรับ PWM คือ 3,5,6, 9, 10 และ 11 มีคำแนะนำสำหรับสิ่งนี้บนกระดาน - มีเครื่องหมายตัวหนอนหรือคมในซิลค์สกรีนก่อนหมายเลขพิน PWM .

ไม่มีอะไรง่ายไปกว่าการควบคุม PWM บน Arduino! เมื่อต้องการทำเช่นนี้ ให้ใช้ฟังก์ชันเดียว analogWrite (พิน, ค่า), ที่ไหน เข็มหมุด- หมายเลขพิน และ ค่า- ค่าตั้งแต่ 0 ถึง 255 ในกรณีนี้ คุณไม่จำเป็นต้องเขียนอะไรเลย การตั้งค่าเป็นโมฆะ ()!

คุณสามารถอ่านเพิ่มเติมเกี่ยวกับเรื่องนี้ในภาษาอังกฤษและ

เราทำงานค่อนข้างน้อย

มาทำให้ LED ระยิบระยับเป็นสีต่างๆ กัน ปล่อยให้สีหนึ่งจางหายไปในขณะที่อีกสีหนึ่งสว่างขึ้น เราจะสลับสีกันสองสามสี และสีจะเคลื่อนที่เป็นวงกลมจากสีแดงเป็นสีเขียว จากสีเขียวเป็นสีน้ำเงิน จากสีน้ำเงินเป็นสีแดง

มาสร้างแผนภาพง่ายๆ กัน:


และมาเขียนโค้ดง่ายๆ:

//ตั้งชื่อพินตามสี
int REDpin = 9;
int กรีนพิน = 10;
อินท์บลูพิน = 11;

เป็นโมฆะ การตั้งค่า (){}

เป็นโมฆะ วนซ้ำ (){
สำหรับ (ค่า int = 0 ; value<= 255; value +=1) {
//ความสว่างสีแดงลดลง
analogWrite (REDpin, ค่า);
// ความสว่างสีเขียวเพิ่มขึ้น
analogWrite (พินสีเขียว, ค่า 255);
//สีน้ำเงินปิดอยู่
อะนาล็อกเขียน(BLUEpin, 255);
//หยุดชั่วคราว
ล่าช้า(30);
}

สำหรับ (ค่า int = 0 ; value<= 255; value +=1) {
//สีแดงปิดอยู่
อะนาล็อกเขียน (REDpin, 255);
// ความสว่างสีเขียวลดลง
analogWrite (พินสีเขียว, ค่า);
// ความสว่างสีน้ำเงินเพิ่มขึ้น
อะนาล็อกเขียน (BLUEpin, ค่า 255);
//หยุดชั่วคราว
ล่าช้า(30);
}

สำหรับ (ค่า int = 0 ; value<= 255; value +=1) {
//ความสว่างสีแดงเพิ่มขึ้น
analogWrite (REDpin, ค่า 255);
//สีเขียวปิดอยู่
อะนาล็อกเขียน (พินสีเขียว, 255);
// ความสว่างสีน้ำเงินลดลง
อะนาล็อกเขียน (BLUEpin, ค่า);
//หยุดชั่วคราว
ล่าช้า(30);
}
}

ประมาณ 3 เดือนที่ผ่านมา เช่นเดียวกับอุปกรณ์อิเล็กทรอนิกส์ที่โชคร้ายอื่นๆ ในความคิดของฉันในเวลานั้น ฉันซื้อบอร์ดไมโครโปรเซสเซอร์ที่ซับซ้อนที่สุดจากตระกูล Arduino คือ Seeeduino Mega ที่ใช้โปรเซสเซอร์ Atmega1280 หลังจากที่ปรนเปรอตัวเองจนพอใจด้วยเซอร์โวไดรฟ์ที่หมุนได้และไฟ LED กะพริบ คำถามก็เกิดขึ้น: “ทำไมฉันถึงซื้อมัน?”

ฉันทำงานเป็นหนึ่งในนักออกแบบชั้นนำที่โรงงานทางทหารขนาดใหญ่ในเซเลโนกราด และปัจจุบันเป็นผู้นำโครงการพัฒนาเครื่องมือวัดทางมาตรวิทยา งานนี้มีปัญหาจำนวนอนันต์ซึ่งต้องการวิธีแก้ไขเฉพาะบุคคล หนึ่งในงานเหล่านี้คือการควบคุมสเต็ปเปอร์มอเตอร์โดยไม่มีเสียงรบกวนและอยู่ในขั้นที่ไม่ 1.8 องศา ตามที่ระบุไว้ในเอกสารประกอบของสเต็ปเปอร์มอเตอร์ แต่สูงถึง 0.0001 องศา ดูเหมือนว่าปัญหาจะซับซ้อนและแก้ไขไม่ได้ แต่หลังจากแก้ไขวงจรควบคุมเล็กน้อยฉันก็ได้ข้อสรุปว่าทุกสิ่งมีจริงและเป็นไปได้ ต้องการเพียงการสร้างสัญญาณสองสัญญาณที่มีรูปร่างเฉพาะและมีการเปลี่ยนเฟสและความถี่ในการเปลี่ยนแปลงแรงดันไฟฟ้าสูงถึง 1 MHz (ฉันจะเขียนการศึกษาโดยละเอียดเกี่ยวกับสเต็ปเปอร์มอเตอร์และเปิดเผยความลับทั้งหมดของการควบคุมในบทความถัดไป) ความหวังอันริบหรี่เริ่มปรากฏในหัวของฉันทันทีว่าฉันไม่ได้ใช้เงิน 1,500 รูเบิลไปอย่างไร้ประโยชน์กับ Seeeduino สีแดงตัวน้อยของฉัน และฉันก็เริ่มคิดออกด้วยความกระตือรือร้น

ความสยองขวัญเบื้องต้น:

หลังจากเชื่อมต่อบอร์ดไมโครโปรเซสเซอร์เข้ากับออสซิลโลสโคป และเขียนวงจร digitalWrite(HIGH) และต่ำกว่า digitalWrite(LOW) ฉันพบคลื่นสี่เหลี่ยมที่ค่อนข้างทื่อซึ่งมีความถี่ 50Hz บนออสซิลโลสโคป มันเป็นฝันร้าย ฉันคิดว่านี่เป็นการล่มสลายเมื่อเทียบกับพื้นหลังของ 1 MHz ที่ต้องการ
ต่อไป ฉันศึกษาความเร็วการประมวลผลเพิ่มเติมหลายประการผ่านออสซิลโลสโคป:
AnalogRead() - ความเร็วในการดำเนินการ 110 µs
อะนาล็อกเขียน() - 2000 µs
SerialPrintLn() - ที่ความเร็ว 9600 ประมาณ 250 µs และที่ความเร็วสูงสุดประมาณ 3 µs
DigitalWrite() - 1800µs
DigitalRead() - 1900µs

เมื่อมาถึงจุดนี้ ฉันน้ำตาไหลและเกือบจะโยน Seeeduino ของฉันออกไป แต่นั่นไม่เป็นเช่นนั้น!

ตากลัวมือก็ทำ!

ฉันจะไม่บอกคุณเกี่ยวกับความเจ็บปวดทางจิตของฉันและอธิบายการเรียนที่ยาวนานสามวัน เป็นการดีกว่าที่จะบอกตามความเป็นจริง!
หลังจากค้นหาเอกสารที่เป็นไปได้ทั้งหมดเกี่ยวกับ Arduino และโปรเซสเซอร์ Atmega1280 และค้นคว้าประสบการณ์ของเพื่อนร่วมงานชาวต่างชาติแล้ว ฉันอยากจะเสนอเคล็ดลับบางประการเกี่ยวกับวิธีแทนที่การอ่าน/เขียน:
การปรับปรุง AnalogRead()
#กำหนด FASTADC 1

// กำหนดสำหรับการตั้งค่าและการล้างบิตรีจิสเตอร์
#ifndef ซีบีไอ
#define cbi(sfr, บิต) (_SFR_BYTE(sfr) &= ~_BV(บิต))
#เอ็นดิฟ
#ifndefsbi
#define sbi(sfr, บิต) (_SFR_BYTE(sfr) |= _BV(บิต))
#เอ็นดิฟ

การตั้งค่าเป็นโมฆะ() (
อินท์เริ่มต้น ;
ฉัน;

#ถ้าฟาสต้าดีซี
// ตั้งค่าพรีสเกลเป็น 16
sbi(ADCSRA,ADPS2) ;
cbi(ADCSRA,ADPS1) ;
cbi(ADCSRA,ADPS0);
#เอ็นดิฟ

อนุกรม.เริ่มต้น(9600) ;
Serial.print("ADCTEST: ") ;
start = มิลลิวินาที() ;
สำหรับ (i = 0 ; i< 30000 ; i++)
อะนาล็อกอ่าน(0) ;
Serial.print(มิลลิวินาที() - เริ่มต้น);
Serial.println(" msec (30,000 สาย)" ;
}

โมฆะวน() (
}

ผลลัพธ์: ความเร็ว 18.2 ไมโครวินาทีกับแฟนเก่า 110 ไมโครวินาที.
อย่างไรก็ตาม ความเร็วสูงสุดของ Atmega ADC อยู่ที่เพียง 16 ไมโครวินาที อีกทางเลือกหนึ่งคือใช้ไมโครวงจรอื่นที่ออกแบบมาสำหรับ ADC โดยเฉพาะซึ่งจะลดความเร็วลง 0.2µs(อ่านด้านล่างว่าทำไม)

การปรับปรุง digitalWrite()
Arduino/Seeeduino/Feduino/Orduino/otherduino ทุกตัวมีพอร์ต แต่ละพอร์ตมีขนาด 8 บิต ซึ่งจะต้องกำหนดค่าสำหรับการบันทึกก่อน ตัวอย่างเช่นบน Seeeduino PORTA ของฉัน - ตั้งแต่ 22 ถึง 30 ขา ตอนนี้ทุกอย่างเป็นเรื่องง่าย เราควบคุมขา 22 ถึง 30 โดยใช้ฟังก์ชัน
PORTA=B00001010 (บิต ขา 23 และ 25 - สูง)
หรือ
PORTA=10 (ทศนิยมยังคงเหมือนเดิม)
ผลลัพธ์ =0.2µsขัดต่อ 1800usซึ่งทำได้โดย digitalWrite() ธรรมดา
การปรับปรุง digitalRead()
เกือบจะเหมือนกับการปรับปรุงด้วย digitalWrite() แต่ตอนนี้เราตั้งค่าขาเป็น INPUT และใช้ตัวอย่างเช่น:
if (PINA==B00000010) (...) (หาก HIGH อยู่ที่ขา 23 และ LOW อยู่ที่ขา 22 และ 24-30)
ผลลัพธ์ทำสิ่งนี้ if() - 0.2µsขัดต่อ 1900µsซึ่งทำได้โดย digitalRead() ตามปกติ
การปรับปรุงโมดูเลเตอร์ PWM หรือ analogWrite()
ดังนั้นจึงมีหลักฐานว่า digitalRead() ดำเนินการใน 0.2 µs และโมดูเลเตอร์ PWM มีความละเอียด 8 บิต เวลาเปลี่ยน PWM ขั้นต่ำคือ 51.2 µs เทียบกับ 2000 µs
เราใช้รหัสต่อไปนี้:
int PWM_time=32; //ตัวเลขที่เราอยากจะเขียนลง analogWrite(PIN, 32)
สำหรับ (int k=0;k สำหรับ (int k=0;k<256-PWM_time) PORTA=B00000000;

ดังนั้นเราจึงได้มัน PWM พร้อมความถี่ 19กิโลเฮิร์ตซ์ขัดต่อ 50เฮิร์ต

มาสรุปกัน

digitalWrite() เคยเป็น 1800usมันกลายเป็น 0.2µs
digitalRead() เคยเป็น 1900µsมันกลายเป็น 0.2µs
analogWrite() คือ 2000usมันกลายเป็น 51.2µs
analogRead() เคยเป็น 110µsมันกลายเป็น 18.2ไมโครวินาทีหรืออาจจะจนกระทั่ง 0.2µs

ตัวอย่างเช่น);

  • ตัวต้านทานที่มีค่าเล็กน้อย 190...240 โอห์ม (นี่คือชุดตัวต้านทานที่ยอดเยี่ยมที่มีค่าทั่วไปที่สุด)
  • คอมพิวเตอร์ส่วนบุคคลที่มีสภาพแวดล้อมการพัฒนา Arduino IDE
  • คำแนะนำในการใช้ PWM ใน Arduino

    1 ข้อมูลทั่วไปเกี่ยวกับการมอดูเลตความกว้างพัลส์

    หมุดดิจิทัล Arduino สามารถส่งออกค่าได้เพียงสองค่าเท่านั้น: ลอจิก 0 (ต่ำ) และลอจิก 1 (สูง) นั่นเป็นเหตุผลว่าทำไมพวกเขาถึงเป็นดิจิทัล แต่ Arduino มีพิน "พิเศษ" ซึ่งได้รับการกำหนดไว้ พีเอ็มดับเบิลยู- บางครั้งจะมีการแสดงด้วยเส้นหยัก "~" หรือวงกลมหรือแตกต่างจากที่อื่น PWM ย่อมาจาก การมอดูเลตความกว้างพัลส์หรือ การมอดูเลตความกว้างพัลส์, พีเอ็มดับเบิลยู.

    สัญญาณมอดูเลตความกว้างพัลส์เป็นสัญญาณพัลส์ที่มีความถี่คงที่ แต่แปรผันได้ รอบหน้าที่(อัตราส่วนของระยะเวลาพัลส์และระยะเวลาการทำซ้ำ) เนื่องจากข้อเท็จจริงที่ว่ากระบวนการทางกายภาพส่วนใหญ่ในธรรมชาติมีความเฉื่อย แรงดันไฟฟ้าที่ลดลงกะทันหันจาก 1 ถึง 0 จะถูกทำให้เรียบลง โดยใช้ค่าเฉลี่ยจำนวนหนึ่ง ด้วยการตั้งค่ารอบการทำงาน คุณสามารถเปลี่ยนแรงดันไฟฟ้าเฉลี่ยที่เอาต์พุต PWM ได้

    หากรอบการทำงานเป็น 100% เอาต์พุตดิจิทัลของ Arduino จะมีแรงดันไฟฟ้าลอจิคัลเป็น "1" หรือ 5 โวลต์เสมอ หากคุณตั้งค่ารอบการทำงานเป็น 50% ครึ่งหนึ่งของเวลาที่เอาต์พุตจะเป็นตรรกะ "1" และครึ่งหนึ่งของเวลา - ตรรกะ "0" และแรงดันไฟฟ้าเฉลี่ยจะเป็น 2.5 โวลต์ และอื่นๆ


    ในโปรแกรม รอบการทำงานไม่ได้ระบุเป็นเปอร์เซ็นต์ แต่เป็นตัวเลขตั้งแต่ 0 ถึง 255 ตัวอย่างเช่น คำสั่ง อะนาล็อกเขียน(10, 64)จะบอกไมโครคอนโทรลเลอร์ให้ส่งสัญญาณด้วยรอบการทำงาน 25% ไปยังเอาต์พุต PWM ดิจิทัลหมายเลข 10

    พิน Arduino พร้อมฟังก์ชันการปรับความกว้างพัลส์ทำงานที่ความถี่ประมาณ 500 Hz ซึ่งหมายความว่าระยะเวลาการเกิดซ้ำของพัลส์จะอยู่ที่ประมาณ 2 มิลลิวินาที ซึ่งวัดโดยเส้นแนวตั้งสีเขียวในรูป

    ปรากฎว่าเราสามารถจำลองสัญญาณอะนาล็อกบนเอาต์พุตดิจิทัลได้!น่าสนใจใช่ไหมล่ะ!

    เราจะใช้ PWM ได้อย่างไร? แอปพลิเคชั่นมากมาย! เช่น ควบคุมความสว่างของ LED, ความเร็วการหมุนของมอเตอร์, กระแสของทรานซิสเตอร์, เสียงจากตัวปล่อยพีโซ ฯลฯ....

    2 แผนภาพสำหรับการสาธิตการปรับความกว้างพัลส์ใน Arduino

    มาดูตัวอย่างพื้นฐานที่สุด - การควบคุมความสว่างของ LED โดยใช้ PWM มารวบรวมโครงร่างแบบคลาสสิกกันดีกว่า


    3 ตัวอย่างร่างด้วยพีเอ็มดับเบิลยู

    มาเปิดภาพร่าง "Fade" จากตัวอย่าง: ตัวอย่างไฟล์ 01.Basics Fade.


    มาเปลี่ยนกันเล็กน้อยแล้วโหลดลงในหน่วยความจำ Arduino

    Int ledPin = 3; // ประกาศพินที่ควบคุมความสว่าง int LED = 0; // ตัวแปรสำหรับตั้งค่าความสว่าง int fadeAmount = 5; // ขั้นตอนการเปลี่ยนความสว่าง การตั้งค่าเป็นโมฆะ () ( pinMode(ledPin, เอาท์พุต); } เป็นโมฆะวน() (อะนาล็อกเขียน (ledPin, ความสว่าง); // ตั้งค่าความสว่างบนความสว่างของพิน ledPin += fadeAmount; // เปลี่ยนค่าความสว่าง /* เมื่อถึงขีด จำกัด 0 หรือ 255 ให้เปลี่ยนทิศทางของความสว่างเปลี่ยน */ ถ้า (ความสว่าง == 0 || ความสว่าง == 255) ( fadeAmount = -fadeAmount; // เปลี่ยนเครื่องหมายของ ขั้นตอน ) ล่าช้า (30); // หน่วงเวลาเพื่อให้มองเห็นเอฟเฟกต์ได้มากขึ้น }

    4 การควบคุมความสว่าง LEDโดยใช้ PWM และ Arduino

    เปิดเครื่อง LED จะค่อยๆ เพิ่มความสว่าง จากนั้นจึงค่อยๆ ลดความสว่างลง เราจำลองสัญญาณแอนะล็อกที่เอาต์พุตดิจิทัลโดยใช้การปรับความกว้างพัลส์


    ดูวิดีโอที่แนบมาซึ่งแสดงให้เห็นการเปลี่ยนแปลงความสว่างของ LED อย่างชัดเจน บนออสซิลโลสโคปที่เชื่อมต่อคุณจะเห็นว่าสัญญาณจาก Arduino เปลี่ยนแปลงไปอย่างไร

    การมอดูเลตความกว้างพัลส์ (PWM) ของ Arduino UNO และ NANO ทำงานบนเอาต์พุตอะนาล็อก 3, 5, 6, 9, 10, 11 ด้วยความถี่ 488.28 Hz เมื่อใช้ฟังก์ชัน analogWrite ความถี่ PWM จะแตกต่างกันไปตั้งแต่ 0 ถึง 255 และสอดคล้องกับรอบการทำงานของพัลส์ตั้งแต่ 0 ถึง 100% สำหรับอุปกรณ์หลายๆ ตัว ความถี่ Arduino NANO PWM ต่ำเกินไป ดังนั้นจึงจำเป็นต้องเพิ่มความถี่ดังกล่าว ลองดูวิธีการทำอย่างถูกต้อง

    การปรับความกว้างพัลส์ Arduino

    PWM ในภาษาอังกฤษ Pulse-Width Modulation (PWM) คือการควบคุมกำลังบนโหลดโดยการเปลี่ยนรอบการทำงาน (ความกว้าง) ของพัลส์ที่ความถี่คงที่และแอมพลิจูดของสัญญาณ กราฟต่อไปนี้แสดงให้เห็นว่าด้วยค่าที่แตกต่างกันในฟังก์ชัน analogWrite แอมพลิจูดของพัลส์จะยังคงที่ แต่ความกว้างของพัลส์จะเปลี่ยนไป กำลังสัญญาณจะกำหนดรอบการทำงานของพัลส์

    กำหนดการ. พารามิเตอร์สัญญาณ, รอบการทำงานของ PWM

    การประยุกต์ใช้การปรับความกว้างพัลส์มีสองด้าน:

    1. PWM ใช้ในอุปกรณ์จ่ายไฟ อุปกรณ์ควบคุมกำลัง ฯลฯ การใช้ PWM บน Arduino Nano ช่วยลดความยุ่งยากในการควบคุมความสว่างของแหล่งกำเนิดแสง (LED, แถบ LED) และความเร็วในการหมุนของมอเตอร์ได้อย่างมาก

    2. PWM ใช้ในการรับสัญญาณอนาล็อก ตัวแปลงดิจิทัลเป็นอนาล็อก (DAC) บน Arduino ใช้งานง่าย เนื่องจากต้องใช้องค์ประกอบวิทยุขั้นต่ำ - ตัวต้านทานและตัวเก็บประจุแบบ RC chain เพียงเส้นเดียวก็เพียงพอแล้ว

    การเปลี่ยนความถี่ Arduino PWM (ขนาดบิต)

    บอร์ด Arduino Uno และ Arduino Nano ที่ใช้ ATmega168/328 มีมอดูเลเตอร์ PWM ฮาร์ดแวร์ 6 ตัวบนพอร์ตอะนาล็อก 3, 5, 6, 9, 10, 11 สัญญาณ PWM ถูกควบคุมโดยใช้ฟังก์ชัน analogWrite ซึ่งสร้างสัญญาณอะนาล็อกที่เอาต์พุตและ ตั้งค่าแรงกระตุ้นรอบการทำงาน Arduino ตั้งค่าความถี่พินเป็น 488.28 Hz และความละเอียดเป็น 8 บิต (ตั้งแต่ 0 ถึง 255)


    โครงการ การมอดูเลตความกว้างพัลส์สำหรับหุ่นจำลอง

    Arduino ที่ใช้ ATmega168/328 ใช้ตัวจับเวลาสามตัวสำหรับ PWM:

    ตัวจับเวลา 0— ข้อสรุปที่ 5 และ 6
    เครื่องจับเวลา 1— ข้อสรุปที่ 9 และ 10
    จับเวลา 2— ข้อสรุป 3 และ 11

    Arduino PWM ถูกกำหนดโดยส่วนประกอบแบบรวมที่เรียกว่าตัวจับเวลา ตัวจับเวลาแต่ละตัวในบอร์ด Arduino Uno และ Nano ที่ใช้ไมโครคอนโทรลเลอร์ ATmega168/328 มีช่องสัญญาณสองช่องที่เชื่อมต่อกับเอาต์พุต หากต้องการเปลี่ยนความถี่ของสัญญาณ PWM คุณต้องเปลี่ยนตัวจับเวลาที่เชื่อมต่ออยู่ ในกรณีนี้ PWM จะเปลี่ยนเอาต์พุตอะนาล็อกที่เชื่อมต่อแบบขนานกับตัวจับเวลาเดียวกันด้วย

    วิธีเพิ่มความถี่และความลึกบิตของ Arduino PWM

    ไม่มีวิธีใดที่จะเปลี่ยนความถี่ Arduino PWM โดยไม่ต้องจัดการหน่วยความจำโดยตรงในระดับต่ำ มาดูวิธีเปลี่ยนโหมดการทำงานของตัวจับเวลาเพื่อเพิ่มความถี่ Arduino PWM กันดีกว่า ตัวจับเวลา 0ใช้ในการคำนวณเวลา เช่น ฟังก์ชันดีเลย์และมิลลิวินาที การเพิ่มความถี่บนตัวจับเวลา 0 จะทำให้ฟังก์ชันประหยัดเวลาที่อาจใช้ในการร่างภาพหยุดทำงาน

    หากต้องการเพิ่มความจุบิต Arduino บนเอาต์พุตอะนาล็อก 9 และ 10 ให้เปลี่ยนความถี่ เครื่องจับเวลา 1ไม่มีห้องสมุด ความถี่ PWM สูงสุดสามารถเข้าถึง 62,500 Hz บนบอร์ด Arduino Uno และ Nano ในการดำเนินการนี้ ในขั้นตอนการตั้งค่าเป็นโมฆะ() คุณจะต้องเพิ่มคำสั่งที่เหมาะสมจากตารางด้านล่าง

    การอนุญาต ความถี่พีเอ็มดับเบิลยู คำสั่งการตั้งค่าโหมด
    8 บิต 62,500 เฮิรตซ์ TCCR1A = TCCR1A & 0xe0 | 1;
    TCCR1B = TCCR1B & 0xe0 | 0x09;
    7,812.5 เฮิรตซ์ TCCR1A = TCCR1A & 0xe0 | 1;
    TCCR1B = TCCR1B & 0xe0 | 0x0a;
    976.56 เฮิรตซ์ TCCR1A = TCCR1A & 0xe0 | 1;
    TCCR1B = TCCR1B & 0xe0 | 0x0b;
    244.14 เฮิรตซ์ TCCR1A = TCCR1A & 0xe0 | 1;
    TCCR1B = TCCR1B & 0xe0 | 0x0c;
    61.04 เฮิรตซ์ TCCR1A = TCCR1A & 0xe0 | 1;
    TCCR1B = TCCR1B & 0xe0 | 0x0d;

    ความถี่ Arduino PWM สูงสุดคือ 62,500 Hz