GPIO ภาษาแอสเซมบลี (Assembly) กับ Arduino Uno

GPIO (General Purpose Input / Output) คืออินเทอร์เฟซที่ควบคุมด้วยซอฟต์แวร์ซึ่งมักพบในไมโครคอนโทรลเลอร์และไมโครโปรเซสเซอร์ ICs หรือชิปเซ็ตอินเทอร์เฟซบางตัว โดยทั่วไปแล้ว GPIO จะเป็นขาหนึ่งตัวขึ้นไปบน IC ซึ่งไม่มีจุดประสงค์พิเศษในตัวมันเอง แต่ช่วยอำนวยความสะดวกให้กับนักออกแบบอุปกรณ์ในการสร้างอินเทอร์เฟซ / การเชื่อมต่อระหว่าง IC และส่วนประกอบอุปกรณ์ต่อพ่วงโดยการเขียนโปรแกรมการลงทะเบียนฮาร์ดแวร์บางตัว ด้วยเหตุนี้ภายในข้อ จำกัด ขา GPIO สามารถปรับแต่งเพื่อใช้เพื่อให้มีฟังก์ชันหรือวัตถุประสงค์เฉพาะบางอย่างภายในการออกแบบอุปกรณ์ฮาร์ดแวร์

ในบทความนี้เราจะเห็นเทคนิคการเขียนโปรแกรม ภาษาแอสเซมบลี (Assembly) เพื่อตั้งค่า GPIO เป็น Digital แบบ Input และ Output โดยจะครอบคลุมโหมดทั้งหมดที่สามารถตั้งค่า GPIO ได้และเราจะเห็นการใช้งานจริงสำหรับแต่ละโหมด

  • Output – Push Pull
  • Input
    • Internal Pull Up
    • External Pull Up
    • External Pull Down


GPIO เป็นเอาต์พุต – Push Pull


โปรแกรมแรกของระบบสมองกลฝังตัวมักจะเป็นโปรแกรมกะพริบ เริ่มต้นด้วย LED ใน บอร์ด Arduino Uno ภาษา Assembly ที่เราเคยทดสอบมา สิ่งนี้จะทำให้เริ่มต้นได้ง่ายเนื่องจากไม่ต้องใช้ฮาร์ดแวร์เพิ่มเติม


DDxn bit ใน DDRx Register จะเลือกทิศทางของขานี้ ถ้า DDxn เขียนลอจิกเป็น 1 จะมีการกำหนดค่า pxn เป็นขาเอาต์พุต ถ้า DDxn เขียนลอจิกเป็น 0 จะกำหนดค่า pxn เป็นขาอินพุต

ถ้า PORTxn ถูกเขียนลอจิกเมื่อกำหนดค่าขาเป็นขาเอาต์พุต ขาพอร์ตจะถูกขับเคลื่อนให้เป็น HIGH (1) ถ้า PORTxn เขียนลอจิกเป็น 0 เมื่อกำหนดค่าขาเป็นขาเอาต์พุตขาพอร์ตจะถูกขับเคลื่อนให้เป็น LOW (0)

เรามีพอร์ต 3 พอร์ตในไมโครคอนโทรลเลอร์ Atmega328P คือ พอร์ต B [PB], พอร์ต C [PC], พอร์ต D [PD]


จริงๆแล้ว พอร์ต B มี 8 ขา คือขา PB0 ถึง PB7 แต่ในการทำงานของบอร์ด Arduino UNO ขาของ PB6 และ PB7 ใช้สำหรับ Crystal Oscillator คือ PB6 หรือที่เป็นขาตัวเลข 9 เป็น XTAL1 และ PB7 หรือที่เป็นขาตัวเลข 10 เป็น XTAL2 ดังนั้นจึงไม่สามารถใช้ได้ เราจึงเหลือ 6 ขา ในการใช้งานเป็น GPIO คือ PB0 ถึง PB5


พอร์ต C มี 7 ขา คือขา PC0 ถึง PC6 แต่ในการใช้งานของบอร์ด Arduino UNO นั้น ขา PC6 หรือที่เป็นขาตัวเลข 1 จะใช้สำหรับ ~ RESET (ขารีเซ็ต) เราจึงสามารถใช้ได้เพียง 6 ขา ที่ เป็น GPIO คือ PC0 ถึง PC5

