- Multitasking คืออะไร?
- ทำไมต้องข้ามการหน่วงเวลา () ใน Arduino
- ทำไมต้องใช้มิลลิวินาที ()?
- ส่วนประกอบที่จำเป็น
- แผนภูมิวงจรรวม
- การเขียนโปรแกรม Arduino UNO สำหรับการทำงานหลายอย่างพร้อมกัน
การทำงานหลายอย่างพร้อมกันได้นำคอมพิวเตอร์ไปสู่การปฏิวัติที่โปรแกรมหนึ่งหรือหลายโปรแกรมสามารถทำงานพร้อมกันซึ่งจะเพิ่มประสิทธิภาพความยืดหยุ่นความสามารถในการปรับตัวและเพิ่มผลผลิต ในระบบฝังตัวไมโครคอนโทรลเลอร์ยังสามารถจัดการมัลติทาสกิ้งและทำงานสองอย่างขึ้นไปพร้อมกันโดยไม่ต้องหยุดคำสั่งปัจจุบัน
ในบทช่วยสอนนี้เราจะได้เรียนรู้ว่า Arduino ทำงานมัลติทาสกิ้งด้วย ฟังก์ชัน Arduino millisอย่างไร โดยทั่วไปฟังก์ชัน delay () จะใช้ใน Arduino สำหรับงานเป็นระยะ ๆ เช่น LED กะพริบ แต่ฟังก์ชัน delay () นี้จะหยุดโปรแกรมในช่วงเวลาหนึ่งที่แน่นอนและไม่อนุญาตให้ดำเนินการอื่น ๆ ดังนั้นบทความนี้จะอธิบายถึงวิธีที่เราสามารถหลีกเลี่ยงการใช้ความล่าช้า () ฟังก์ชันและแทนที่ด้วยมิลลิวินาที ()ในการดำเนินการมากกว่าหนึ่งงานพร้อมกันและทำให้ Arduino ตัวควบคุมมัลติทาสกิ้ง ก่อนที่จะลงรายละเอียดเรามาเริ่มต้นด้วยการใช้งานมัลติทาสก์อย่างเข้าใจ
Multitasking คืออะไร?
การทำงานหลายอย่างพร้อมกันหมายถึงการดำเนินการมากกว่าหนึ่งงานหรือโปรแกรมพร้อมกันในเวลาเดียวกัน ระบบปฏิบัติการเกือบทั้งหมดมีการทำงานหลายอย่างพร้อมกัน ระบบปฏิบัติการประเภทนี้เรียกว่า MOS (ระบบปฏิบัติการมัลติทาสก์) MOS สามารถเป็นระบบปฏิบัติการพีซีแบบพกพาหรือเดสก์ท็อป ตัวอย่างที่ดีของการทำงานหลายอย่างในคอมพิวเตอร์คือเมื่อผู้ใช้เรียกใช้แอปพลิเคชันอีเมลอินเทอร์เน็ตเบราว์เซอร์เครื่องเล่นสื่อเกมในเวลาเดียวกันและหากผู้ใช้ไม่ต้องการใช้แอปพลิเคชันจะทำงานในพื้นหลังหากไม่ปิด ผู้ใช้ปลายทางใช้แอปพลิเคชันเหล่านี้ทั้งหมดในเวลาเดียวกัน แต่ระบบปฏิบัติการใช้แนวคิดนี้แตกต่างกันเล็กน้อย มาดูกันว่า OS จัดการการทำงานหลายอย่างพร้อมกันได้อย่างไร
ดังที่เห็นในภาพ CPU จะแบ่งเวลาในสามส่วนเท่า ๆ กันและกำหนดแต่ละส่วนให้กับแต่ละงาน / แอปพลิเคชัน นี่คือวิธีการทำงานหลายอย่างพร้อมกันในระบบส่วนใหญ่ แนวคิดเกือบจะเหมือนกันสำหรับArduino Multitaskingยกเว้นการกระจายเวลาจะแตกต่างกันเล็กน้อย เนื่องจาก Arduino ทำงานในความถี่ต่ำและ RAM เมื่อเปรียบเทียบกับแล็ปท็อป / มือถือ / พีซีดังนั้นเวลาที่ให้กับแต่ละงานก็จะแตกต่างกันไปด้วย Arduino ยังมีฟังก์ชัน delay () ซึ่งใช้กันอย่างแพร่หลาย แต่ก่อนที่จะเริ่มเรามาดูกันว่าเหตุใดเราจึงไม่ควรใช้ฟังก์ชัน delay () ในโปรเจ็กต์ใด ๆ
ทำไมต้องข้ามการหน่วงเวลา () ใน Arduino
หากเอกสารอ้างอิงของ Arduino ถือว่านั้นมีสองประเภทของการทำงานล่าช้าคนแรกคือความล่าช้า ()และสองคือdelayMicroseconds () ฟังก์ชันทั้งสองเหมือนกันในแง่ของการสร้างความล่าช้า ข้อแตกต่างเพียงอย่างเดียวคือในฟังก์ชัน delay () จำนวนเต็มพารามิเตอร์ที่ส่งผ่านจะมีหน่วยเป็นมิลลิวินาทีเช่นถ้าเราเขียนดีเลย์ (1000)ความล่าช้าจะเท่ากับ 1,000 มิลลิวินาทีนั่นคือ 1 วินาที ในทำนองเดียวกันในฟังก์ชัน delayMicroseconds () พารามิเตอร์ที่ส่งผ่านจะมีหน่วยเป็นไมโครวินาทีเช่นถ้าเราเขียนdelayMicroseconds (1000)ความล่าช้าจะเท่ากับ 1,000 microseconds คือ 1 milliseconds
มาถึงจุดนี้ฟังก์ชั่นทั้งสองหยุดโปรแกรมชั่วคราวตามระยะเวลาที่ผ่านไปในฟังก์ชันหน่วงเวลา ดังนั้นหากเราหน่วงเวลา 1 วินาทีโปรเซสเซอร์จะไม่สามารถไปยังคำสั่งถัดไปได้จนกว่าจะผ่านไป 1 วินาที ในทำนองเดียวกันถ้าการหน่วงเวลาคือ 10 วินาทีโปรแกรมจะหยุดเป็นเวลา 10 วินาทีและโปรเซสเซอร์จะไม่อนุญาตให้ทำตามคำแนะนำถัดไปจนกว่าจะผ่านไป 10 วินาที สิ่งนี้ขัดขวางประสิทธิภาพของไมโครคอนโทรลเลอร์ในแง่ของความเร็วและการดำเนินการตามคำสั่ง
ตัวอย่างที่ดีที่สุดในการอธิบายข้อเสียของฟังก์ชันหน่วงเวลาคือการใช้ปุ่มกดสองปุ่ม ลองพิจารณาว่าเราต้องการสลับไฟ LED สองดวงโดยใช้ปุ่มกดสองปุ่ม ดังนั้นหากกดปุ่มใดปุ่มหนึ่งไฟ LED ที่เกี่ยวข้องจะติดสว่างเป็นเวลา 2 วินาทีในทำนองเดียวกันหากกดปุ่มที่สอง LED จะติดสว่างเป็นเวลา 4 วินาที แต่เมื่อเราใช้ delay () หากผู้ใช้กดปุ่มแรกโปรแกรมจะหยุด 2 วินาทีและหากผู้ใช้กดปุ่มที่สองก่อนหน่วงเวลา 2 วินาทีไมโครคอนโทรลเลอร์จะไม่ยอมรับอินพุตตามที่โปรแกรมกำลัง อยู่ในขั้นหยุด
เอกสารอย่างเป็นทางการของ Arduino ระบุไว้อย่างชัดเจนในคำอธิบายฟังก์ชัน Notes and Warning of delay () คุณสามารถตรวจสอบสิ่งนี้เพื่อให้ชัดเจนยิ่งขึ้น
ทำไมต้องใช้มิลลิวินาที ()?
เพื่อเอาชนะปัญหาที่เกิดจากการใช้ความล่าช้านักพัฒนาควรใช้ฟังก์ชัน millis () ซึ่งใช้งานง่ายเมื่อคุณเป็นนิสัยและจะใช้ประสิทธิภาพของ CPU 100% โดยไม่สร้างความล่าช้าในการดำเนินการตามคำสั่งมิลลิวินาที()เป็นฟังก์ชันที่เพียงส่งคืนจำนวนมิลลิวินาทีที่ผ่านไปนับตั้งแต่บอร์ด Arduino เริ่มรันโปรแกรมปัจจุบันโดยไม่หยุดโปรแกรม เวลานี้จะล้น (เช่นกลับไปที่ศูนย์) หลังจากนั้นประมาณ 50 วัน
เช่นเดียวกับ Arduino มี delayMicroseconds () มันยังมีรุ่น micro ของ millis () เป็นmicros () ความแตกต่างระหว่างไมโครและมิลลิวินาทีคือไมโคร () จะล้นหลังจากผ่านไปประมาณ 70 นาทีเมื่อเทียบกับมิลลิวินาที () ซึ่งเป็นเวลา 50 วัน ขึ้นอยู่กับแอปพลิเคชันคุณสามารถใช้ millis () หรือ micros ()
ใช้มิลลิวินาที () แทนการหน่วงเวลา ():
ในการใช้มิลลิวินาที () สำหรับการจับเวลาและการหน่วงเวลาคุณต้องบันทึกและจัดเก็บเวลาที่การดำเนินการเกิดขึ้นเพื่อเริ่มเวลาจากนั้นตรวจสอบตามช่วงเวลาว่าเวลาที่กำหนดนั้นผ่านไปแล้วหรือไม่ ตามที่ระบุไว้ให้เก็บเวลาปัจจุบันไว้ในตัวแปร
กระแสไฟยาวที่ไม่ได้ลงชื่อ = millis ();
เราต้องการตัวแปรอีกสองตัวเพื่อดูว่าเวลาที่กำหนดผ่านไปหรือไม่ เราได้จัดเก็บเวลาปัจจุบันไว้ในตัวแปร currentMillis แต่เราต้องรู้ด้วยว่าช่วงเวลาเริ่มต้นเมื่อใดและระยะเวลาเป็นเท่าใด ดังนั้น Interval และ previousMillis จึงถูกประกาศ ช่วงเวลาจะบอกให้เราทราบถึงการหน่วงเวลาและ previosMillis จะจัดเก็บครั้งสุดท้ายที่เกิดเหตุการณ์
ไม่ได้ลงนามยาวก่อนหน้ามิลลิส; ระยะยาวที่ไม่ได้ลงนาม = 1,000;
เพื่อให้เข้าใจสิ่งนี้เรามาดูตัวอย่าง LED กะพริบแบบธรรมดา คาบ = 1,000 จะบอกเราว่า LED จะกะพริบเป็นเวลา 1 วินาทีหรือ 1,000 มิลลิวินาที
const int ledPin = 4; // หมายเลขพิน LED เชื่อมต่อ int ledState = LOW; // ใช้เพื่อตั้งค่าสถานะ LED ที่ ไม่ได้ลงนาม long previousMillis = 0; // จะจัดเก็บครั้งสุดท้ายที่ LED กะพริบ const long period = 1000; // ระยะเวลาที่จะกะพริบใน ms void setup () { pinMode (ledPin, OUTPUT); // ตั้ง ledpin เป็น output } void loop () { unsigned long currentMillis = millis (); // เก็บเวลาปัจจุบัน if (currentMillis - previousMillis> = period) {// ตรวจสอบว่า 1000ms ผ่าน previousMillis = currentMillis; // บันทึกครั้งสุดท้ายที่คุณกะพริบ LED ถ้า (ledState == LOW) {// ถ้า LED ปิดอยู่ให้เปิดและในทางกลับกัน ledState = HIGH; } else { ledState = LOW; } digitalWrite (ledPin, ledState); // ตั้งค่า LED พร้อม ledState ให้กระพริบอีกครั้ง } }
นี่คือคำสั่ง
อินเทอร์รัปต์ใน Arduinoทำงานเหมือนกับไมโครคอนโทรลเลอร์อื่น ๆ บอร์ด Arduino UNO มีพินสองพินแยกกันสำหรับติด อินเทอร์รัปต์บน GPIO พิน 2 และ 3 เราได้อธิบายรายละเอียดไว้ในArduino Interrupts Tutorial ซึ่งคุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับอินเทอร์รัปต์และวิธีการใช้งาน
ที่นี่เราจะแสดงArduino Multitasking โดยจัดการสองงานในเวลาเดียวกัน งานจะรวมถึงการกะพริบของ LED สองดวงในการหน่วงเวลาที่ต่างกันพร้อมกับปุ่มกดซึ่งจะใช้เพื่อควบคุมสถานะเปิด / ปิดของ LED ดังนั้นสามงานจะดำเนินการพร้อมกัน
ส่วนประกอบที่จำเป็น
- Arduino UNO
- ไฟ LED สามดวง (สีใดก็ได้)
- ความต้านทาน (470, 10k)
- จัมเปอร์
- เขียงหั่นขนม
แผนภูมิวงจรรวม
แผนภาพวงจรสำหรับสาธิตการใช้งาน Arduino Millis () fuction นั้นง่ายมากและไม่มีส่วนประกอบให้ติดมากนักดังที่แสดงด้านล่าง
การเขียนโปรแกรม Arduino UNO สำหรับการทำงานหลายอย่างพร้อมกัน
การเขียนโปรแกรม Arduino UNO สำหรับการทำงานหลายอย่างจะต้องใช้ตรรกะที่อยู่เบื้องหลังการทำงานของมิลลิวินาที () ซึ่งได้อธิบายไว้ข้างต้นเท่านั้น ขอแนะนำให้ฝึก LED กะพริบโดยใช้ มิลลิวินาที ซ้ำแล้วซ้ำอีกเพื่อให้ตรรกะชัดเจนและทำให้ตัวเองสบายใจกับมิลลิวินาที () ก่อนที่จะเริ่มโปรแกรม Arduino UNO สำหรับการทำงานหลายอย่างพร้อมกัน ในบทช่วยสอนนี้ยังใช้การขัดจังหวะร่วมกับมิลลิวินาที () พร้อมกันสำหรับการทำงานหลายอย่างพร้อมกัน ปุ่มจะขัดจังหวะดังนั้นเมื่อใดก็ตามที่เกิดการขัดจังหวะเช่นกดปุ่มกดไฟ LED จะเปลี่ยนเป็นสถานะเปิดหรือปิดการเขียนโปรแกรมเริ่มต้นด้วยการประกาศหมายเลขพินที่เชื่อมต่อ LED และปุ่มกด
int led1 = 6; int led2 = 7; int toggleLed = 5; int pushButton = 2;
ต่อไปเราจะเขียนตัวแปรเพื่อเก็บสถานะของ LED เพื่อใช้ในอนาคต
int ledState1 = ต่ำ; int ledState2 = ต่ำ;
เช่นเดียวกับที่อธิบายข้างต้นในตัวอย่างพริบที่ตัวแปรสำหรับระยะเวลาและ previousmillis ประกาศเพื่อเปรียบเทียบและสร้างความล่าช้าสำหรับไฟ LED ไฟ LED ดวงแรกจะกะพริบทุก ๆ 1 วินาทีและไฟ LED อีกดวงหนึ่งจะกะพริบหลังจากผ่านไป 200 มิลลิวินาที
ไม่ได้ลงนามยาวก่อนหน้านี้ Millis1 = 0; const long period1 = 1,000; ไม่ได้ลงนามยาวก่อนหน้านี้มิลลิส 2 = 0; const long period2 = 200;
ฟังก์ชั่นมิลลิวินาทีอื่นจะถูกใช้เพื่อสร้างการหน่วงเวลา debounceเพื่อหลีกเลี่ยงการกดปุ่มกดหลาย ๆ ครั้ง จะมีแนวทางที่คล้ายกันดังกล่าวข้างต้น
int debouncePeriod = 20; int debounceMillis = 0;
สามตัวแปรจะถูกนำมาใช้ในการจัดเก็บสถานะของปุ่มกดเป็นขัดจังหวะสลับ LED และรัฐกดปุ่ม
บูล buttonPushed = เท็จ; int ledChange = ต่ำ; int lastState = สูง;
กำหนดการทำงานของพินว่าพินใดจะทำงานเป็น INPUT หรือ OUTPUT
PinMode (led1, เอาท์พุท); PinMode (led2, เอาท์พุท); pinMode (toggleLed, เอาท์พุท); pinMode (pushButton, INPUT);
ตอนนี้กำหนดพินอินเทอร์รัปต์โดยแนบอินเทอร์รัปต์ด้วยนิยามของ ISR และโหมดขัดจังหวะ โปรดทราบว่าขอแนะนำให้ใช้ digitalPinToInterrupt (pin_number) เมื่อประกาศ ฟังก์ชัน attachInterrupt () เพื่อแปลพินดิจิทัลจริงเป็นหมายเลข อินเตอร์รั ปต์เฉพาะ
attachInterrupt (digitalPinToInterrupt (pushButton), pushButton_ISR, CHANGE);
รูทีนย่อย interrupt ถูกเขียนและจะเปลี่ยนเฉพาะแฟล็ก buttonPushed โปรดทราบว่ารูทีนย่อยอินเตอร์รัปต์ควรสั้นที่สุดเท่าที่จะเป็นไปได้ดังนั้นพยายามเขียนและลดคำแนะนำเพิ่มเติม
เป็นโมฆะ pushButton_ISR () { buttonPushed = true; }
Loop เริ่มต้นด้วยการจัดเก็บค่ามิลลิลิสในตัวแปร currentMillis ซึ่งจะเก็บค่าของเวลาที่ผ่านไปทุกครั้งที่วนซ้ำ
กระแสไฟยาวที่ไม่ได้ลงชื่อ = millis ();
มีทั้งหมดสามฟังก์ชั่นในการทำงานแบบ multitasking หนึ่งพริบ LED ที่ 1 วินาที, Blink สอง LED ที่ 200ms และถ้ากดปุ่มกดแล้วสลับปิด / เปิดไฟ LED ดังนั้นเราจะเขียนสามส่วนเพื่อทำงานนี้
ประการแรกคือการสลับสถานะ LED หลังจากทุกๆ 1 วินาทีโดยการเปรียบเทียบมิลลิวินาทีที่ผ่านไป
ถ้า (currentMillis - previousMillis1> = period1) { previousMillis1 = currentMillis; ถ้า (ledState1 == LOW) { ledState1 = HIGH; } else { ledState1 = ต่ำ; } digitalWrite (led1, ledState1); }
ในทำนองเดียวกันประการที่สองจะสลับ LED หลังจากทุกๆ 200ms โดยเปรียบเทียบมิลลิวินาทีที่ผ่านไป คำอธิบายได้อธิบายไว้แล้วก่อนหน้านี้ในบทความนี้
ถ้า (currentMillis - previousMillis2> = period2) { previousMillis2 = currentMillis; ถ้า (ledState2 == LOW) { ledState2 = HIGH; } else { ledState2 = ต่ำ; } digitalWrite (led2, ledState2); }
สุดท้ายที่ buttonPushed ธงจะถูกตรวจสอบและหลังการสร้างความล่าช้าของ debounce 20ms ก็แค่สลับสถานะของ LED เพื่อสอดคล้องกับปุ่มกดแนบมาเป็นขัดจังหวะ
if (buttonPushed = true) // ตรวจสอบว่า ISR ถูกเรียกหรือไม่ { if ((currentMillis - debounceMillis)> debouncePeriod && buttonPushed) // สร้างการหน่วงเวลา debounce 20ms เพื่อหลีกเลี่ยงการกดหลาย ๆ ครั้ง { debounceMillis = currentMillis; // บันทึกเวลาหน่วงเวลา debounce ล่าสุด ถ้า (digitalRead (pushButton) == LOW && lastState == HIGH) // เปลี่ยน led หลังจากกดปุ่มกด { ledChange =! ledChange; digitalWrite (toggleLed, ledChange); lastState = ต่ำ; } else if (digitalRead (pushButton) == HIGH && lastState == LOW) { lastState = HIGH; } buttonPushed = false; } }
นี้เสร็จสิ้นArduino มิลลิวินาที () การสอน โปรดทราบว่าเพื่อให้เป็นนิสัยกับ มิลลิส () เพียงแค่ฝึกฝนเพื่อนำตรรกะนี้ไปใช้ในแอปพลิเคชันอื่น ๆ คุณยังสามารถขยายเพื่อใช้มอเตอร์เซอร์โวมอเตอร์เซ็นเซอร์และอุปกรณ์ต่อพ่วงอื่น ๆ ในกรณีที่มีข้อสงสัยโปรดเขียนในฟอรัมหรือแสดงความคิดเห็นด้านล่าง
โค้ดที่สมบูรณ์และวิดีโอสำหรับสาธิตการใช้งานฟังก์ชันมิลลิวินาทีใน Arduino มีดังต่อไปนี้