ผู้เขียน หัวข้อ: การเรียนรู้ครั้งที่ 5 [Basic ESP32] การใช้งานพอร์ตดิจิทัลอินพุทและอินเตอร์รัพท์  (อ่าน 6237 ครั้ง)

admin

  • Administrator
  • Hero Member
  • *****
  • กระทู้: 706
    • ดูรายละเอียด
    • อีเมล์
การใช้งานพอร์ตในโหมดดิจิทัลอินพุทและการใช้งานอินเตอร์รัพท์บื้องต้น
   ขาพอร์ตของ ESP32 ทุกขาสามารถใช้งานเป็นอินพุทพอร์ตได้และทุกขาก็สามารถใช้งานในส่วนอินเตอร์รัพท์แบบภายนอกได้ การเขียนโปรแกรมรับค่าเข้ามาเพื่อประมวลผลสามารถทำได้ 2 แนวทางคือ
   1. แบบ Polling เป็นการเขียนโปรแกรมแบบวนตรวจสอบลอจิกที่ขาพอร์ต การเขียนโปรแกรมลักษณะนี้จะอ่านค่าจากขาพอร์ตด้วยฟังก์ชั่น digitalRead
   2. แบบ Interrupt เป็นการเขียนโปรแกรมที่เปิดให้ยอมรับการรับสัญญาณการขัดจังหวะจากภายนอกได้

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

(a) การใช้งานตัวต้านทานพูลอัพภายนอก ใช้ฟังก์ชั่น pinMode(pin,INPUT);
(b) การใช้งานตัวต้านทานพูลอัพภายใน ใช้ฟังก์ชั่น pinMode(pin,INPUT_PULLUP);
หมายเหตุ ขาพอร์ต GPIO34,35,36,39 ต้องใช้ตัวต้านทานพูลอัพภายนอกเท่านั้น

วิธีการใช้งานพอร์ตดิจิทัลอินพุท
  เป็นการใช้งานพอร์ตที่ต้องวนอ่านสถานะลอจิกที่ขาพอร์ต การใช้งานพอร์ตให้ทำงานเป็นอินพุทพอร์ตมี 2 ฟังก์ชั่นที่เกี่ยวข้องคือ
1. ฟังก์ชั่นกำหนดโหมดให้เป็นอินพุทพอร์ต โดยจะวางฟังก์ชั่นนี้ไว้ใน void setup() ตัวอย่างฟังก์ชั่นใช้งานได้แก่
     pinMode(pin,INPUT)   ;     // กำหนดขาพอร์ตให้ทำงานเป็นอินพุทพอร์ตแบบไม่ใช้ตัวต้านทานพูลอัพภายใน
     pinMode(pin,INPUT_PULLUP)   ;   // กำหนดขาพอร์ตให้ทำงานเป็นอินพุทพอร์ตแบบใช้ตัวต้านทานพูลอัพภายใน
2. ฟังก์ชั่นอ่านค่าสถานะลอจิกที่ขาพอร์ต ซึ่งฟังชั่นนี้จะส่งค่ากลับมา 2 ค่าคือ HIGH,LOW  การจะใช้งานฟังก์ชั่นนี้ได้จะต้องใช้ฟังก์ชั่นกำหนดโหมดขาให้เป็นอินพุทก่อน ตัวอย่างฟังก์ชั่นใช้งานได้แก่
     bool status=digitalRead(pin)   ;     // เป็นฟังก์ชั่นการอ่านสถานะที่ขา pin มาไว้ในตัวแปลชื่อว่า status ซึ่งประกาศเป็นตัวแปรชนิด boolean ไว้

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


หากไมโครคอนโทรลเลอร์ทำงานด้วยความเร็วสูงมากจะเข้าใจว่ามีการกดหลายครั้ง การแก้ไขสามารถทำได้ 2 วิธีการคือ
1. แก้ด้วยซอฟต์แวร์ โดยหน่วงเวลาให้พ้นช่วงสัญญาณเบาส์แล้วอ่านใหม่หากยังเป็นลอจิกเดิมแสดงว่าเป็นการกดสวิตช์
2. แก้ด้วยฮาร์ดแวร์ โดยใช้ตัวเก็บประจุคร่อมสวิตช์เพื่อให้สัญญาณเบาส์หายไปดังรูป


วิธีการใช้งานการอินเตอร์รัพท์ภายนอก
   เป็นวิธีการรู้สถานะของขาพอร์ตโดยไม่ต้องวนอ่านสถานะ เพียงแต่ต้องกำหนดให้ไมโครคอนโทรลเลอร์เปิดระบบให้ยอมรับการอินเตอร์รัพท์ได้ โดยฟังก์ชั่นการเปิดการยอมรับการอินเตอร์รัพท์นี้จะวางไว้ใน void setup() ฟังก์ชั่นนี้คือ
attachInterrupt(pin, ISR, mode);
    pin: หมายเลขขาพอร์ตที่ต้องการรับสัญญาณอินเตอรรัพท์
    ISR: ชื่อฟังก์ชั่นรองที่ใช้ตอบสนองการอินเตอร์รัพท์
    mode: เป็นการกำหนดลักษณะของสัญญาณที่ใช้กระตุ้นการอินเตอร์รัพท์
        ->LOW เมื่อขาเป็นลอจิกศูนย์
        ->CHANGE เมื่อขามีการเปลี่ยนระดับลอจิก 1->0, 0->1
        ->RISING เมื่อขามีการเปลี่ยนระดับลอจิกจาก 0 ไปเป็น 1
        ->FALLING เมื่อขามีการเปลี่ยนระดับลอจิกจาก 1 ไปเป็น 0