พอร์ต D มี 8 ขา คือ PD0 ถึง PD7 ในการใช้งานของบอร์ด Arduino UNO เราสามารถใช้ขาทั้ง 8 เป็น GPIO ได้อย่างมีประสิทธิภาพ

ให้เราดูแผนผังของการใช้งานแบบบอร์ด Arduino UNO และดูว่าความสามารถการใช้งานของขาต่างๆ

Arduino UNO Schematics Port Pin Mapping
Atmega328p Pin Mapping with Arduino UNO Board


1: การเขียนโปรแกรม ภาษา Assembly กำหนดค่าเป็นเอาต์พุต



ตัวอย่างที่ 1: การกำหนดค่าขา PB0 ถึง PB5 ของพอร์ต B ของ Atmega328P ให้เป็นเอาต์พุตทั้งหมด

ldi r24, 0x3F ; // Load Immediate to Register r24 [ 1 CPU Cycle ]
out 0x04, r24 ; // Store Register to I/O Location 0x04 [ 1 CPU Cycle ] 




ตัวอย่างที่ 2: การกำหนดค่า PB4 ขาเดียวให้เป็นเอาต์พุตโดยไม่ทำให้ขาอื่นๆเปลี่ยนแปลง

sbi 0x04, 4 ; // Set Bit in I/O Register 0x04 [ 2 CPU Cycle ] 



ตัวอย่างที่ 3: การกำหนดค่าขาหลายๆขาเช่น PB2, PB3, PB4 เป็นเอาต์พุต

in r24, 0x04 ; //  Load an I/O Location to Register r24 [ 1 CPU Cycle ]
ori r24, 0x1C ; // Logical OR r24 with Immediate value 0x1C [ 1 CPU Cycle ] 
out 0x04, r24 ; // Store Register r24 to I/O Location 0x04 [ 1 CPU Cycle ] 


2: การเขียนโปรแกรม ภาษา Assembly ขับเคลื่อนผลลัพธ์

ตัวอย่างที่ 1: การกำหนดขาของพอร์ต B ทั้งหมด คือขา PB0 ถึง PB5 ของ Atmega328P ให้เป็น HIGH

ldi r24, 0x3F ; // Load Immediate to Register r24 [ 1 CPU Cycle ] out 0x05, r24 ; // Store Register to I/O Location 0x04 [ 1 CPU Cycle ] 



ตัวอย่างที่ 2: การกำหนดขา PB4 ขาเดียวให้เป็น HIGH โดยที่ขาอื่นๆไม่เปลี่ยนแปลง

sbi 0x05, 4 ; // Set Bit in I/O Register 0x05 [ 2 CPU Cycle ] 



ตัวอย่างที่ 3: การกำหนดหลายๆขา เช่น PB2, PB3, PB4 ให้เป็น HIGH

in r24, 0x05 ; //  Load an I/O Location to Register r24 [ 1 CPU Cycle ]
ori r24, 0x1C ; // Logical OR r24 with Immediate value 0x1C [ 1 CPU Cycle ] 
out 0x05, r24 ; // Store Register r24 to I/O Location 0x05 [ 1 CPU Cycle ] 



ตัวอย่างที่ 4: การกำหนดหลายๆขา เช่น PB1, PB2, PB5 ให้เป็น LOW

in r24, 0x05 ; //  Load an I/O Location to Register r24 [ 1 CPU Cycle ]
andi r24, 0xD9 ; // Logical AND r24 with Immediate value 0xD9 [ 1 CPU Cycle ] 
out 0x05, r24 ; // Store Register r24 to I/O Location 0x05 [ 1 CPU Cycle ]



ตัวอย่างที่ 5: การกำหนดขา PB5 ขาเดียวให้เป็น LOW โดยไม่ทำให้ขาอื่นๆเปลี่ยนแปลง

cbi 0x05, 5 ; // Clear Bit in I/O Register 0x05 [ 2 CPU Cycle ] 


3: การเขียนโปรแกรม ภาษา Assembly Binky LED


โค้ดตัวอย่างเป็นการทำให้ LED ที่อยู่เชื่อมต่ออยู่ที่ ขา PB5 ของ ATmega328P กระพริบได้ ด้วยการหน่วงเวลา หรือเว้นระยะ จะใช้วิธีที่เรียกว่า Software Delay Loop


