กระบวนการแบบขนานของ Arduino Arduino: การเชื่อมต่อแบบขนานและแบบอนุกรมของอุปกรณ์ทาสกับบัส SPI การควบคุม LED และ Piezo Emitter โดยใช้ตัวดำเนินการหน่วงเวลา ()

โดยทั่วไปแล้ว 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.

แผนภาพการเชื่อมต่อจะยังคงเหมือนเดิม เฉพาะรหัสโปรแกรมเท่านั้นที่จะเปลี่ยนแปลง

#รวม // เชื่อมต่อไลบรารี ArduinoThread const int soundPin = 3; // ตัวแปรที่มีหมายเลขพินขององค์ประกอบเพียโซอิเล็กทริก const int ledPin = 13; // ตัวแปรที่มีหมายเลขพิน LED Thread ledThread = Thread(); // สร้างเธรดควบคุม LED Thread soundThread = Thread(); // สร้างเธรดควบคุมไซเรน การตั้งค่าเป็นโมฆะ () ( pinMode(soundPin, เอาท์พุต); // ประกาศพิน 3 เป็นเอาต์พุต } pinMode(ledPin, เอาท์พุต); // ประกาศพิน 13 เป็นเอาต์พุต pinMode(ledPin, เอาท์พุต); // ประกาศพิน 13 เป็นเอาต์พุต } ledThread.onRun(ledBlink); // มอบหมายงานให้กับเธรด ledThread.setInterval(1000); // ตั้งค่าช่วงเวลาตอบสนอง ms soundThread.onRun(sound); // มอบหมายงานให้กับเธรด soundThread.setInterval(20); // กำหนดช่วงเวลาตอบสนอง ms // ตรวจสอบว่าถึงเวลาที่ LED จะเปลี่ยนหรือไม่: if (ledThread.shouldRun()) ledThread.run(); // เริ่มเธรด // ตรวจสอบว่าถึงเวลาเปลี่ยนเสียงไซเรนหรือไม่: if (soundThread.shouldRun()) soundThread.run(); //เริ่มกระทู้// กระแสไฟ LED: } เป็นโมฆะ ledBlink() ( บูลคงที่ ledStatus = false; // สถานะ LED เปิด/ปิด ledStatus = !ledStatus; // สลับสถานะ digitalWrite (ledPin, ledStatus); // เปิด/ปิด LED// กระแสไซเรน:

เสียงเป็นโมฆะ() ( โทนเสียงคงที่ = 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); // หยุด

อื่น // หากระยะทางที่วัดได้น้อยกว่าหรือเท่ากับขั้นต่ำ - เราก็หยุด