เมื่อใดที่ควรเปลี่ยนจาก ASCII เป็นโปรโตคอลอนุกรมขั้นสูง


28

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

การสื่อสาร ASCII พื้นฐานเป็นที่ยอมรับได้เมื่อใดและฉันควรพิจารณาสิ่งที่สูงกว่าเช่น Modbus หรือไม่ อุปกรณ์เชิงพาณิชย์ใช้ ASCII เช่นนี้หรือไม่? อุตสาหกรรม?


3
คำตอบสั้น ๆ : เมื่อใบสมัครของคุณต้องการมัน ใช่อุปกรณ์เชิงพาณิชย์ใช้ ASCII นำ GPS NMEA มาเป็นตัวอย่าง (และอีกครั้งฉันจะดูคำถามของฉันที่นี่ )
Eugene Sh


@EugeneSh: เป็นที่น่าสังเกตว่า NMEA มีเขตข้อมูลเช็คซัมและการวางตัวอย่างการระเบิดหนึ่งครั้งเนื่องจากความล้มเหลวในการตรวจสอบ (ซึ่งเกิดขึ้นบ่อยกว่าที่คุณคิด) โดยทั่วไปไม่ใช่ความล้มเหลวที่สำคัญ นั่นเป็นเรื่องที่ดีสำหรับโปรโตคอลอื่น ๆ ... และมีโปรโตคอล GPS GPS จำนวนมากที่ใช้งานอยู่ (เช่น Garmin) สำหรับแอปพลิเคชั่นซึ่งมันอาจสำคัญมาก (หรืออัตราการสุ่มตัวอย่างสูงกว่า 1Hz) จำเป็นต้องใช้สำหรับ NMEA ซึ่ง verbose มากเกินไป) แม้ว่านี่จะเป็นเพียงจุดแข็งของคุณเท่านั้น
การแข่งขัน Lightness กับโมนิก้า

คำตอบ:


28
  1. ASCII และ CRC ไม่ได้เกิดขึ้นพร้อมกัน ASCII เป็นการเข้ารหัสและ CRC สำหรับการตรวจสอบข้อผิดพลาด

  2. สิ่งใดสามารถส่งเป็น ASCII พวกเราผู้เฒ่าจำได้อย่างแน่นอนว่า UUEncoding ซึ่งเปลี่ยนทุกอย่างให้เป็นสตริง ASCII

  3. A) สำหรับฉันมันมักจะเป็นคำถามเกี่ยวกับความเร็วและประสิทธิภาพ การส่งหมายเลข 32 บิตขนาดใหญ่โดย ASCII อาจใช้เวลานาน แต่ใช้เวลาเพียง 4 ไบต์ในการส่งเป็นไบนารี่ผ่านโปรโตคอลอนุกรม

    B) การส่ง NUMBERS ผ่าน ASCII หมายความว่าคุณต้องแปลงตัวเลขเป็น ASCII ซึ่งเป็นขั้นตอนพิเศษที่ชัดเจน (นี่เป็นส่วนหนึ่งของสิ่งที่ "printf" ทำ)

  4. หากคุณสูญเสียสถานที่ของคุณอย่างใดอย่างหนึ่ง, สกรูขึ้น, สูญเสียรูปแบบ, ได้รับ endian ผิด ฯลฯ , โปรโตคอลการสื่อสารแบบไบนารีสามารถแน่นอนขึ้น หากคุณกำลังส่ง ASCII จะสามารถกู้คืนได้ง่ายจากอาการเมาค้างโดยเพียงเข้าไปและดูที่สตรีมข้อมูล


12
+1 สำหรับ "ASCII เป็นการเข้ารหัส" มันไม่ใช่โปรโตคอล โปรโตคอลสามารถสร้างขึ้นบน ASCII
Pete Becker

8
การกู้คืนโดยอัตโนมัติจากสกรูอัพไม่ได้เป็นเรื่องง่ายสำหรับโปรโตคอลที่ใช้ข้อความเป็นไบนารีหนึ่ง
Nick Johnson

1
@NickJohnson - อย่างแน่นอน เมื่อคุณถึงจุดเปิดไฟล์ใน hex editor เพื่อดูว่าคุณสามารถกู้คืนอะไรได้คุณก็อยู่ที่ FUBAR จนถึง SOP แล้ว
Scott Seidman

1
@nickjohnson ที่ไม่เป็นความจริง ASCII ให้ตัวเลือกการจัดเฟรม / ตัวคั่นขอบเขตจำนวนมากแก่คุณเพื่อช่วยในการซิงโครไนซ์และการกู้คืนซึ่งจะต้องใช้การหลบหลีกเพิ่มเติมการบรรจุบิตช่วงเวลาหรือเทคนิคอื่น ๆ หากใช้ช่องสัญญาณสำหรับข้อมูลไบนารีเต็มความกว้าง
Chris Stratton

