ประเภท: วงจรไมโครคอนโทรลเลอร์
จำนวนการดู: 41940
ความเห็นเกี่ยวกับบทความ: 5

วิธีการสำหรับการอ่านและการจัดการพอร์ต Arduino I / O

 

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

วิธีการสำหรับการอ่านและการจัดการพอร์ต Arduino I / O

วิธีที่หนึ่ง - ภาษามาตรฐานสำหรับ Arduino IDE

ทุกคนรู้ดีว่า Arduino มันถูกตั้งโปรแกรมใน C ++ พร้อมการปรับแต่งและการทำให้เรียบง่ายสำหรับผู้เริ่มต้น มันเรียกว่าการเดินสาย เริ่มแรกพอร์ต arduino ทั้งหมดจะถูกกำหนดเป็นอินพุตและไม่จำเป็นต้องระบุในรหัส

พอร์ตมักจะเขียนในฟังก์ชั่นการเริ่มต้นตัวแปร:

การตั้งค่าเป็นโมฆะ ()
{
// รหัส
}

คำสั่ง pinMode ใช้สำหรับสิ่งนี้มันมีไวยากรณ์ที่ค่อนข้างง่ายก่อนอื่นหมายเลขพอร์ตจะถูกระบุจากนั้นบทบาทจะถูกคั่นด้วยเครื่องหมายจุลภาค

pinMode (nomer_porta, naznachenie)

ด้วยคำสั่งนี้วงจรภายในของไมโครคอนโทรลเลอร์จะถูกกำหนดค่าด้วยวิธีเฉพาะ

มีสามโหมดที่พอร์ตสามารถทำงานได้: อินพุต - อินพุตในโหมดนี้เกิดขึ้น อ่านข้อมูลจากเซ็นเซอร์สถานะปุ่มสัญญาณอะนาล็อกและดิจิตอล พอร์ตตั้งอยู่ในสิ่งที่เรียกว่า สภาวะที่มีความต้านทานสูงในคำง่ายๆ - อินพุตมีความต้านทานสูง ค่านี้ถูกตั้งค่าไว้เช่น 13 pin ของบอร์ดหากจำเป็นดังต่อไปนี้:

pinMode (13, INPUT);

OUTPUT - เอาต์พุตขึ้นอยู่กับคำสั่งที่กำหนดไว้ในรหัสพอร์ตใช้ค่าหนึ่งหรือศูนย์ เอาต์พุตกลายเป็นแหล่งพลังงานที่ควบคุมได้และสร้างกระแสสูงสุด (ในกรณีของเราคือ 20 mA และ 40 mA ที่จุดสูงสุด) ที่เชื่อมต่อกับโหลด ในการกำหนดพอร์ตเป็นเอาต์พุตไปยัง Arduino คุณต้องป้อน:

pinMode (13, OUTPUT);

INPUT_PULLUP - พอร์ตทำงานเป็นอินพุต แต่สิ่งที่เรียกว่าเชื่อมต่อกับมัน ตัวต้านทานแบบดึงขึ้น 20 kΩ

วงจรภายในแบบมีเงื่อนไขของพอร์ตในสถานะนี้แสดงอยู่ด้านล่าง คุณลักษณะของอินพุตนี้คือสัญญาณอินพุตถูกรับรู้เป็นฤvertedษี (“ หน่วย” ที่อินพุตถูกรับรู้โดยไมโครคอนโทรลเลอร์ว่า“ ศูนย์”) ในโหมดนี้คุณไม่สามารถใช้ตัวต้านทานแบบดึงขึ้นภายนอกได้ เมื่อทำงานกับปุ่มต่างๆ.

pinMode (13, INPUT_PULLUP);

ตัวต้านทานแบบดึงขึ้นอินพุต

ข้อมูลที่ได้รับจากพอร์ตและส่งไปยังพวกเขาโดยคำสั่ง:

  • digitalWrite (พินค่า) - แปลงพินเอาต์พุตเป็นโลจิคัล 1 หรือ 0 ตามลำดับแรงดัน 5V จะปรากฏขึ้นหรือหายไปที่เอาต์พุตเช่น digitalWrite (13, HIGH) - จ่าย 5 โวลต์ (โลจิคัลยูนิต) เป็น 13 พินและ digitalWrite (13, ต่ำ ) - แปล 13 พินให้อยู่ในสถานะศูนย์ตรรกะ (0 โวลต์)

  • digitalRead (พิน) - อ่านค่าจากอินพุตเช่น digitalRead (10) อ่านสัญญาณจาก 10 พิน

  • analogRead (พิน) - อ่านสัญญาณอะนาล็อกจากพอร์ตอะนาล็อกคุณจะได้รับค่าอยู่ในช่วงตั้งแต่ 0 ถึง 1023 (ภายใน ADC 10 บิต) ตัวอย่างคือ analogRead (3)


