อ้างอิงถึง Arduino Uno, Mega2560, Leonardo และบอร์ดที่คล้ายกัน:
- การสื่อสารแบบอนุกรมทำงานอย่างไร
- ซีเรียสนั้นเร็วแค่ไหน?
- ฉันจะเชื่อมต่อระหว่างผู้ส่งและผู้รับได้อย่างไร
โปรดทราบ: นี่เป็นคำถามอ้างอิง
อ้างอิงถึง Arduino Uno, Mega2560, Leonardo และบอร์ดที่คล้ายกัน:
โปรดทราบ: นี่เป็นคำถามอ้างอิง
คำตอบ:
การสื่อสารแบบอนุกรมแบบอะซิงโครนัส (โดยปกติจะเรียกว่าแบบอนุกรม) ใช้เพื่อส่งไบต์จากอุปกรณ์หนึ่งไปยังอุปกรณ์อื่น อุปกรณ์อาจเป็นหนึ่งในสิ่งต่อไปนี้:
ซึ่งแตกต่างจากการสื่อสารแบบอนุกรม SPI / USB / I2C ไม่มีสัญญาณนาฬิกา นาฬิกาตัวอย่างเป็นอัตราตัวอย่างที่ตกลงกันไว้ (เรียกว่าอัตรารับส่งข้อมูล) ทั้งผู้ส่งและผู้รับจะต้องได้รับการกำหนดค่าให้ใช้อัตราเดียวกันมิฉะนั้นผู้รับจะได้รับข้อมูลที่ไม่มีความหมาย (เนื่องจากบิตที่ไม่ได้ถูกสุ่มตัวอย่างในอัตราเดียวกันกับที่พวกเขาถูกส่ง)
การส่งเป็นแบบอะซิงโครนัสซึ่งโดยทั่วไปหมายความว่าไบต์สามารถส่งได้ตลอดเวลาโดยมีช่องว่างที่แตกต่างกันระหว่างพวกเขา กราฟิกนี้แสดงให้เห็นว่ามีการส่งไบต์เดียว:
ภาพด้านบนแสดงตัวอักษร 'F' ที่กำลังถูกส่ง ใน ASCII นี่คือ 0x46 (เป็นเลขฐานสิบหก) หรือ 0b01000110 (เป็นเลขฐานสอง) น้อยอย่างมีนัยสำคัญ (ต่ำลำดับ) 01100010
บิตจะถูกส่งเป็นครั้งแรกดังนั้นในกราฟิกข้างต้นที่คุณเห็นบิตที่เดินทางมาถึงในลำดับที่:
เวลา "ไม่ได้ใช้งาน" ระหว่างไบต์จะถูกส่งเป็นบิต "1" ต่อเนื่อง (อย่างมีประสิทธิภาพบรรทัดการส่งจะถูกเก็บไว้อย่างต่อเนื่องสูง)
เพื่อระบุจุดเริ่มต้นของไบต์บิตเริ่มต้นจะถูกระบุเสมอโดยการดึงบรรทัดต่ำตามที่แสดงบนกราฟิก เมื่อผู้รับเห็นบิตเริ่มต้นมันจะรอ 1.5 เท่าของเวลาตัวอย่างจากนั้นสุ่มตัวอย่างบิตข้อมูล มันรอ 1.5 ครั้งเพื่อที่:
หากอัตรา baud เป็น 9600 baud เช่นนั้นอัตราตัวอย่างจะเป็น1/9600 = 0.00010416
วินาที (104.16 µs)
ดังนั้นที่ 9600 baud หลังจากได้รับบิตเริ่มต้นผู้รับจะรอ 156.25 ands แล้วสุ่มตัวอย่างทุก ๆ 104.16
จุดประสงค์ของStop Bitคือเพื่อให้แน่ใจว่ามี 1 บิตระหว่างแต่ละไบต์ หากไม่มีไบต์หยุดหากไบต์สิ้นสุดลงที่ศูนย์ดังนั้นจะเป็นไปไม่ได้ที่ฮาร์ดแวร์จะสามารถบอกความแตกต่างระหว่างสิ่งนั้นกับบิตเริ่มต้นของไบต์ต่อไป
เพื่อผลิตผลลัพธ์ข้างต้นใน Uno คุณสามารถเขียนรหัสนี้:
void setup()
{
Serial.begin(9600);
Serial.print("F");
}
void loop ()
{
}
เพื่อที่จะประหยัดเวลาในการส่งข้อมูล (ในสมัยก่อน heh) คุณได้รับอนุญาตให้ระบุจำนวนบิตข้อมูลที่แตกต่างกัน ฮาร์ดแวร์ AtMega รองรับบิตข้อมูลที่มีหมายเลขตั้งแต่ 5 ถึง 9 บิตยิ่งน้อยกว่าบิตข้อมูลที่คุณสามารถส่งได้น้อยลง แต่ยิ่งเร็วเท่าไหร่
คุณสามารถเลือกที่จะมีบิตพาริตี้ คำนวณนี้ถ้าจำเป็นโดยการนับจำนวน 1 ในตัวอักษรแล้วตรวจสอบให้แน่ใจว่าตัวเลขนี้เป็นเลขคี่หรือแม้กระทั่งโดยการตั้งค่าบิตพาริตีเป็น 0 หรือ 1 ตามที่ต้องการ
ตัวอย่างเช่นสำหรับตัวอักษร "F" (หรือ 0x46 หรือ 0b01000110) คุณจะเห็นว่ามี 3 ตัว (ใน 01000110) ดังนั้นเราจึงมีความเท่าเทียมกันแปลก ดังนั้นบิตพาริตีจะเป็นดังนี้:
บิตพาริตี (ถ้ามี) จะปรากฏขึ้นหลังจากบิตข้อมูลสุดท้าย แต่ก่อนบิตหยุด
หากผู้รับไม่ได้รับบิตพาริตีที่ถูกต้องนั่นจะเรียกว่า "ข้อผิดพลาดพาริตี" มันแสดงว่ามีปัญหาบางอย่าง อาจเป็นไปได้ว่าผู้ส่งและผู้รับได้รับการกำหนดค่าให้ใช้อัตราการรับส่งข้อมูล (บิต) ที่แตกต่างกันหรือมีสัญญาณรบกวนในบรรทัดซึ่งเปลี่ยนเป็นศูนย์เป็นหนึ่งหรือในทางกลับกัน
ระบบเริ่มต้นบางระบบใช้พาริตี "ทำเครื่องหมาย" (โดยที่บิตพาริตีคือ 1 โดยไม่คำนึงถึงข้อมูล) หรือพาริตี "ช่องว่าง" (โดยที่บิตพาริตีเป็น 0 เสมอโดยไม่คำนึงถึงข้อมูล)
อุปกรณ์สื่อสารบางอย่างใช้ข้อมูล 9 บิตดังนั้นในกรณีนี้บิตพาริตี้จะเปลี่ยนเป็นบิตที่ 9 มีเทคนิคพิเศษสำหรับการส่งบิตที่ 9 นี้ (รีจิสเตอร์เป็นเรจิสเตอร์ 8 บิตดังนั้นบิตที่ 9 จะต้องใส่ที่อื่น)
อุปกรณ์แรกมีแนวโน้มที่จะค่อนข้างช้าลงทางอิเล็กทรอนิกส์ดังนั้นเพื่อให้เวลาของผู้รับในการประมวลผลไบต์ขาเข้าบางครั้งมีการระบุว่าผู้ส่งจะส่งบิตหยุดสองบิต โดยทั่วไปจะเพิ่มเวลามากขึ้นเมื่อสายข้อมูลถูกเก็บไว้สูง (อีกหนึ่งบิตอีกครั้ง) ก่อนที่จะสามารถเริ่มบิตถัดไปได้ เวลาบิตพิเศษนี้ให้เวลาผู้รับเพื่อประมวลผลไบต์ขาเข้าล่าสุด
หากผู้รับไม่ได้รับตรรกะ 1 เมื่อบิตควรจะหยุดที่เรียกว่า "ข้อผิดพลาดในการกำหนดกรอบ" มันแสดงว่ามีปัญหาบางอย่าง ค่อนข้างเป็นไปได้ว่าผู้ส่งและผู้รับได้รับการกำหนดค่าให้ใช้อัตรารับส่งข้อมูล (บิต) ที่แตกต่างกัน
โดยทั่วไปการสื่อสารแบบอนุกรมจะแสดงโดยบอกความเร็วจำนวนบิตข้อมูลประเภทของพาริตี้และจำนวนบิตหยุดเช่นนี้:
9600/8-N-1
นี่คือการบอกเรา:
เป็นเรื่องสำคัญที่ผู้ส่งและผู้รับจะต้องยอมรับในข้างต้นมิฉะนั้นการสื่อสารก็ไม่น่าจะสำเร็จ
Arduino Uno มีพินดิจิตอล 0 และ 1 สำหรับซีเรียลฮาร์ดแวร์:
ในการเชื่อมต่อ Arduinos สองอันคุณต้องสลับ Tx และ Rx ดังนี้:
รองรับความเร็วที่หลากหลาย (ดูกราฟิคด้านล่าง) ความเร็ว "มาตรฐาน" มักจะเป็นหลายเท่าของ 300 baud (เช่น 300/600/1200/2400 เป็นต้น)
ความเร็ว "ที่ไม่ได้มาตรฐาน" อื่น ๆ สามารถจัดการได้โดยการตั้งค่าการลงทะเบียนที่เหมาะสม คลาส HardwareSerial ใช้สำหรับคุณ เช่น.
Serial.begin (115200); // set speed to 115200 baud
ในฐานะกฎของหัวแม่มือสมมติว่าคุณกำลังใช้ข้อมูล 8 บิตจากนั้นคุณสามารถประมาณจำนวนไบต์ที่คุณสามารถส่งต่อวินาทีโดยแบ่งอัตรารับส่งข้อมูลเป็น 10 (เพราะบิตเริ่มต้นและบิตหยุด)
ดังนั้นที่ 9600 baud คุณสามารถส่ง 960 bytes ( 9600 / 10 = 960
) ต่อวินาที
อัตราการรับส่งข้อมูลของ Atmega นั้นสร้างขึ้นโดยการแบ่งเวลาของระบบนาฬิกาจากนั้นนับเป็นจำนวนที่ตั้งไว้ล่วงหน้า ตารางนี้จากแผ่นข้อมูลแสดงค่าการลงทะเบียนและเปอร์เซ็นต์ความผิดพลาดสำหรับนาฬิกา 16 MHz (เช่นหนึ่งใน Arduino Uno)
บิต U2Xn ส่งผลกระทบต่อตัวหารอัตรานาฬิกา (0 = หารด้วย 16, 1 = หารด้วย 8) การลงทะเบียน UBRRn มีจำนวนโปรเซสเซอร์ที่นับได้สูงสุด
จากตารางด้านบนเราเห็นว่าเราได้รับ 9600 baud จากนาฬิกา 16 MHz ดังนี้:
16000000 / 16 / 104 = 9615
เราหารด้วย 104 และไม่ใช่ 103 เพราะตัวนับนั้นเป็นศูนย์สัมพันธ์ ดังนั้นข้อผิดพลาดที่นี่15 / 9600 = 0.0016
ซึ่งอยู่ใกล้กับสิ่งที่ตารางข้างต้นพูดว่า (0.02%)
คุณจะสังเกตเห็นว่าอัตราการรับส่งข้อมูลบางอย่างมีจำนวนข้อผิดพลาดสูงกว่าอัตราอื่น ๆ
ตามแผ่นข้อมูลเปอร์เซ็นต์ความผิดพลาดสูงสุดสำหรับ 8 บิตข้อมูลอยู่ในช่วง 1.5% ถึง 2.0% (ดูแผ่นข้อมูลสำหรับรายละเอียดเพิ่มเติม)
Arduino Leonardo และ Micro มีวิธีการสื่อสารแบบอนุกรมที่แตกต่างกันเนื่องจากพวกเขาเชื่อมต่อโดยตรงผ่าน USB เข้ากับโฮสต์คอมพิวเตอร์ไม่ใช่ผ่านพอร์ตอนุกรม
ด้วยเหตุนี้คุณต้องรอให้ Serial เป็น "พร้อม" (เนื่องจากซอฟต์แวร์สร้างการเชื่อมต่อ USB) โดยมีบรรทัดเพิ่มเติมสองบรรทัดเช่นนี้
void setup()
{
Serial.begin(115200);
while (!Serial)
{} // wait for Serial comms to become ready
Serial.print("Fab");
}
void loop ()
{
}
อย่างไรก็ตามหากคุณต้องการสื่อสารผ่านพิน D0 และ D1 จริง ๆ (แทนที่จะใช้สายเคเบิล USB) คุณต้องใช้ Serial1 แทน Serial คุณทำเช่นนี้:
void setup()
{
Serial1.begin(115200);
Serial1.print("Fab");
}
void loop ()
{
}
โปรดทราบว่า Arduino ใช้ระดับ TTL สำหรับการสื่อสารแบบอนุกรม ซึ่งหมายความว่าคาดว่า:
อุปกรณ์อนุกรมรุ่นเก่าที่ออกแบบมาเพื่อเสียบเข้ากับพอร์ตอนุกรมของพีซีอาจใช้ระดับแรงดันไฟฟ้า RS232 ซึ่ง ได้แก่ :
ไม่เพียง แต่เป็น "ฤvertedษี" ที่เกี่ยวกับระดับ TTL ("หนึ่ง" เป็นลบมากกว่า "ศูนย์"), Arduino ไม่สามารถจัดการแรงดันไฟฟ้าเชิงลบบนหมุดอินพุตของมัน (หรือบวกมากกว่า 5V)
ดังนั้นคุณต้องมีวงจรอินเตอร์เฟสสำหรับการสื่อสารกับอุปกรณ์ดังกล่าว สำหรับอินพุต (ไปยัง Arduino) เท่านั้นทรานซิสเตอร์ธรรมดาไดโอดและตัวต้านทานสองตัวจะทำ:
สำหรับการสื่อสารสองทางคุณต้องสามารถสร้างแรงดันไฟฟ้าเชิงลบได้ดังนั้นจึงจำเป็นต้องใช้วงจรที่ซับซ้อนมากขึ้น ตัวอย่างเช่นชิป MAX232 จะทำเช่นนั้นร่วมกับตัวเก็บประจุ 1 µF สี่ตัวเพื่อทำหน้าที่เป็นวงจรปั๊มประจุ
มีไลบรารีชื่อ SoftwareSerial ที่ให้คุณสื่อสารแบบอนุกรม (จนถึงจุดหนึ่ง) ในซอฟต์แวร์มากกว่าฮาร์ดแวร์ นี่เป็นข้อดีที่คุณสามารถใช้การกำหนดค่าพินที่แตกต่างกันสำหรับการสื่อสารแบบอนุกรม ข้อเสียคือการทำซีเรียลในซอฟต์แวร์นั้นใช้ตัวประมวลผลมากขึ้นและมีแนวโน้มที่จะเกิดข้อผิดพลาดมากขึ้น ดูSoftware Serialสำหรับรายละเอียดเพิ่มเติม
Arduino "Mega" มีพอร์ตอนุกรมฮาร์ดแวร์เพิ่มเติม 3 พอร์ต พวกเขาถูกทำเครื่องหมายบนกระดานเป็น Tx1 / Rx1, Tx2 / Rx2, Tx3 / Rx3 ควรใช้ซอฟต์แวร์เหล่านี้ตามความต้องการของ SoftwareSerial ในการเปิดพอร์ตอื่น ๆ เหล่านั้นให้ใช้ชื่อ Serial1, Serial2, Serial3 เช่นนี้:
Serial1.begin (115200); // start hardware serial port Tx1/Rx1
Serial2.begin (115200); // start hardware serial port Tx2/Rx2
Serial3.begin (115200); // start hardware serial port Tx3/Rx3
ทั้งการส่งและรับโดยใช้ไลบรารี HardwareSerial ใช้การขัดจังหวะ
เมื่อคุณทำ a Serial.print
ข้อมูลที่คุณพยายามพิมพ์จะถูกวางในบัฟเฟอร์ "ส่ง" ภายใน หากคุณมี 1024 ไบต์หรือมากกว่า RAM (เช่นใน Uno) คุณจะได้รับบัฟเฟอร์ 64- มิฉะนั้นคุณจะได้รับบัฟเฟอร์ 16 ไบต์ หากบัฟเฟอร์มีที่ว่างแล้วSerial.print
จะส่งคืนทันทีจึงไม่ทำให้รหัสของคุณล่าช้า หากไม่มีที่ว่างก็จะ "บล็อก" รอให้บัฟเฟอร์ว่างเปล่าพอที่จะมีที่ว่าง
จากนั้นเมื่อแต่ละไบต์ถูกส่งโดยฮาร์ดแวร์อินเตอร์รัปต์จะถูกเรียก (อินเทอร์รัปต์ "USART, Data Register Empty") และรูทีนการขัดจังหวะจะส่งไบต์ถัดไปจากบัฟเฟอร์ออกจากพอร์ตอนุกรม
เมื่อได้รับข้อมูลขาเข้าแล้วรูทีนการขัดจังหวะจะถูกเรียก (การขัดจังหวะ "USART Rx Complete") และไบต์ขาเข้าจะถูกวางลงในบัฟเฟอร์ "รับ" (ขนาดเดียวกับบัฟเฟอร์การส่งสัญญาณที่กล่าวถึงข้างต้น)
เมื่อคุณโทรSerial.available
หาคุณจะทราบว่ามีกี่ไบต์ในบัฟเฟอร์ "รับ" นั้น เมื่อคุณเรียกSerial.read
ไบต์จะถูกลบออกจากบัฟเฟอร์การรับและส่งกลับไปที่รหัสของคุณ
ใน Arduinos ที่มีหน่วยความจำ 1,000 ไบต์ขึ้นไปไม่ต้องรีบลบข้อมูลออกจากบัฟเฟอร์รับหากคุณไม่ปล่อยให้มันเติม หากกรอกข้อมูลแล้วข้อมูลขาเข้าเพิ่มเติมจะถูกยกเลิก
โปรดทราบว่าเนื่องจากขนาดของบัฟเฟอร์นี้ไม่มีจุดรอให้จำนวนไบต์ที่มาถึงมากตัวอย่างเช่น:
while (Serial.available () < 200)
{ } // wait for 200 bytes to arrive
สิ่งนี้จะไม่ทำงานเนื่องจากบัฟเฟอร์ไม่สามารถเก็บได้มาก
ก่อนอ่านควรตรวจสอบให้แน่ใจว่ามีข้อมูลอยู่เสมอ ตัวอย่างเช่นนี่ผิด
if (Serial.available ())
{
char a = Serial.read ();
char b = Serial.read (); // may not be available
}
การSerial.available
ทดสอบทำให้คุณมั่นใจว่าคุณมีหนึ่งไบต์ แต่รหัสพยายามอ่านสองตัว มันอาจทำงานได้หากมีสองไบต์ในบัฟเฟอร์ถ้าไม่คุณจะได้รับ -1 คืนซึ่งจะมีลักษณะเช่น 'ÿ' ถ้าพิมพ์
ใช้ความระมัดระวังในการส่งข้อมูล ดังที่กล่าวไว้ข้างต้นที่ 9600 บอดคุณส่งเพียง 960 ไบต์ต่อวินาทีดังนั้นพยายามส่ง 1,000 อ่านจากพอร์ตอะนาล็อกที่ 9600 บอดจะไม่ประสบความสำเร็จมาก