2
ฉันชอบ ASCII เสมอเมื่อเขียนโปรโตคอลเพื่อประโยชน์ที่ชัดเจน (อ่านง่าย, ความสามารถในการล็อกอิน, ฯลฯ ) มีสองกรณีที่ไบนารีเหมาะสมดีกว่า: อันดับแรกหากความเร็วเป็นปัญหาและคุณต้องการไบนารีเพื่ออัดข้อมูลให้มากที่สุดเท่าที่จะเป็นไปได้ในสตรีมและอันดับสองเล็กน้อยถ้าคุณตั้งใจพยายามทำให้งง สตรีมไปยังขัดขวางหรือป้องกันวิศวกรรมย้อนกลับ ที่นั่นฉันมีโปรโตคอลไบนารีแบบย้อนกลับที่ได้รับการดัดแปลงและส่วนใหญ่ทำให้ฉันหงุดหงิดมากกว่าที่จะป้องกันการกระทำ
เจ ...

10

นี่คือความคิดบางอย่างเกี่ยวกับมัน:

  • ASCII นั้นดีเพราะคุณสามารถใช้จอภาพอนุกรมเพื่อดูคู่มือในสิ่งที่ส่ง
  • หากการเชื่อมต่อของคุณไม่น่าเชื่อถือคุณต้องคาดหวังข้อผิดพลาดในการส่งข้อมูลและควรใช้ CRC เพื่อตรวจสอบความสมบูรณ์ของข้อความที่ได้รับแต่ละข้อความ สิ่งนี้สามารถทำได้ในข้อความ ASCII
  • หากการเชื่อมต่อของคุณช้าเกินไปคุณสามารถลดขนาดของข้อความได้โดยเปลี่ยนเป็นรูปแบบไบนารี
  • รูปแบบไบนารีพิเศษอาจง่ายต่อการถอดรหัสทางฝั่งผู้รับมากกว่า ASCII

7

ในระดับที่ง่ายที่สุดคุณสามารถพูดได้ว่าโปรโตคอลการสื่อสารอย่างง่ายมีสามชั้น: ทางกายภาพการขนส่งและการใช้งาน (มีหลายรุ่นเช่นOSI ที่มี 7 หรือTCP / IP ที่มี 4 จำนวนเลเยอร์ไม่สำคัญอย่างยิ่งในบริบทของคำถามนี้)

เลเยอร์แอปพลิเคชันคือเลเยอร์ที่คุณจัดการโดยตรงในรหัสของคุณและจุดเน้นของคำถาม เท่าที่เลเยอร์การขนส่งเกี่ยวข้องไบต์ที่คุณส่งไปใน send_data เป็นเพียงรูปแบบไบนารี แต่คุณอาจตีความมันในรหัสแอปพลิเคชันของคุณเป็นตัวอักษร 'A' การคำนวณ CRC หรือการตรวจสอบจะเหมือนกันโดยไม่คำนึงว่าคุณพิจารณาว่าไบต์เป็น 'A,' 0x41 หรือ 0b01000001

เลเยอร์การขนส่งเป็นระดับแพ็กเก็ตที่คุณมีส่วนหัวของข้อความและการตรวจสอบข้อผิดพลาดไม่ว่าจะเป็น CRC หรือการตรวจสอบขั้นพื้นฐาน ในบริบทของเฟิร์มแวร์คุณอาจมีฟังก์ชั่นเช่น send_data ซึ่งคุณจะส่งเป็นไบต์เพื่อส่ง ภายในฟังก์ชั่นนั้นมันใส่เข้าไปในแพ็คเก็ตที่บอกว่า "เฮ้นี่เป็นข้อความปกติต้องมีการตอบรับและการตรวจสอบคือ 0x47 เวลาปัจจุบันคือ X" แพ็คเก็ตนี้จะถูกส่งออกไปบนชั้นกายภาพเพื่อโหนดรับ

เลเยอร์ทางกายภาพเป็นที่กำหนดอิเล็กทรอนิกส์และอินเตอร์เฟส: ตัวเชื่อมต่อระดับแรงดันไฟฟ้าเวลา ฯลฯ เลเยอร์นี้อาจมีตั้งแต่สองร่องรอยที่ใช้สัญญาณ TTL สำหรับ UART พื้นฐานบน PCB เป็นคู่ที่แยกได้อย่างเต็มที่ในบางครั้งสามารถใช้งานได้