วิธีที่สอง - จัดการพอร์ตผ่าน Atmega register และเร่งความเร็วโค้ด

แน่นอนว่าการควบคุมดังกล่าวเป็นเรื่องง่าย แต่ในกรณีนี้มีสองข้อเสียคือการใช้หน่วยความจำที่มากขึ้นและประสิทธิภาพที่ต่ำเมื่อทำงานกับพอร์ต แต่จำไว้ว่า Arduino คืออะไรโดยไม่คำนึงถึงบอร์ดตัวเลือก (uno, micro, nano)? ก่อนอื่นนี้ ไมโครคอนโทรลเลอร์ตระกูล AVR ATMEGAเพิ่งใช้ MK atmega328

ใน Arduino IDE คุณสามารถตั้งโปรแกรมภาษา C AVR ให้กับตระกูลนี้ราวกับว่าคุณกำลังทำงานกับไมโครคอนโทรลเลอร์แยกต่างหาก แต่สิ่งแรกก่อน ในการจัดการพอร์ต Arduino ด้วยวิธีนี้อันดับแรกคุณต้องพิจารณาภาพประกอบต่อไปนี้อย่างรอบคอบ

Atmega168 พอร์ตไมโครคอนโทรลเลอร์

อาจมีบางคนที่จะตรวจสอบพอร์ตในรูปแบบนี้อย่างชัดเจนมากขึ้น (เหมือนกันในรูป แต่ในรูปแบบที่แตกต่างกัน):

Atmega328 พอร์ตไมโครคอนโทรลเลอร์

ที่นี่คุณจะเห็นการโต้ตอบของข้อสรุปของ Arduino และชื่อของพอร์ตของ Atmega ดังนั้นเรามี 3 พอร์ต:

  • PORTB;

  • PORTC;

  • PORTD

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

ตารางความสอดคล้องของพอร์ต Arduino และ Atmega

Atmega มีรีจิสเตอร์ 8 บิตสามตัวที่ควบคุมสถานะของพอร์ตตัวอย่างเช่นพอร์ต B จะคิดออกวัตถุประสงค์ของพวกเขาโดยการวาดคล้ายคลึงกับเครื่องมือการเดินสายมาตรฐานที่อธิบายไว้ที่จุดเริ่มต้นของบทความนี้:

  • PORTB - จัดการสถานะเอาต์พุต หากพินอยู่ในโหมด“ เอาต์พุต” ดังนั้น 1 และ 0 จะกำหนดว่ามีสัญญาณเดียวกันที่เอาต์พุตหรือไม่ หากพินอยู่ในโหมด“ อินพุต” ดังนั้น 1 จะเชื่อมต่อตัวต้านทานแบบดึงขึ้น (เช่นเดียวกับ INPUT_PULLUP ที่กล่าวถึงด้านบน) ถ้า 0 เป็นสถานะความต้านทานสูง (อนาล็อกของอินพุต)

  • PINB เป็นทะเบียนอ่าน ดังนั้นจึงมีข้อมูลเกี่ยวกับสถานะปัจจุบันของพินพอร์ต (หน่วยโลจิคัลหรือศูนย์)

  • DDRB - การลงทะเบียนทิศทางพอร์ต ด้วยคุณระบุไมโครคอนโทรลเลอร์ว่าพอร์ตเป็นอินพุตหรือเอาต์พุตโดยมี“ 1” เอาต์พุตและ“ 0” อินพุต

แทนที่จะใช้ตัวอักษร“ B” สามารถมีชื่ออื่นตามชื่อพอร์ตตัวอย่างเช่นคำสั่งอื่น ๆ ของ PORTD หรือ PORTC ก็ทำงานในทำนองเดียวกัน

เรากระพริบไฟ LED แทนฟังก์ชั่น digitalWrite () มาตรฐาน ก่อนอื่นเรามาดูกันว่าตัวอย่างต้นฉบับจากห้องสมุด Arduino IDE มีหน้าตาเป็นอย่างไร