รูปแบบของสัญญาณอินเตอร์รัพท์ที่ตอบสนองเป็นดังรูป


ขาพอร์ตที่มีให้ใช้งาน
« แก้ไขครั้งสุดท้าย: มกราคม 27, 2019, 03:18:03 PM โดย admin »

admin

  • Administrator
  • Hero Member
  • *****
  • กระทู้: 706
    • ดูรายละเอียด
    • อีเมล์
Re: ....
« ตอบกลับ #1 เมื่อ: มกราคม 20, 2019, 08:22:31 PM »

ฟังก์ชั่นที่ใช้งานในการทดลองนี้

รูปแบบ คำอธิบาย
pinMode(pin, mode); pin: หมายเลขขาที่ต้องการเซตโหมด
mode: INPUT, OUTPUT, INPUT_PULLUP
digitalWrite(pin,value); pin: หมายเลข ขาที่ต้องการเขียนลอจิกออกพอร์ต
value: ค่าลอจิกที่ต้องการส่งออก HIGH or LOW
digitalRead(pin); pin: หมายเลขขาที่ต้องการอ่านค่าสถานะลอจิก
delay(ms); ms: ตัวเลขที่หยุดค้างของเวลาหน่วยมิลลิวินาที (unsigned long)

รูปแบบ คำอธิบาย
attachInterrupt(pin, ISR, mode); ฟังก์ชั่นเปิดการใช้งานอินเตอร์รัพท์ภายนอก
pin: หมายเลขขาพอร์ตที่ต้องการรับสัญญาณอินเตอรรัพท์
ISR: ชื่อฟังก์ชั่นรองที่ใช้ตอบสนองการอินเตอร์รัพท์
mode: เป็นการกำหนดลักษณะของสัญญาณที่ใช้กระตุ้นการอินเตอร์รัพท์
->LOW เมื่อขาเป็นลอจิกศูนย์
->CHANGE เมื่อขามีการเปลี่ยนระดับลอจิก 1->0, 0->1
->RISING เมื่อขามีการเปลี่ยนระดับลอจิกจาก 0 ไปเป็น 1
->FALLING เมื่อขามีการเปลี่ยนระดับลอจิกจาก 1 ไปเป็น 0
หมายเหตุ
   1. หมายเลข pin สามารถใช้ตัวเลข GPIO ได้โดยตรง
   2. ขาพอร์ต GPIO34, GPIO35, GPIO36, GPIO39 ใช้งานได้เฉพาะอินพุทเท่านั้น
« แก้ไขครั้งสุดท้าย: มกราคม 25, 2019, 01:34:38 PM โดย admin »

admin

  • Administrator
  • Hero Member
  • *****
  • กระทู้: 706
    • ดูรายละเอียด
    • อีเมล์
Re: ....
« ตอบกลับ #2 เมื่อ: มกราคม 20, 2019, 08:50:31 PM »
วงจรที่ใช้ทดลอง


ตัวอย่างโปรแกรม [1] วนตรวจสอบสถานะที่ขาพอร์ต
   โปรแกรมอ่านค่าสถานะของขาพอร์ตที่เชื่อมต่อกับสวิตช์กดติดปล่อยดับ แล้วแสดงสถานะที่อ่านได้แสดงผลที่ LED
โค๊ด: [Select]
#define LED1 21
#define LED2 19
#define LED3 18
#define LED4 5
#define SW1 27
#define SW2 14
#define SW3 12
#define SW4 13
void setup(){
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(LED4, OUTPUT);
  pinMode(SW1, INPUT_PULLUP);
  pinMode(SW2, INPUT_PULLUP);
  pinMode(SW3, INPUT_PULLUP);
  pinMode(SW4, INPUT_PULLUP);
}
void loop(){
  digitalWrite(LED1, digitalRead(SW1));
  digitalWrite(LED2, digitalRead(SW2));
  digitalWrite(LED3, digitalRead(SW3));
  digitalWrite(LED4, digitalRead(SW4));
  delay(50);
}
ตัวอย่างโปรแกรม [2] ใช้การอินเตอร์รัพท์
   โปรแกรมทดสอบการใช้งานการอินเตอร์รัพท์ภายนอก โดยรับจากสวิตช์ที่ต่อไว้ที่ขา GPIO27
โค๊ด: [Select]
struct Button {
  const uint8_t PIN;
  uint32_t numberKeyPresses;
  volatile bool pressed;
};
Button SW = {27, 0, false};
void IRAM_ATTR isr() {
  SW.pressed = true;
}
void setup() {
  pinMode(SW.PIN, INPUT_PULLUP);
  attachInterrupt(SW.PIN, isr, FALLING);
  Serial.begin(9600);
}
void loop() {
  for (byte i = 0; i < 20; i++) {
    Serial.print(".");
    delay(100);
    if (SW.pressed) {
      SW.numberKeyPresses += 1;
      Serial.printf("\nSwitch has been pressed %u times\n", SW.numberKeyPresses);
      SW.pressed  = false;
      return;
    }
  }
  Serial.println();
}
« แก้ไขครั้งสุดท้าย: มกราคม 25, 2019, 02:15:31 PM โดย admin »

admin

  • Administrator
  • Hero Member
  • *****
  • กระทู้: 706
    • ดูรายละเอียด
    • อีเมล์

admin

  • Administrator
  • Hero Member
  • *****
  • กระทู้: 706
    • ดูรายละเอียด
    • อีเมล์