ที่โหนดการรับแพ็คเก็ตจะมาในเลเยอร์ทางกายภาพจะถูกคลายแพ็กเกจที่เลเยอร์การขนส่งและจากนั้นรูปแบบไบนารีของคุณจะพร้อมใช้งานกับชั้นแอปพลิเคชัน มันขึ้นอยู่กับเลเยอร์ของแอปพลิเคชั่นโหนดที่รับรู้ว่ารูปแบบนั้นควรตีความว่า 'A,' 0x41 หรือ 0b01000001 และจะทำอย่างไรกับมัน

โดยสรุปแล้วมันค่อนข้างยอมรับได้เสมอในการส่งอักขระ ASCII ถ้านั่นคือสิ่งที่แอปพลิเคชันต้องการ สิ่งสำคัญคือการเข้าใจรูปแบบการสื่อสารของคุณและรวมถึงกลไกการตรวจสอบข้อผิดพลาด


โปรโตคอล Ascii สามารถรวมการตรวจสอบด้วยเช่นกัน ฉันพบรูปแบบ Hex-as-ascii โดยใช้การแทน ascii ของตัวเลข
ยูจีน Sh.

@EugeneSh ชี้แจงประเด็นดังกล่าว
Matt Young

ไม่ใช่เพื่อ nitpick แต่ TCP ไม่ใช่สี่เลเยอร์ มันถูกมองว่าเหมาะสมในชั้นที่สี่ของแบบจำลอง OSI การสื่อสารแบบอนุกรมไม่เหมาะกับรุ่น OSI เป็นอย่างดี
batsplatsterson

@batsplatsterson นั่นคือ nitpicking และค่อนข้างไม่เกี่ยวข้องกับจุดที่ฉันกำลังทำอยู่
Matt Young

5

จุดที่ยังไม่ได้กล่าวถึงคือไม่ว่าจะมีใครใช้ ASCII หรือไบนารีโปรโตคอลการส่งตัวอักษรออกก่อนแต่ละแพ็กเก็ตจะช่วยให้มั่นใจได้ว่าแม้ว่าสัญญาณรบกวนสายหรือข้อผิดพลาดในการกำหนดกรอบปรากฏขึ้นก่อนที่จะเริ่มแพ็คเก็ต กรอบจะถูกต้องในกรณีที่ไม่มีสัญญาณรบกวนเพิ่มเติม มิฉะนั้นหากมีใครส่งแพ็คเก็ตอย่างต่อเนื่องและไม่มีตัวอักษรใด ๆ ที่รับประกันว่าจะได้รับการซิงโครไนซ์อีกครั้งอาจเป็นไปได้ว่าข้อผิดพลาดอันหนึ่งอาจเสียหายทุกอย่างที่ตามมาจนกว่าจะหยุดส่งครั้งถัดไป อักขระ 0xFF นั้นดีเพราะรับประกันว่าผู้รับใด ๆ จะสามารถซิงโครไนซ์กับอักขระต่อไปนี้อีกครั้ง

(*) 0xFF - เรียกว่า rub-out เพราะคนที่พิมพ์อักขระที่ผิดพลาดในขณะที่พิมพ์ข้อมูลลงบนเทปกระดาษสามารถกดปุ่ม "step tape backward" และกด rub-out เพื่อแทนที่อักขระที่เจาะผิดด้วย 0xFF ซึ่งจะ ผู้รับส่วนใหญ่จะถูกเพิกเฉย)


2

ข้อดีอย่างหนึ่งของการส่งสตริง ASCII ก็คือสามารถใช้รหัสควบคุมเพื่อส่งสัญญาณเริ่มต้น / สิ้นสุดข้อความได้ เช่น STX (ถ่าน 2) และ ETX (ถ่าน 3) สามารถส่งสัญญาณเริ่มส่งและสิ้นสุดส่ง หรือคุณสามารถเพิ่มการป้อนบรรทัดแบบง่าย ๆ เพื่อทำเครื่องหมายจุดสิ้นสุดของการส่ง

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


3
โปรโตคอลไบนารีจำนวนมาก DO สงวนรูปแบบบิตหนึ่งรูปแบบหรือมากกว่าเป็นรหัสควบคุม แต่พวกเขายังมีกลไกการหลบหนีเพื่อจัดการรหัสเหล่านั้นเมื่อพวกเขาปรากฏในข้อมูล
Dave Tweed