Arduino LED กระพริบรหัส

นี่คือรหัสของ“ การกะพริบ” ที่รู้จักกันดีซึ่งแสดงการกะพริบของ LED ที่ติดตั้งไว้ในบอร์ด

การจัดการพิน

ความคิดเห็นอธิบายรหัส ตรรกะของงานนี้มีดังนี้

คำสั่ง PORTB B00100000 ทำให้ PB5 อยู่ในสถานะของหน่วยโลจิคัลรูปลักษณ์และรูปภาพเหล่านั้นและตารางที่อยู่ด้านล่างและดูว่า PB5 นั้นสอดคล้องกับ Arduina 13 พิน

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

โครงสร้างพอร์ต D

คุณสามารถตั้งค่าไม่ได้อยู่ในไบนารี แต่ในรูปแบบเลขฐานสิบหกเช่นนี้เราเปิดเครื่องคิดเลข windows และในโหมด“ ดู” ให้เลือกตัวเลือก“ โปรแกรมเมอร์”

เครื่องคิดเลข Windows

ป้อนหมายเลขที่ต้องการ:

โหมดเครื่องคิดเลขโปรแกรมเมอร์

และคลิกที่ HEX:

การแปลตัวเลขในเครื่องคิดเลข

ในกรณีนี้เราถ่ายโอนทั้งหมดนี้ไปยัง Arduino IDE แต่แทนที่จะเป็นคำนำหน้า "B" มันจะเป็น "0x"

การถ่ายโอนตัวเลขใน Arduino IDE

แต่ด้วยอินพุตนี้มีปัญหา หากคุณมีสิ่งใดเชื่อมต่อกับพินอื่นให้ป้อนคำสั่งเช่น B00010000 - คุณจะรีเซ็ตพินทั้งหมดยกเว้น 13 (PB5) คุณสามารถป้อนข้อมูลสำหรับแต่ละพินได้ทีละรายการ มันจะมีลักษณะเช่นนี้:

การป้อนข้อมูลลงในแต่ละพิน

เร็กคอร์ดดังกล่าวอาจดูเข้าใจไม่ได้ลองหากัน

การแยกบันทึก

นี่เป็นการดำเนินการเพิ่มเติมเชิงตรรกะ | = หมายถึงการเพิ่มบางสิ่งลงในเนื้อหาของพอร์ต

การดำเนินการเพิ่มเติมเชิงตรรกะ

ซึ่งหมายความว่าคุณต้องเพิ่มคำว่า 8 บิตในรีจิสเตอร์โดยที่หน่วยเลื่อนไป 5 บิต - ถ้า 11000010 เปลี่ยนเป็น 110,110,010 ในตัวอย่างนี้จะเห็นได้ว่ามีการเปลี่ยนแปลงเพียง PB5 เท่านั้นส่วนที่เหลือของเรจิสเตอร์นี้ยังคงไม่เปลี่ยนแปลง สถานะของหมุดไมโครคอนโทรลเลอร์ยังคงไม่เปลี่ยนแปลง

แต่ด้วยการเพิ่มเชิงตรรกะปัญหาเกิดขึ้น - คุณไม่สามารถเปลี่ยนหน่วยเป็นศูนย์ได้เนื่องจาก:

0+0=1

1+0=1

0+1=1

การคูณเชิงตรรกะและการผกผันจะช่วยเราได้:

การคูณเชิงตรรกะและการอินเวอร์เตอร์

& = หมายถึงการคูณเนื้อหาของพอร์ตด้วยตัวเลขเฉพาะ

 

การคูณเนื้อหาพอร์ตด้วยตัวเลข

และนี่คือจำนวนที่เราคูณ เครื่องหมาย“ ~” หมายถึงการกลับด้าน ในกรณีของเราหน่วยกลับเป็นศูนย์ นั่นคือเราคูณเนื้อหาของพอร์ตเป็นศูนย์เลื่อนเป็น 5 บิต ตัวอย่างเช่นมันคือ 10110001 มันกลายเป็น 10100001 บิตที่เหลือยังคงไม่เปลี่ยนแปลง

ทวีคูณเนื้อหาของพอร์ตโดยเลื่อนเป็นศูนย์ 5 บิต

สามารถทำได้โดยใช้การดำเนินการกลับหัว (^):