main:
    sbi 0x04, 5       ; PORTB5 output
  loop:               ; main loop begin
    sbi 0x05, 5       ; PORTB5 high
    call delay_1000ms ; delay 1s
    cbi 0x05, 5       ; 5 PORTB5 low
    call delay_1000ms ; delay 1s
    rjmp  loop        ; main loop
  delay_1000ms:       ; subroutine for 1s delay
                      ; initialize counters
    ldi r18, 0xFF     ; 255
    ldi r24, 0xD3     ; 211
    ldi r25, 0x30     ; 48
  inner_loop:
    subi  r18, 0x01   ; 1
    sbci  r24, 0x00   ; 0
    sbci  r25, 0x00   ; 0
    brne  inner_loop
    ret


GPIO as Input – Internal Pull Up


ถ้า DDxn เขียนลอจิกเป็น 0 จะกำหนดค่า pxn เป็นขาอินพุต

ถ้า PORTxn ถูกเขียนลอจิกเมื่อกำหนดค่าขาเป็นพินอินพุตตัวต้านทานแบบ Pull Up จะเปิดใช้งาน ในการปิดตัวต้านทานแบบ Pull Up นั้น PORTxn จะต้องเขียนลอจิกเป็น 0 หรือต้องกำหนดค่าขาเป็นขาเอาต์พุต port pins are tri-stated when reset จะใช้งานได้แม้ว่าจะไม่มีนาฬิกาทำงานอยู่ก็ตาม


4: การเขียนโปรแกรม ภาษา Assembly กำหนดค่าเป็นอินพุต


ตัวอย่างที่ 1: การกำหนดค่าขาทั้งหมดของพอร์ต B คือ ขา PB0 ถึง PB5 ของ ATmega328P เป็นอินพุต

ldi r24, 0xC0 ; // Load Immediate to Register r24 [ 1 CPU Cycle ]
out 0x04, r24 ; // Store Register to I/O Location 0x04 [ 1 CPU Cycle ] 



ตัวอย่างที่ 2: การกำหนดค่า PB4 ขาเดียวให้เป็นอินพุต โดยไม่ทำให้ขาอื่นๆเปลี่ยนแปลง

cbi 0x04, 4 ; // Clear Bit in I/O Register 0x04 [ 2 CPU Cycle ] 



ตัวอย่างที่ 3: การกำหนดค่าหลายๆขา เช่นขา PB2, PB3, PB4 ให้เป็นอินพุต

in r24, 0x04 ; //  Load an I/O Location to Register r24 [ 1 CPU Cycle ]
andi r24, 0xE3 ; // Logical AND r24 with Immediate value 0xE3 [ 1 CPU Cycle ]
out 0x04, r24 ; // Store Register r24 to I/O Location 0x04 [ 1 CPU Cycle ]


5: การเขียนโปรแกรม ภาษา Assembly เปิดใช้งาน Pull Up ภายใน


ตัวอย่างที่ 1: การเปิดใช้งาน Internal Pull Up ขาที่ใช้งานทั้งหมดของพอร์ต B คือขา PB0 ถึง PB5

ldi r24, 0xC0 ; // Load Immediate to Register r24 [ 1 CPU Cycle ]
out 0x05, r24 ; // Store Register to I/O Location 0x05 [ 1 CPU Cycle ] 


ตัวอย่างที่ 2: การเปิดใช้งาน Internal Pull Up ขา PB4 ขาเดียว

sbi 0x05, 4 ; // Set Bit in I/O Register 0x05 [ 2 CPU Cycle ] 


6: การเขียนโปรแกรม ภาษา Assembly จับอินพุต


ตัวอย่างที่ 1: การจับอินพุตของขาทั้งหมดของพอร์ต B คือขา PB0 ถึง PB5

in r24, 0x03 ; // Store I/O Location to Register r24 [ 1 CPU Cycle ]

Leave a Reply

Your email address will not be published. Required fields are marked *

เราใช้คุกกี้เพื่อพัฒนาประสิทธิภาพ และประสบการณ์ที่ดีในการใช้เว็บไซต์ของคุณ คุณสามารถศึกษารายละเอียดได้ที่ นโยบายความเป็นส่วนตัว และสามารถจัดการความเป็นส่วนตัวเองได้ของคุณได้เองโดยคลิกที่ ตั้งค่า

Privacy Preferences

คุณสามารถเลือกการตั้งค่าคุกกี้โดยเปิด/ปิด คุกกี้ในแต่ละประเภทได้ตามความต้องการ ยกเว้น คุกกี้ที่จำเป็น

Allow All
Manage Consent Preferences
  • Always Active

Save