คุณสามารถจองรูปแบบใดก็ได้เพื่อตั้งค่าสถานะสิ่งที่คุณต้องการในรูปแบบไบนารี ตัวอย่างเช่นฉันอยู่ในโครงการที่มีสตรีมข้อมูลที่รวดเร็วและสตรีมข้อมูลที่ช้าก็ออกไปข้างนอก uart เดียวกัน ฉันจอง int32 เชิงลบที่ใหญ่ที่สุดเป็นค่าสถานะสำหรับข้อมูลที่ช้าของฉันและเพียงแค่ลบข้อมูลเชิงลบของฉันที่ค่าลบที่ใหญ่ที่สุด + 1
Scott Seidman

ตกลง ฉันชี้แจงเรื่องนี้ในคำตอบที่แก้ไขแล้วฉันหวังว่า
ทรานซิสเตอร์

2

ASCII ไม่เป็นไรฉันใช้มันในเกือบทุกโครงการ มันทำให้การดีบักง่ายขึ้นมากสำหรับการตรวจสอบพอร์ตและมันจะกลายเป็นปัญหาเฉพาะเมื่อมีข้อมูลจำนวนมากที่จะส่ง

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

นอกจากนี้การส่งสิ่งต่าง ๆ ในรูปแบบไบนารี่เป็นไปไม่ได้ที่จะทำการดีบั๊กและขึ้นอยู่กับเครื่องมือของคุณคุณสามารถแยกไบนารีและแปลงเป็นสิ่งที่มนุษย์สามารถอ่านได้ หรือถ้าคุณรู้ว่าคุณกำลังมองหาอะไรคุณสามารถตรวจสอบดาต้าสตรีมและรับรู้คุณค่าที่ควรจะเป็นและหาข้อผิดพลาดด้วยวิธีนั้นแม้ว่าจะไม่ใช่อย่างง่ายดาย เช่นคุณจะรู้จักรูปแบบของไบต์และรับรู้ค่าที่คาดหวัง


2

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

ฉันใช้ HDLC ในเครือข่าย RS-485 โดยไม่มีปัญหาและ PPP ก็ใช้เช่นกัน


2
จะดีถ้าคุณชี้ให้เห็นว่าทำไมคุณแนะนำมากกว่า Modbus
ฉันไม่รู้ว่าฉันกำลังทำอะไรอยู่

1

ASCII บน UART เป็นที่นิยมมากที่สุดเนื่องจาก:

  • เป็นมนุษย์ที่สามารถอ่านได้เมื่อทำการดีบั๊ก (ฉันยังไม่เห็นตัววิเคราะห์เชิงตรรกะที่ไม่ได้ถอดรหัส ASCII)

  • มันง่ายมากที่จะใช้งานคุณได้รับตาราง ASCII ผ่านทาง google ด่วนที่ได้มาตรฐาน

  • มันได้สร้างขึ้นในการประสานกับบิตเริ่มต้น / หยุด

  • โลกทั้งโลกฮอบบิสต์ตั้งขึ้นเองด้วย ASCII บนซีเรียลดังนั้นวิธีการใหม่ใด ๆ ที่จะต้องจัดการกับเรื่องนั้นและนั่นไม่ใช่เรื่องง่าย

จากนั้นคุณจะเข้าสู่สถานการณ์เมื่อคุณเริ่มส่งการเข้ารหัสที่เฉพาะเจาะจงเช่นการส่งหน่วยความจำที่เป็นตัวแทนของการลอยเมื่อเทียบกับการแปลง float เป็น ASCII ส่งที่มากกว่าอนุกรมซึ่งอาจเป็นวิธีที่มากกว่า 4 ไบต์แล้วแปลงกลับ เพื่อเป็นตัวแทนในหน่วยความจำบนโฮสต์ แต่คุณเพียงแค่ส่งการแทน 4 ไบต์ทุกครั้ง แน่นอนว่าคุณสามารถเริ่มจัดการการเข้ารหัสได้ด้วยตัวเอง แต่คุณต้องตั้งค่าแท็กเริ่มต้น / สิ้นสุดคำสั่งซื้อ ฯลฯ

สามารถใช้สิ่งต่างๆเช่นProtobufได้ นี่เป็นจริงที่ใช้ในโครงการที่ฉันกำลังทำอยู่และมันมีประโยชน์อย่างมากมันมีข้อความความยาวผันแปรจัดการ endian สำหรับคุณและคุณสมบัติเจ๋ง ๆ อีกสองสามอย่าง มันยังไม่ใหญ่ขนาดรหัสและคุณสามารถระบุทุกอย่างที่จะถูกจัดสรรแบบคงที่เมื่อเริ่มต้น คุณจะต้องโยนเช็คซัมด้วยตัวเองถ้าคุณต้องการ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.