ARDUINO "Hack pinMode"
ARDUINO “แกะฟังก์ชัน pinMode”
ประจิน
พลังสันติกุล
เกิดอะไรขึ้นเมื่อเราเรียกใช้งานคำสั่ง
pinMode() ก่อนอื่นเรามาดูฟังก์ชัน pinMode() กันก่อนครับ คำสั่ง pinMode จะอยู่ในโฟลเดอร์ “C:\Program Files
(x86)\Arduino\hardware\arduino\avr\cores\arduino” ไฟล์ wiring_digital.c
void pinMode(uint8_t pin, uint8_t mode)
{
uint8_t bit =
digitalPinToBitMask(pin);
uint8_t port =
digitalPinToPort(pin);
volatile uint8_t
*reg, *out;
if (port ==
NOT_A_PIN) return;
// JWS: can I
let the optimizer do this?
reg = portModeRegister(port);
out =
portOutputRegister(port);
if (mode ==
INPUT) {
uint8_t
oldSREG = SREG;
cli();
*reg
&= ~bit;
*out
&= ~bit;
SREG
= oldSREG;
} else if (mode ==
INPUT_PULLUP) {
uint8_t
oldSREG = SREG;
cli();
*reg
&= ~bit;
*out
|= bit;
SREG
= oldSREG;
} else {
uint8_t
oldSREG = SREG;
cli();
*reg
|= bit;
SREG
= oldSREG;
}
}
|
** อ้างอิงกับบอร์ด ARDUINO UNO
เมื่อเราเรียกใช้งานฟังก์ชัน pinMode(pin, mode) ดังนี้
void setup()
{
pinMode(13, OUTPUT);
}
สิ่งที่เกิดขึ้นคือ
ค่า 13
จะถูกกำหนดไปที่พารามิเตอร์(อาร์กิวเมนต์)
pin
OUTPUT จะถูกกำหนดไปที่พารามิเตอร์(อาร์กิวเมนต์)
mode
และเข้าสู่การทำงานของฟังก์ชัน
pinMode() โดยมีลำดับขั้นตอนการทำงานดังนี้
เรียกใช้งานฟังก์ชัน
digitalPinToBitMask()
bit = digitalPinToBitMask(13); ผลที่เกิดขึ้นคือ
bit = _BV(5);
bit = (1<<(5));
เรียกใช้งานฟังก์ชัน
digitalPinToPort(pin)
port =
digitalPinToPort(13); ผลที่เกิดขึ้นคือ
port = PB;
สรุปแล้ว 2
คำสั่งฟังก์ชัน ที่ผ่านมาคือ PB5 ครับ ซึ่งก็คือขาที่
19 ของ ATmega328P
ส่วนคำสั่งนี้จะถูกข้ามไปครับ
if (port == NOT_A_PIN) return;
เพราะ port
ของเราเท่ากับ
PB
เรียกใช้งานฟังก์ชัน
reg = portModeRegister(port);
reg =
portModeRegister(PB); ผลที่เกิดขึ้น
reg = (uint16_t) &DDRB;
*** ถ้าได้ศึกษา AVR
จะทราบดีว่า
DDRB เป็นรีจิสเตอร์ที่ใช้กำหนดทิศทางการทำงานของขาพอร์ต
ว่าจะให้เป็นอินพุต (กำหนดค่า 0) หรือเป็นเอาต์พุต (กำหนดค่า 1) ของพอร์ต PORTB
เรียกใช้งานฟังก์ชัน
out = portOutputRegister(port);
out =
portOutputRegister(PB); ผลที่เกิดขึ้น
out =
(uint16_t) &PORTB;
*** PORTB เป็นรีจิสเตอร์ที่ใช้ในการอินพุตหรือเอาตพุต
(รีจิสเตอร์ตัวนี้มีผลเกี่ยวข้องกับรีจิสเตอร์อีก 1 ตัว
ไม่ขอกล่าวในที่นี้)
เนื่องจากเรากำหนดให้
mode เป็น OUTPUT คำสั่งที่ทำงานต่อคือ
uint8_t
oldSREG = SREG; // เก็บค่า SREG
ไว้
cli(); //
ปิดการทำงานของอินเตอรรัปต์ทั้งหมด
*reg
|= bit; //
DDRB |= (1<<(5));
*** เรารู้มาแล้วว่า
*reg ชี้ไปที่ DDRB จากนั้นกำหนดค่า bit ซึ่งเท่ากับ (1<<(5)) ด้วยโอเปอร์เรเตอร์
|= (OR compound
assignment) ส่งผลให้รีจิสเตอร์ DDRB บิตที่
5 เป็น
‘1’ หรือเอาต์พุต โดยไม่ไปยุ่งกับบิตอื่น
ๆ
SREG =
oldSREG; //
คืนค่า
SREG กลับ
ความคิดเห็น
แสดงความคิดเห็น