การอ่านจากพอร์ตอะนาล็อกของ digitalRead () ดำเนินการโดยใช้การลงทะเบียน PIN ในทางปฏิบัติดูเหมือนว่า:

อ่านจากพอร์ต

ที่นี่เราตรวจสอบว่าการแสดงออกในวงเล็บเท่ากับรัฐจริงของพอร์ตคือ ในทำนองเดียวกันถ้าเราเขียนว่า (digitalRead (12) == 1)


ข้อสรุป

ทำไมถึงมีปัญหาดังกล่าวกับการจัดการพอร์ตหากคุณสามารถใช้ฟังก์ชั่นที่สะดวกสบายมาตรฐาน ทุกอย่างเกี่ยวกับความเร็วและขนาดโค้ด เมื่อใช้วิธีที่สองที่กล่าวถึงในบทความขนาดของรหัสจะลดลงอย่างมากและความเร็วจะเพิ่มขึ้นตามลำดับความสำคัญหลายประการ DigitalWrite มาตรฐาน () ถูกดำเนินการใน 1800 μsและบันทึกโดยตรงไปยังพอร์ตใน 0.2 μsและ digitalRead () ใน 1900 μsและยังกลายเป็น 0.2 μs วิธีการควบคุมนี้พบในพื้นที่เปิดโล่งของเครือข่ายและมักจะพบในรหัส โครงการที่แล้วเสร็จ.

ดูได้ที่ bgv.electricianexp.com:

  • การเชื่อมต่อและการเขียนโปรแกรม Arduino สำหรับผู้เริ่มต้น
  • วิธีการเชื่อมต่อตัวเข้ารหัสแบบเพิ่มหน่วยกับ Arduino
  • ไมโครคอนโทรลเลอร์ PIC สำหรับผู้เริ่มต้น
  • การควบคุมระยะไกลไมโครคอนโทรลเลอร์: IR Remote, Arduino, ESP8266, 433 ...
  • การวัดอุณหภูมิและความชื้นบน Arduino - การเลือกวิธีการ

  •  
     
    ความคิดเห็นที่:

    # 1 wrote: Kipovets | [Cite]

     
     

    "แต่ด้วยการเพิ่มเชิงตรรกะปัญหาเกิดขึ้น - คุณไม่สามารถเปลี่ยนหน่วยเป็นศูนย์เพราะ

    0 + 0 = 1 "(c)

    การกำกับดูแลขนาดเล็ก: 0 + 0 = 0

     
    ความคิดเห็นที่:

    # 2 wrote: chugou | [Cite]

     
     

    Kipovets เขาอาจต้องการพูดว่า:

    1 + 1 = 1

     
    ความคิดเห็นที่:

    # 3 wrote: | [Cite]

     
     

    Kipovets,
    พิมพ์ผิดซ้ำ! คุณเห็นว่าผู้เชี่ยวชาญกำลังนั่งอยู่บนพอร์ทัลของเราดีแค่ไหน! คุณต้องสร้างเนื้อหาที่เหมาะสมเท่านั้น!

     
    ความคิดเห็นที่:

    # 4 เขียนว่า: Serg | [Cite]

     
     

    ในส่วนสุดท้ายมันบอกว่า PORTB | = 1 << 5 ... ถ้า (digitalRead (12) == 1) แต่พอร์ต 5 B คือ 13 อาร์ดิโน่ หรือฉันเข้าใจผิด?!

     
    ความคิดเห็นที่:

    # 5 เขียนว่า: P-a-H-A | [Cite]

     
     

    หาก (PINB == B00010000) {} ไม่ใช่คล้ายกับถ้าเราเขียนว่า (digitalRead (12) == 1)
    อะนาล็อกค่อนข้าง
    (digitalRead (12) == 1) &&(digitalRead (13) == 1) &&(digitalRead (14) == 1) &&(digitalRead (15) == 1) &&(digitalRead (11) == 1) ... และอื่น ๆ 8 พินพอร์ต

    ที่นี่คุณต้องการสิ่งนี้:
    ถ้า (
    ! (~ PORTB & (1 << PB4))) {} //ผลตอบแทน0 หรือ 1
    อย่างนี้:
    ถ้า (PORTB & (1 << PB4)) {} // ส่งคืนหน่วย shifted = 16, DEC
    อย่างนี้:
    ถ้า (
    bit_is_set (PORTB, 4)) {}// ส่งคืนหน่วย shifted = 16, DEC