โดยทั่วไปแล้ว Arduino ไม่รองรับการทำงานแบบขนานหรือมัลติเธรดอย่างแท้จริง แต่เป็นไปได้ด้วยการทำซ้ำของวงจรแต่ละครั้ง วนซ้ำ()สั่งให้ไมโครคอนโทรลเลอร์ตรวจสอบว่าถึงเวลาที่ต้องทำงานเบื้องหลังเพิ่มเติมหรือไม่ ในกรณีนี้ดูเหมือนว่าผู้ใช้จะมีการทำงานหลายอย่างพร้อมกัน
ตัวอย่างเช่น ลองแฟลช LED ที่ความถี่ที่กำหนด และในขณะเดียวกันก็สร้างเสียงเพิ่มและลดเสียงเหมือนเสียงไซเรนจากตัวปล่อยพีโซ เราได้เชื่อมต่อทั้ง LED และตัวส่งสัญญาณ Piezo กับ Arduino มากกว่าหนึ่งครั้งแล้ว มาประกอบวงจรดังรูป
หากคุณเชื่อมต่อ LED เข้ากับพินดิจิทัลอื่นที่ไม่ใช่ "13" อย่าลืมเกี่ยวกับตัวต้านทานจำกัดกระแสประมาณ 220 โอห์ม
2 การควบคุม LED และตัวปล่อย Piezoใช้ตัวดำเนินการล่าช้า ()
มาเขียนภาพร่างแบบนี้แล้วอัปโหลดไปยัง Arduino
ค่าคงที่ int soundPin = 3; /* ประกาศตัวแปรด้วยจำนวนพินที่เชื่อมต่อองค์ประกอบเพียโซอิเล็กทริก */ const int ledPin = 13; // ประกาศตัวแปรด้วยหมายเลขพิน LED การตั้งค่าเป็นโมฆะ () ( pinMode(soundPin, เอาท์พุต); // ประกาศพิน 3 เป็นเอาต์พุต } pinMode(ledPin, เอาท์พุต); // ประกาศพิน 13 เป็นเอาต์พุตเป็นโมฆะวน() ( }
// การควบคุมเสียง: โทนเสียง (soundPin, 700); // ส่งเสียงที่ความถี่ล่าช้า 700 Hz (200); โทนเสียง (soundPin, 500); // ที่ความถี่ความล่าช้า 500 Hz (200);โทนเสียง (soundPin, 300); // ที่ความถี่ความล่าช้า 300 Hz (200);
โทนเสียง (soundPin, 200); // ที่ความถี่ความล่าช้า 200 Hz (200); // การควบคุม LED: digitalWrite (ledPin, สูง); // ความล่าช้าของแสง (200);ชะลอการทำงานของโปรแกรมตามระยะเวลาที่กำหนด และจนกว่าจะหมดเวลานี้ คำสั่งต่อไปนี้ของโปรแกรมจะไม่ถูกดำเนินการ ด้วยเหตุนี้ เราจึงไม่สามารถกำหนดระยะเวลาการดำเนินการที่แตกต่างกันสำหรับแต่ละงานในลูปได้ วนซ้ำ()โปรแกรม ดังนั้นคุณต้องจำลองการทำงานหลายอย่างพร้อมกัน
3 กระบวนการคู่ขนานโดยไม่มีตัวดำเนินการ "delay()"
ตัวเลือกที่ Arduino จะดำเนินการแบบหลอกขนานนั้นเสนอโดยนักพัฒนา Arduino สาระสำคัญของวิธีนี้คือการทำซ้ำแต่ละรอบ วนซ้ำ()เราตรวจสอบว่าถึงเวลาที่ต้องกระพริบ LED (ทำงานเบื้องหลัง) หรือไม่ และถ้ามันมาถึงแล้ว เราจะกลับสถานะของ LED นี่เป็นตัวเลือกบายพาสสำหรับผู้ปฏิบัติงาน // การควบคุม LED: digitalWrite (ledPin, สูง); // ความล่าช้าของแสง (200);.
ค่าคงที่ int soundPin = 3; // ตัวแปรที่มีหมายเลขพินขององค์ประกอบเพียโซอิเล็กทริก const int ledPin = 13; // ตัวแปรที่มีหมายเลขพิน LED const long ledInterval = 200; // ช่วงเวลา LED กะพริบ, ms. int ledState = ต่ำ; // สถานะเริ่มต้นของ LED ที่ไม่ได้ลงนามแบบยาว PreviousMillis = 0; // เก็บเวลาของการเปิดใช้งาน LED ก่อนหน้า การตั้งค่าเป็นโมฆะ () ( pinMode(soundPin, เอาท์พุต); // ตั้งค่าพิน 3 เป็นเอาต์พุต } pinMode(ledPin, เอาท์พุต); // ประกาศพิน 13 เป็นเอาต์พุต pinMode(ledPin, เอาท์พุต); // ตั้งค่าพิน 13 เป็นเอาต์พุต }
// การควบคุมเสียง: โทนเสียง (soundPin, 700);
ความล่าช้า(200); // การควบคุม LED: digitalWrite (ledPin, สูง); // ความล่าช้าของแสง (200);โทนเสียง (soundPin, 500);
ในกรณีนี้จำเป็นต้องให้หน่วยควบคุมเสียงไซเรนตรวจสอบด้วยว่าถึงเวลาหรือไม่และไม่ใช้ // การควบคุม LED: digitalWrite (ledPin, สูง); // ความล่าช้าของแสง (200);- แต่สิ่งนี้จะเพิ่มจำนวนโค้ดและทำให้โปรแกรมอ่านได้น้อยลง
4 การใช้ไลบรารี ArduinoThreadเพื่อสร้างเธรดคู่ขนาน
เพื่อแก้ปัญหา เราจะใช้ห้องสมุดที่ยอดเยี่ยม ArduinoThreadซึ่งช่วยให้คุณสร้างกระบวนการหลอกขนานกันได้อย่างง่ายดาย มันทำงานในลักษณะเดียวกัน แต่ช่วยให้คุณไม่ต้องเขียนโค้ดเพื่อตรวจสอบเวลา - ไม่ว่าคุณจะต้องทำงานในลูปนี้หรือไม่ก็ตาม ซึ่งจะช่วยลดจำนวนโค้ดและปรับปรุงความสามารถในการอ่านของร่าง เรามาตรวจสอบการทำงานของห้องสมุดกันดีกว่า
ก่อนอื่น ให้ดาวน์โหลดไฟล์เก็บถาวรของไลบรารีจากเว็บไซต์อย่างเป็นทางการแล้วแตกไฟล์ลงในไดเร็กทอรี ห้องสมุด/สภาพแวดล้อมการพัฒนา Arduino IDE จากนั้นเปลี่ยนชื่อโฟลเดอร์ ArduinoThread-masterวี ArduinoThread.
แผนภาพการเชื่อมต่อจะยังคงเหมือนเดิม เฉพาะรหัสโปรแกรมเท่านั้นที่จะเปลี่ยนแปลง
#รวม
เสียงเป็นโมฆะ() ( โทนเสียงคงที่ = 100; // ระดับเสียง, โทน Hz (soundPin, ตัน); // เปิดไซเรนที่ "ตัน" Hz ถ้า (ตัน)ในโปรแกรมเราสร้างสองเธรด - นำด้ายและ วิ่ง()- สิ่งสำคัญคือไม่ใช้ตัวดำเนินการ // การควบคุม LED: digitalWrite (ledPin, สูง); // ความล่าช้าของแสง (200);- รหัสให้คำอธิบายโดยละเอียดเพิ่มเติม
มาโหลดโค้ดลงในหน่วยความจำ Arduino แล้วรัน ตอนนี้ทุกอย่างทำงานได้ตรงตามที่ควร!
และนี่คือตัวอย่างการใช้ฟังก์ชัน Arduino แนบขัดจังหวะ().
การขัดจังหวะเป็นสัญญาณที่แจ้งให้โปรเซสเซอร์ทราบว่ามีเหตุการณ์เกิดขึ้นซึ่งต้องได้รับการดูแลทันที โปรเซสเซอร์จะต้องตอบสนองต่อสัญญาณนี้โดยการขัดจังหวะการดำเนินการตามคำสั่งปัจจุบันและถ่ายโอนการควบคุมไปยังตัวจัดการการขัดจังหวะ (ISR, กิจวัตรการบริการขัดจังหวะ) ตัวจัดการเป็นฟังก์ชันปกติที่เราเขียนเองและใส่โค้ดที่ควรตอบสนองต่อเหตุการณ์ไว้ที่นั่น
หลังจากให้บริการ ISR อินเทอร์รัปต์แล้ว ฟังก์ชันจะทำงานให้เสร็จสิ้น และโปรเซสเซอร์จะกลับสู่กิจกรรมที่ถูกขัดจังหวะอย่างมีความสุข โดยจะรันโค้ดต่อจากที่ค้างไว้ ทั้งหมดนี้เกิดขึ้นโดยอัตโนมัติ ดังนั้นงานของเราคือเขียนตัวจัดการการขัดจังหวะเท่านั้นโดยไม่ทำให้สิ่งใดเสียหายหรือทำให้เราเสียสมาธิกับโปรเซสเซอร์บ่อยเกินไป คุณจะต้องมีความเข้าใจเกี่ยวกับวงจรหลักการทำงานของอุปกรณ์ที่เชื่อมต่อและแนวคิดว่าสามารถกระตุ้นการหยุดชะงักได้บ่อยเพียงใดและคุณลักษณะของการเกิดขึ้นคืออะไร ทั้งหมดนี้ถือเป็นปัญหาหลักในการทำงานกับการหยุดชะงัก
ฮาร์ดแวร์และซอฟต์แวร์ขัดจังหวะ
การขัดจังหวะใน Arduino สามารถแบ่งออกเป็นหลายประเภท:
- ฮาร์ดแวร์ขัดจังหวะ- การหยุดชะงักในระดับสถาปัตยกรรมไมโครโปรเซสเซอร์ เหตุการณ์นั้นสามารถเกิดขึ้นได้ในช่วงเวลาที่มีประสิทธิผลตั้งแต่ อุปกรณ์ภายนอก– เช่น การกดปุ่มบนคีย์บอร์ด, การเคลื่อนย้าย เมาส์คอมพิวเตอร์ฯลฯ
- ซอฟต์แวร์ขัดจังหวะ- มีการเปิดตัวภายในโปรแกรมโดยใช้คำแนะนำพิเศษ ใช้เพื่อเรียกตัวจัดการการขัดจังหวะ
- การขัดจังหวะภายใน (ซิงโครนัส)- การขัดจังหวะภายในเกิดขึ้นอันเป็นผลมาจากการเปลี่ยนแปลงหรือการละเมิดการทำงานของโปรแกรม (เช่น เมื่อเข้าถึงที่อยู่ที่ไม่ถูกต้อง รหัสการทำงานที่ไม่ถูกต้อง ฯลฯ)
เหตุใดการขัดจังหวะฮาร์ดแวร์จึงจำเป็น?
การขัดจังหวะด้วยฮาร์ดแวร์เกิดขึ้นเพื่อตอบสนองต่อเหตุการณ์ภายนอกและเกิดขึ้นจากอุปกรณ์ฮาร์ดแวร์ภายนอก Arduino มีการขัดจังหวะฮาร์ดแวร์ 4 ประเภท ทั้งหมดต่างกันในสัญญาณที่พินอินเตอร์รัปต์:
- หน้าสัมผัสถูกดึงลงสู่พื้น ตัวจัดการอินเทอร์รัปต์จะถูกดำเนินการตราบเท่าที่มีสัญญาณ LOW บนพินอินเทอร์รัปต์
- การเปลี่ยนสัญญาณบนหน้าสัมผัส ในกรณีนี้ Arduino ดำเนินการตัวจัดการการขัดจังหวะเมื่อมีการเปลี่ยนแปลงสัญญาณเกิดขึ้นบนพินขัดจังหวะ
- การเปลี่ยนสัญญาณจาก LOW เป็น HIGH บนพิน - เมื่อเปลี่ยนจากสัญญาณต่ำไปเป็นสูง ตัวจัดการการขัดจังหวะจะถูกดำเนินการ
- การเปลี่ยนสัญญาณจากสูงเป็นต่ำบนพิน - เมื่อเปลี่ยนจากสัญญาณสูงเป็นสัญญาณต่ำ ตัวจัดการการขัดจังหวะจะถูกดำเนินการ
การขัดจังหวะมีประโยชน์ในโปรแกรม Arduino เนื่องจากช่วยแก้ปัญหาเรื่องเวลา ตัวอย่างเช่น เมื่อทำงานกับ UART การขัดจังหวะจะทำให้คุณไม่ต้องติดตามการมาถึงของอักขระแต่ละตัว อุปกรณ์ฮาร์ดแวร์ภายนอกจะส่งสัญญาณขัดจังหวะ โปรเซสเซอร์จะเรียกตัวจัดการขัดจังหวะทันที ซึ่งจะจับอักขระได้ทันเวลา ซึ่งจะช่วยประหยัดเวลาของ CPU ที่จะใช้ในการตรวจสอบสถานะ UART โดยไม่มีการขัดจังหวะ การดำเนินการที่จำเป็นทั้งหมดจะดำเนินการโดยตัวจัดการการขัดจังหวะโดยไม่ส่งผลกระทบต่อโปรแกรมหลัก ไม่จำเป็นต้องมีความสามารถพิเศษจากอุปกรณ์ฮาร์ดแวร์
สาเหตุหลักที่ต้องเรียกการขัดจังหวะคือ:
- การตรวจจับการเปลี่ยนแปลงในสถานะเอาต์พุต
- จับเวลาขัดจังหวะ;
- ข้อมูลขัดจังหวะผ่าน SPI, I2C, USART;
- การแปลงแอนะล็อกเป็นดิจิทัล
- ความเต็มใจที่จะใช้ EEPROM หน่วยความจำแฟลช
วิธีการใช้อินเทอร์รัปต์ใน Arduino
เมื่อได้รับสัญญาณขัดจังหวะ การทำงานจะถูกระงับ การดำเนินการของฟังก์ชันที่ประกาศว่าจะดำเนินการเมื่อถูกขัดจังหวะเริ่มต้นขึ้น ฟังก์ชันที่ประกาศไม่สามารถยอมรับค่าอินพุตและส่งกลับค่าเมื่อออกได้ การขัดจังหวะไม่ส่งผลกระทบต่อโค้ดในลูปโปรแกรมหลัก ในการทำงานกับการขัดจังหวะใน Arduino จะใช้ฟังก์ชันมาตรฐาน แนบขัดจังหวะ().
ความแตกต่างในการใช้งานอินเทอร์รัปต์ในบอร์ด Arduino ต่างๆ
ขึ้นอยู่กับการใช้งานฮาร์ดแวร์ รุ่นเฉพาะไมโครคอนโทรลเลอร์มีการขัดจังหวะหลายครั้ง บอร์ด Arduino Uno มีการขัดจังหวะ 2 ครั้งบนพินที่สองและสาม แต่หากจำเป็นต้องใช้เอาต์พุตมากกว่าสองเอาต์พุต บอร์ดจะรองรับโหมด "เปลี่ยนพิน" พิเศษ โหมดนี้ทำงานโดยการเปลี่ยนอินพุตสำหรับพินทั้งหมด ความแตกต่างระหว่างโหมดอินเทอร์รัปต์การเปลี่ยนแปลงอินพุตก็คือ อินเทอร์รัปต์สามารถสร้างขึ้นบนพินใดก็ได้จากแปดพิน ในกรณีนี้การประมวลผลจะยากขึ้นและนานขึ้นเนื่องจากคุณจะต้องติดตามสถานะล่าสุดในผู้ติดต่อแต่ละราย
บนบอร์ดอื่นๆ จำนวนการขัดจังหวะจะสูงกว่า ตัวอย่างเช่น บอร์ดมี 6 พินที่สามารถรองรับการขัดจังหวะภายนอกได้ สำหรับบอร์ด Arduino ทั้งหมด เมื่อทำงานกับฟังก์ชันแนบอินเทอร์รัปต์ (อินเทอร์รัปต์ ฟังก์ชัน โหมด) อาร์กิวเมนต์ Inerrupt 0 จะเชื่อมโยงกับพินดิจิทัล 2
ขัดจังหวะในภาษา Arduino
ตอนนี้เรามาปฏิบัติจริงและพูดคุยเกี่ยวกับวิธีใช้การขัดจังหวะในโครงการของคุณ
ไวยากรณ์แนบInterrupt()
ฟังก์ชันแนบอินเทอร์รัปต์ใช้เพื่อทำงานกับอินเทอร์รัปต์ มันทำหน้าที่เชื่อมต่อการขัดจังหวะภายนอกกับตัวจัดการ
ไวยากรณ์การโทร:แนบInterrupt(ขัดจังหวะ ฟังก์ชัน โหมด)
อาร์กิวเมนต์ของฟังก์ชัน:
- ขัดจังหวะ - จำนวนการขัดจังหวะที่จะเรียก (มาตรฐาน 0 - สำหรับพินที่ 2 สำหรับบอร์ด Arduino Uno 1 - สำหรับพินที่ 3)
- function – ชื่อของฟังก์ชันที่จะเรียกใช้เมื่อถูกขัดจังหวะ (สำคัญ - ฟังก์ชันไม่ควรยอมรับหรือส่งคืนค่าใดๆ)
- โหมด - เงื่อนไขสำหรับการทริกเกอร์การขัดจังหวะ
สามารถตั้งค่าเงื่อนไขทริกเกอร์ต่อไปนี้ได้:
- ต่ำ - ดำเนินการเมื่อระดับสัญญาณต่ำเมื่อหน้าสัมผัสมีค่าเป็นศูนย์ การหยุดทำงานสามารถทำซ้ำเป็นรอบได้ เช่น เมื่อกดปุ่ม เป็นต้น
- CHANGE – ที่ขอบ การหยุดชะงักเกิดขึ้นเมื่อสัญญาณเปลี่ยนจากสูงไปต่ำหรือในทางกลับกัน ดำเนินการหนึ่งครั้งสำหรับการเปลี่ยนแปลงสัญญาณใดๆ
- RISING – ดำเนินการขัดจังหวะหนึ่งครั้งเมื่อสัญญาณเปลี่ยนจาก LOW เป็น HIGH
- FALLING – ดำเนินการขัดจังหวะหนึ่งครั้งเมื่อสัญญาณเปลี่ยนจาก HIGH เป็น LOW.4
หมายเหตุสำคัญ
เมื่อทำงานกับการขัดจังหวะ จะต้องคำนึงถึงข้อจำกัดที่สำคัญต่อไปนี้:
- ฟังก์ชันตัวจัดการไม่ควรทำงานนานเกินไป ประเด็นก็คือ Arduino ไม่สามารถจัดการกับการขัดจังหวะหลายครั้งในเวลาเดียวกันได้ ขณะที่ฟังก์ชันตัวจัดการของคุณกำลังทำงานอยู่ การขัดจังหวะอื่นๆ ทั้งหมดจะถูกละเว้น และคุณอาจพลาดเหตุการณ์สำคัญได้ หากคุณต้องการทำสิ่งที่ยิ่งใหญ่ เพียงโอนการประมวลผลเหตุการณ์ไปยังลูป main loop() ในตัวจัดการคุณสามารถตั้งค่าแฟล็กเหตุการณ์ได้เท่านั้น และในลูปคุณสามารถตรวจสอบแฟล็กและประมวลผลได้
- คุณต้องระมัดระวังตัวแปรให้มาก คอมไพเลอร์ C++ อันชาญฉลาดสามารถ "เพิ่มประสิทธิภาพ" โปรแกรมของคุณใหม่ได้ โดยลบตัวแปรที่คิดว่าไม่จำเป็นออก คอมไพเลอร์จะไม่เห็นว่าคุณตั้งค่าตัวแปรบางตัวในส่วนหนึ่งแล้วนำไปใช้ในอีกส่วนหนึ่ง คุณสามารถใช้เพื่อขจัดความเป็นไปได้นี้ในกรณีของประเภทข้อมูลพื้นฐาน คำหลักระเหยได้ เช่น สถานะบูลีนระเหย = 0 แต่วิธีนี้ใช้ไม่ได้กับโครงสร้างข้อมูลที่ซับซ้อน ดังนั้นคุณต้องตื่นตัวอยู่เสมอ
- ไม่แนะนำให้ใช้การขัดจังหวะจำนวนมาก (พยายามอย่าใช้เกิน 6-8) ปริมาณมากการประมวลผลเหตุการณ์ต่างๆ ต้องใช้โค้ดที่ซับซ้อนอย่างมาก ดังนั้นจึงนำไปสู่ข้อผิดพลาด นอกจากนี้เราต้องเข้าใจว่าไม่มีความแม่นยำของเวลาในการดำเนินการในระบบด้วย จำนวนมากไม่มีการขัดจังหวะคำพูด - คุณจะไม่มีวันเข้าใจแน่ชัดว่าช่วงเวลาระหว่างการเรียกคำสั่งที่สำคัญสำหรับคุณคืออะไร
- ห้ามมิให้ใช้ความล่าช้า () ในตัวจัดการโดยเด็ดขาด กลไกในการกำหนดช่วงเวลาล่าช้านั้นใช้ตัวจับเวลา และยังดำเนินการกับการขัดจังหวะที่ตัวจัดการของคุณจะบล็อกอีกด้วย เป็นผลให้ทุกคนจะรอทุกคนและโปรแกรมจะหยุดทำงาน ด้วยเหตุผลเดียวกัน โปรโตคอลการสื่อสารแบบขัดจังหวะ (เช่น i2c) ไม่สามารถใช้งานได้
ตัวอย่างการใช้ไฟล์แนบอินเทอร์รัปต์
มาเริ่มกันเลยดีกว่า ตัวอย่างที่ง่ายที่สุดการใช้การขัดจังหวะ ในตัวอย่าง เรากำหนดฟังก์ชันตัวจัดการที่เมื่อสัญญาณบนพิน 2 ของ Arduino Uno เปลี่ยนไป จะเปลี่ยนสถานะของพิน 13 ซึ่งโดยปกติแล้วเราจะเชื่อมต่อกับ LED
#define PIN_LED 13 สถานะการกระทำบูลีนที่ผันผวน = ต่ำ; การตั้งค่าเป็นโมฆะ () ( pinMode (PIN_LED, OUTPUT); // ตั้งค่าการขัดจังหวะ // ฟังก์ชัน myEventListener จะถูกเรียกเมื่อ // บนพิน 2 (การขัดจังหวะ 0 เชื่อมต่อกับพิน 2) // สัญญาณเปลี่ยนไป (ไม่ว่าจะอยู่ที่ใด ทิศทาง)แนบInterrupt (0, myEventListener, CHANGE); void loop() ( // เราไม่ได้ทำอะไรเลยในฟังก์ชันลูป เนื่องจากโค้ดการจัดการเหตุการณ์ทั้งหมดจะอยู่ในฟังก์ชัน myEventListener) void myEventListener() ( actionState != actionState ; // / / ดำเนินการอื่น ๆ เช่น เปิดหรือปิด LED digitalWrite(PIN_LED, actionState )
ลองดูตัวอย่างบางส่วนของการขัดจังหวะที่ซับซ้อนยิ่งขึ้นและตัวจัดการ: สำหรับตัวจับเวลาและปุ่ม
ขัดจังหวะด้วยการกดปุ่มพร้อมระบบป้องกันการเด้ง
เมื่อถูกขัดจังหวะ เหตุการณ์จะเกิดขึ้น - ก่อนที่ผู้ติดต่อจะสัมผัสกันอย่างใกล้ชิดเมื่อกดปุ่ม ผู้ติดต่อจะสั่นทำให้เกิดการทำงานหลายอย่าง มีสองวิธีในการจัดการกับการตีกลับ: ฮาร์ดแวร์ นั่นคือ การบัดกรีตัวเก็บประจุไปที่ปุ่ม และซอฟต์แวร์
คุณสามารถกำจัดการพูดคุยได้โดยใช้ฟังก์ชัน - ช่วยให้คุณสามารถวัดเวลาที่ผ่านไปนับตั้งแต่การใช้งานปุ่มครั้งแรก
If(digitalRead(2)==HIGH) ( //เมื่อกดปุ่ม //หากผ่านไปมากกว่า 100 มิลลิวินาทีนับตั้งแต่กดครั้งก่อน if (มิลลิวินาที() - PreviousMillis >= 100) ( //เวลาของครั้งแรก การดำเนินการถูกจดจำ PreviousMillis = millis(); if (led==oldled) ( //ตรวจสอบว่าสถานะของปุ่มไม่เปลี่ยนแปลง led=!led; )
รหัสนี้ช่วยให้คุณสามารถลบ debounce และไม่บล็อกการทำงานของโปรแกรม เช่นเดียวกับกรณีที่มีฟังก์ชันหน่วงเวลา ซึ่งไม่ได้รับอนุญาตในการขัดจังหวะ
ตัวจับเวลาขัดจังหวะ
ตัวจับเวลาคือตัวนับที่นับตามความถี่ที่กำหนดซึ่งได้จากโปรเซสเซอร์ 16 MHz สามารถกำหนดค่าตัวแบ่งความถี่เพื่อรับได้ โหมดที่ต้องการบัญชี คุณยังสามารถกำหนดค่าตัวนับเพื่อสร้างการขัดจังหวะเมื่อถึงค่าที่ตั้งไว้
และการขัดจังหวะตัวจับเวลาทำให้คุณสามารถขัดจังหวะได้ทุกๆ มิลลิวินาที Arduino มีตัวจับเวลา 3 ตัว - Timer0, Timer1 และ Timer2 Timer0 ใช้เพื่อสร้างอินเทอร์รัปต์ทุกๆ มิลลิวินาที ซึ่งจะอัพเดตตัวนับและส่งผ่านไปยังฟังก์ชัน millis() ตัวจับเวลานี้เป็นแบบแปดบิตและนับจาก 0 ถึง 255 การขัดจังหวะจะถูกสร้างขึ้นเมื่อค่าถึง 255 ตามค่าเริ่มต้น ตัวแบ่งสัญญาณนาฬิกาที่ 65 จะถูกใช้เพื่อให้ได้ความถี่ใกล้เคียงกับ 1 kHz
การลงทะเบียนการเปรียบเทียบใช้เพื่อเปรียบเทียบสถานะของตัวจับเวลาและข้อมูลที่เก็บไว้ ใน ในตัวอย่างนี้รหัสจะสร้างการขัดจังหวะเมื่อตัวนับถึง 0xAF
TIMSK0 |= _BV(OCIE0A);
คุณต้องกำหนดตัวจัดการการขัดจังหวะสำหรับเวกเตอร์ขัดจังหวะตัวจับเวลา เวกเตอร์อินเทอร์รัปต์เป็นตัวชี้ไปยังที่อยู่ตำแหน่งของคำสั่งที่จะถูกดำเนินการเมื่อมีการเรียกอินเทอร์รัปต์ เวกเตอร์อินเทอร์รัปต์หลายตัวจะรวมกันเป็นตารางเวกเตอร์อินเทอร์รัปต์ ตัวจับเวลาในกรณีนี้จะถูกเรียกว่า TIMER0_COMPA_vect ตัวจัดการนี้จะดำเนินการเช่นเดียวกับในลูป ()
SIGNAL(TIMER0_COMPA_vect) ( currentMillis แบบยาวที่ไม่ได้ลงนาม = millis(); Sweeper1.Update(currentMillis); if(digitalRead(2) == HIGH) ( Sweeper2.Update(currentMillis); led1.Update(currentMillis); ) led2.Update( currentMillis); led3.Update(currentMillis); //ฟังก์ชัน loop() จะยังคงว่างเปล่า เป็นโมฆะวน() ( )
สรุป.
การหยุดชะงักใน Arduino เป็นหัวข้อที่ค่อนข้างซับซ้อน เนื่องจากคุณต้องคิดถึงสถาปัตยกรรมทั้งหมดของโครงการในคราวเดียว ลองจินตนาการว่าโค้ดถูกดำเนินการอย่างไร เหตุการณ์ใดบ้างที่เป็นไปได้ จะเกิดอะไรขึ้นเมื่อโค้ดหลักถูกขัดจังหวะ เราไม่ได้กำหนดไว้ว่าจะเปิดเผยคุณสมบัติทั้งหมดของการทำงานกับโครงสร้างภาษานี้ เป้าหมายหลักคือการแนะนำกรณีการใช้งานหลัก ในบทความต่อๆ ไป เราจะพูดคุยเกี่ยวกับการหยุดชะงักโดยละเอียดต่อไป
สวัสดีอันเดรย์ แนวทางในการถ่ายทอดความรู้และประสบการณ์ที่คุณสั่งสมมานั้นน่าสนใจมาก ช่วยได้มากในความพยายามของคุณ ฉันเริ่มเชี่ยวชาญ Arduino และมีความปรารถนาที่จะก้าวหน้า ยิ่งไปกว่านั้น ด้วยความช่วยเหลือจากภายนอก ฉันจึงสามารถทำมันได้เร็วขึ้น ในตอนแรก งานของฉันคือสร้างหุ่นยนต์ที่วิ่งไปตามเส้น ฉันทำไปแล้ว - ทุกอย่างเรียบร้อยดี แต่นอกเหนือจากนั้น เมื่อมีตัวเลือกเพิ่มเติม ฉันก็ไม่เข้าใจว่าทำไมมันถึงหยุดตอบสนองต่อสายอย่างถูกต้อง ฉันมาเจอบทความนี้และเข้าใจเหตุผล
ตอนนี้ฉันมีคำถามสำหรับคุณ: ในแบบร่างที่กล่าวถึงด้านล่างและเสร็จสิ้นโดยคำนึงถึงปัญหาความล่าช้าฉันต้องเปลี่ยนไปใช้มิลลิวินาทีทุกที่ที่มีฟังก์ชันนี้หรือไม่? ถ้าเป็นเช่นนั้น ฉันเข้าใจว่าจะต้องทำแบบร่างใหม่เกือบทั้งหมดใช่ไหม และยังไม่ชัดเจนว่าจะใช้มิลลิวินาทีในการวัดระยะทางอย่างไร ขอบคุณ
//หุ่นยนต์ที่มีฟังก์ชันติดตามเส้นสีขาว
// ************************ การติดตั้งสายมอเตอร์ *********************** *
int มอเตอร์ซ้ายความเร็ว = 5; // ความเร็วมอเตอร์ซ้าย (A) - ENA
int มอเตอร์ซ้ายไปข้างหน้า = 4; // มอเตอร์ซ้าย (A) ไปข้างหน้า - IN1
int MotorLeftBack = 3; // มอเตอร์ซ้าย (A) กลับ - IN2
int MotorRightForward = 8; // ขวา (B) มอเตอร์ ไปข้างหน้า - IN3
int MotorRightBack = 7; // ขวา (B) มอเตอร์ BACK - IN4
อินท์ MotorRightSpeed \u003d 9; // ขวา (B) ความเร็วมอเตอร์ - ENB
// ************************การติดตั้งเอาต์พุตเซ็นเซอร์อัลตราโซนิก********************* * *
int ตรีโกณมิติ = 14; // การตั้งค่าหมายเลขพินของเซ็นเซอร์อัลตราโซนิกตรีโกณมิติด้านซ้าย
int echoPinL = 15; // การตั้งค่าหมายเลขเอาต์พุตของเซ็นเซอร์อัลตราโซนิกเสียงสะท้อนด้านซ้าย
int ตรีโกณมิติ = 10; // การตั้งค่าหมายเลขเอาต์พุตของเซ็นเซอร์อัลตราโซนิกตรีโกณมิติกลาง
int echoPinC = 11; // การตั้งค่าหมายเลขเอาต์พุตของเซ็นเซอร์อัลตราโซนิกเสียงก้องกลาง
int ตรีโกณมิติ R = 12; // การตั้งค่าหมายเลขพินของเซ็นเซอร์อัลตราโซนิกตรีโกณมิติที่ถูกต้อง
int echoPinR = 13; // การตั้งค่าหมายเลขเอาต์พุตของเซ็นเซอร์อัลตราโซนิคสะท้อนที่ถูกต้อง
// ********************* การติดตั้งหมุดเซ็นเซอร์เส้น *******************
const int LineSensorLeft = 19; // อินพุตเซ็นเซอร์บรรทัดซ้าย
const int LineSensorRight = 18; // อินพุตของเซ็นเซอร์เส้นด้านขวา
อินท์ SL; // สถานะเซ็นเซอร์ด้านซ้าย
อินท์ เอสอาร์; // สถานะเซ็นเซอร์ที่ถูกต้อง
// ********************* การตั้งค่าเอาต์พุตแจ้งเตือนแสงและเสียง **************
อินท์ไลท์ = 2; // ตั้งค่าจำนวนเอาต์พุตแจ้งเตือนแสง
อินท์ ซุมม์ = 6; // ตั้งค่าหมายเลขเอาท์พุตของออด
int ledState = ต่ำ; // ตั้งค่าสถานะของ LED ด้วยตัวแปรนี้
ก่อนหน้ายาวMillis = 0; // เก็บเวลาของการสลับ LED ครั้งล่าสุด
ช่วงเวลายาว = 300; // ช่วงเวลาระหว่างการเปิด/ปิด LED (0.3 วินาที)
// *********************การวัดตัวแปรเซ็นเซอร์วัดระยะ************
int impulseTimeL = 0;
int impulseTimeC = 0 ที่ไม่ได้ลงนาม;
int impulseTimeR = 0 ที่ไม่ได้ลงนาม;
ระยะทางยาว = 0; // วัดระยะทางด้วยเซ็นเซอร์อัลตราโซนิกด้านซ้าย
ระยะทางยาว C=0; // ระยะทางที่วัดโดยเซ็นเซอร์อัลตราโซนิกกลาง
ระยะทางยาว = 0; // วัดระยะทางด้วยเซ็นเซอร์อัลตราซาวนด์ที่ถูกต้อง
// ************************************ ตั้งค่า ************ * *******************
อนุกรมเริ่มต้น(9600); // เริ่มพอร์ตอนุกรม (ความเร็ว 9600)
//*************** ตั้งค่าหน้าสัมผัสมอเตอร์******************
pinMode (MotorRightBack, เอาต์พุต); // ขวา (B) มอเตอร์กลับ
pinMode (MotorRightForward, เอาต์พุต); // ขวา (B) มอเตอร์ไปข้างหน้า
pinMode (MotorLeftBack, เอาต์พุต); // ซ้าย (A) มอเตอร์กลับ
pinMode (มอเตอร์ซ้ายไปข้างหน้า, เอาต์พุต); // ซ้าย (A) มอเตอร์ไปข้างหน้า
ความล่าช้า(ระยะเวลา);
//*************** ตั้งค่าหน้าสัมผัสเซ็นเซอร์แถบ**************
pinMode(LineSensorLeft, อินพุต); // กำหนดพินของเซ็นเซอร์เส้นด้านซ้าย
pinMode(LineSensorRight, อินพุต); // กำหนดพินของเซ็นเซอร์เส้นด้านขวา
// ***************การตั้งค่าโหมดเอาต์พุตของเซ็นเซอร์อัลตราโซนิก************************
pinMode(trigPinL, เอาท์พุต); // การตั้งค่าโหมดการทำงานของเอาต์พุตตรีโกณมิติด้านซ้ายของเซ็นเซอร์อัลตราโซนิก
pinMode(echoPinL, อินพุต); // การตั้งค่าโหมดการทำงานของเอาต์พุตเซ็นเซอร์อัลตราโซนิกสะท้อนด้านซ้าย
pinMode(trigPinC, เอาท์พุต); // การตั้งค่าโหมดการทำงานของเอาต์พุตเซ็นเซอร์อัลตราโซนิกตรีโกณมิติส่วนกลาง
pinMode(echoPinC, อินพุต); // การตั้งค่าโหมดการทำงานของเอาต์พุตเซ็นเซอร์อัลตราโซนิกเสียงสะท้อนกลาง
pinMode(trigPinR, เอาท์พุต); // การตั้งค่าโหมดการทำงานของเอาต์พุตเซ็นเซอร์อัลตราโซนิกตรีโกณมิติที่ถูกต้อง
pinMode(echoPinR, อินพุต); // การตั้งค่าโหมดการทำงานของเอาต์พุตเซ็นเซอร์อัลตราโซนิคสะท้อนที่ถูกต้อง
// *************** ตั้งค่าผู้ติดต่อสำหรับการเตือนด้วยแสงและเสียง ************************** * *****
pinMode(ซูม,เอาท์พุต); // การตั้งค่าโหมดการทำงานของเอาต์พุตออด
pinMode (แสง, เอาต์พุต); // การตั้งค่าโหมดการทำงานของเอาต์พุตการส่งสัญญาณแสง
// ****************** คำสั่งพื้นฐานการเคลื่อนไหว ******************
โมฆะไปข้างหน้า (int a, int sa) // ส่งต่อ
อะนาล็อกเขียน (MotorRightSpeed, sa);
อะนาล็อกเขียน (MotorLeftSpeed, sa);
เป็นโมฆะขวา (int b, int sb) // หมุนขวา (ด้านใดด้านหนึ่ง)
digitalWrite (มอเตอร์ขวากลับ, ต่ำ);
digitalWrite (มอเตอร์ซ้ายกลับ, ต่ำ);
digitalWrite (มอเตอร์ซ้ายไปข้างหน้าสูง);
อะนาล็อกเขียน (MotorLeftSpeed, sb);
โมฆะซ้าย (int k, int sk) // เลี้ยวซ้าย (ด้านใดด้านหนึ่ง)
digitalWrite (มอเตอร์ขวากลับ, ต่ำ);
digitalWrite (มอเตอร์ขวาไปข้างหน้าสูง);
อะนาล็อกเขียน (MotorRightSpeed, sk);
digitalWrite (มอเตอร์ซ้ายกลับ, ต่ำ);
เป็นโมฆะ stopp (int f) // หยุด
digitalWrite (มอเตอร์ขวากลับ, ต่ำ);
digitalWrite (มอเตอร์ขวาไปข้างหน้า, ต่ำ);
digitalWrite (มอเตอร์ซ้ายกลับ, ต่ำ);
digitalWrite (มอเตอร์ซ้ายไปข้างหน้า, ต่ำ);
// ********************************* การวัดระยะทาง*************** ****** *
เป็นโมฆะ izmdistL () // การวัดระยะทางด้วยเซ็นเซอร์อัลตราโซนิกด้านซ้าย
digitalWrite (ตรีโกณมิติ, สูง);
digitalWrite(ตรีโกณมิติ, ต่ำ); // พัลส์ 10 mS ไปยังเอาท์พุตตรีโกณมิติของเซ็นเซอร์อัลตราโซนิกสำหรับการวัดระยะทาง
ImpulseTimeL = พัลส์อิน (echoPinL, สูง); // อ่านระยะห่างจากเซ็นเซอร์อัลตราโซนิก
distL=แรงกระตุ้นTimeL/58; // แปลงเป็นเซนติเมตร
เป็นโมฆะ izmdistC () // การวัดระยะทางด้วยเซ็นเซอร์อัลตราโซนิกกลาง
digitalWrite (trigPinC, สูง);
digitalWrite (ตรีโกณมิติ, ต่ำ); // พัลส์ 10 mS ไปยังเอาท์พุตตรีโกณมิติของเซ็นเซอร์อัลตราโซนิกสำหรับการวัดระยะทาง
impulseTimeC = พัลส์อิน (echoPinC, สูง); // อ่านระยะห่างจากเซ็นเซอร์อัลตราโซนิก
distC=แรงกระตุ้นTimeC/58; // แปลงเป็นเซนติเมตร
เป็นโมฆะ izmdistR () // การวัดระยะทางด้วยเซ็นเซอร์อัลตราโซนิกกลาง
digitalWrite(trigPinR, สูง);
digitalWrite(trigPinR, ต่ำ); // พัลส์ 10 mS ไปยังเอาท์พุตตรีโกณมิติของเซ็นเซอร์อัลตราโซนิกสำหรับการวัดระยะทาง
impulseTimeR = พัลส์อิน (echoPinR, สูง); // อ่านระยะห่างจากเซ็นเซอร์อัลตราโซนิก
distR=แรงกระตุ้นTimeR/58; // แปลงเป็นเซนติเมตร
// *********************************** วนซ้ำ ************ *********************
// ************************ โหมดติดตาม LINE *********************** ********* ***
// *********************สัญญาณไฟและเสียงแจ้งเตือน***************
โทน(Zumm,900); // เปิดเสียงที่ 900 Hz
โทน(Zumm,900); // เปิดเสียงที่ 800 Hz
currentMillis แบบยาวที่ไม่ได้ลงนาม = millis();
if (currentMillis - PreviousMillis > ช่วงเวลา) //ตรวจสอบว่าช่วงเวลาที่ต้องการผ่านไปแล้วหรือไม่ หากผ่านไปแล้ว
ก่อนหน้าMillis = ปัจจุบัน Millis; // ประหยัดเวลาของสวิตช์สุดท้าย
ถ้า (ledState == LOW) // ถ้า LED ไม่ติดก็ให้เปิดไฟและในทางกลับกัน
ledState = สูง;
digitalWrite (แสง, ledState); // ตั้งค่าสถานะเอาต์พุตเพื่อเปิดหรือปิด LED
// ************************ ระยะการวัด************************ **
Serial.println(distL);
Serial.println(distC);
Serial.println(distR);
ถ้า (distL>50 && distC>50 && distR>50) // ถ้าวัดได้เกิน 50 เซนติเมตร เราก็ไป
SL = digitalRead(LineSensorLeft); // อ่านสัญญาณจากเซ็นเซอร์เลนซ้าย
SR = digitalRead(LineSensorRight); // อ่านสัญญาณจากเซ็นเซอร์เลนขวา
// ******************************** ตามเส้นสีดำ ************ ******* ****
// หุ่นยนต์บนเลน - ตรงไป
ถ้า (SL == ต่ำ & SR == ต่ำ) // สีขาว - สีขาว - ตรงไป
ไปข้างหน้า (10, 100); // DIRECT (เวลา, ความเร็ว)
// หุ่นยนต์เริ่มเคลื่อนตัวออกนอกเลน - พวกเราแท็กซี่
อย่างอื่นถ้า (SL == LOW & SR == HIGH) // BLACK - WHITE - เลี้ยวซ้าย
ซ้าย (10, 100); // เลี้ยวซ้าย (เวลา, ความเร็ว)
อย่างอื่นถ้า (SL == HIGH & SR == LOW) // สีขาว - สีดำ - เลี้ยวขวา
ขวา (10, 100); // เลี้ยวขวา (เวลา, ความเร็ว)
// เสร็จสิ้น - หุ่นยนต์มองเห็นแถบที่มีเซ็นเซอร์ทั้งสองตัว
อย่างอื่นถ้า (SL == HIGH & SR == HIGH) // BLACK - BLACK - STOP
หยุด (50); // หยุด
อื่น // หากระยะทางที่วัดได้น้อยกว่าหรือเท่ากับขั้นต่ำ - เราก็หยุด