//https://www.etechnophiles.com/tachometer-using-arduino/
//GPIO ทุกขาสามารถใช้คำสั่ง Interrupt ได้ ยกเว้นขา GPIO16
การเชื่อมต่อLCD1602 I2C บอร์ด ESP8266
I2C module ESP8266
VCC ------> 5V
GND ------> Ground
SDA ------> D2 GPIO 4
SCL ------> D1 GPIO 5
ติดตั้งไลบรารี LiquidCrystal ให้ไปที่ Arduino IDE:
ไปที่เมนู Sketch > Include Library > Manage Libraries...
ติดตั้งไลบรารี LiquidCrystal ให้ไปที่ Arduino IDE:
ไปที่เมนู Sketch > Include Library > Manage Libraries...
ค้นหา LiquidCrystal I2C และติดตั้ง
การเชื่อมต่อ บอร์ด ESP8266 กับ IR sensor
GND ------> GND
3.3V ------> VCC
D8 ------> OUT
เขียนโปรแกรมเพื่อสั่งให้จอ LCD แสดงผล
และทดสอบการทำงาน
// Code Detect Object From IR
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
int ir_pin =15; //D8
int ir_val;
void setup(){
// initialize LCD
lcd.init();
lcd.backlight();
Serial.begin(115200);
}
void loop(){
// set cursor to first column, first row
lcd.setCursor(0, 0);
lcd.print("IR Value:");
lcd.print(ir_val);
delay(1000);
lcd.clear();
ir_val = digitalRead(ir_pin);//อ่านค่าสัญญาณ digital ขา D1 ที่ต่อกับ เซ็นเซอร์ตรวจจับวัตถุ IR Infrared
if (ir_val>0){
Serial.print("No Detect VaLue:");
Serial.println(ir_val);
} else{
Serial.print("Detect Value:");
Serial.println(ir_val);
}
}
// END Code Detect Object From IR
///////////////////////////////////////
การเขียนโปรแกรม การวัดรอบของใบพัด
รูปแบบคำสั่ง attachInterrupt(digitalPinToInterrupt(ir_sensor), IRinterrupt, FALLING);
digitalPinToInterrupt(ir_sensor) คือลำดับขาอินเตอร์รัพท์ตามที่ได้ดูไปในตารางที่ผ่านมา ใน Arduino IDE สามารถใส่หมายเลขขาลงไปได้เลย
IRinterrupt คือชื่อฟังก์ชั่นที่จะไปถูกเรียกขึ้นมาเมื่อเกิดอินเตอร์รัพท์
mode รูปแบบที่จะให้เกิดอินเตอร์รัพท์ มีทั้งหมด 4 รูปแบบดังนี้
LOW จะเกิดอินเตอร์รัพท์ต่อเมื่อพอร์ตที่กำหนดไว้มีสถานะเป็น LOW
CHANGE จะเกิดอินเตอร์รัพท์เมื่อพอร์ตที่กำหนดไว้มีการเปลี่ยนสถานะ เช่น จากสถานะ HIGH เป็น LOW หรือจาก LOW เป็น HIGH
RISING จะเกิดอินเตอร์รัพท์เมื่อพอร์ตที่กำหนดไว้มีการเปลี่ยนสถานะจาก LOW เป็น HIGH
FALLING จะเกิดอินเตอร์รัพท์เมื่อพอร์ตที่กำหนดไว้มีการเปลี่ยนสถานะจาก HIGH เป็น LOW
HIGH จะเกิดอินเตอร์รัพท์ต่อเมื่อพอร์ตที่กำหนดไว้มีสถานะเป็น HIGH
ทำไมต้องใช้ ICACHE_RAM_ATTR?
ICACHE_RAM_ATTR ทำหน้าที่บังคับให้ตัวแปร counter ถูกจัดเก็บไว้ในส่วนของ RAM ที่เรียกว่า I-Cache (Instruction Cache)
ซึ่งเป็นส่วนหนึ่งของ RAM ที่ใช้เก็บคำสั่งของโปรแกรม โดยการจัดเก็บตัวแปรไว้ใน I-Cache จะทำให้การเข้าถึงตัวแปรนั้น เร็วขึ้น
เพราะไมโครคอนโทรลเลอร์สามารถเข้าถึงข้อมูลใน I-Cache ได้โดยตรงโดยไม่ต้องผ่านขั้นตอนการเข้าถึง RAM ทั่วไป
Attribute นี้มักจะใช้กับไมโครคอนโทรลเลอร์ ที่ใช้ชิป ESP8266 หรือ ESP32 และอาจมีการใช้งานที่แตกต่างกันไปในไมโครคอนโทรลเลอร์รุ่นอื่นๆ
คุณสมบัติ ICACHE_RAM_ATTR volatile
วัตถุประสงค์ เพิ่มความเร็วในการเข้าถึง ป้องกันการเพิ่มประสิทธิภาพที่ผิดพลาด
ผลกระทบต่อการจัดเก็บ บังคับให้เก็บใน I-Cache ไม่ได้ระบุตำแหน่งการจัดเก็บ
เหตุผลในการใช้ ตัวแปรที่ใช้บ่อย,สำคัญ ตัวแปรที่ใช้ในการสื่อสารกับฮาร์ดแวร์
unsigned int: นี่คือชนิดข้อมูลของตัวแปร counter ซึ่งหมายถึงตัวแปรนี้จะเก็บค่าจำนวนเต็มบวกเท่านั้น (ไม่มีเครื่องหมายลบ)
และมีขนาดที่ขึ้นอยู่กับสถาปัตยกรรมของระบบ (โดยทั่วไปจะใช้ 2 หรือ 4 ไบต์)
counter: นี่คือชื่อของตัวแปรที่ใช้เก็บค่าจำนวนเต็มบวก
unsigned long currentMillis = millis();
ฟังก์ชัน millis() คืออะไร?
millis() เป็นฟังก์ชันที่พบได้บ่อยในภาษาโปรแกรมที่เกี่ยวข้องกับไมโครคอนโทรลเลอร์ เช่น Arduino โดยฟังก์ชันนี้จะคืนค่าเวลาที่ผ่านไป
นับตั้งแต่เริ่มต้นโปรแกรมทำงานเป็นหน่วยมิลลิวินาที (milliseconds) หรือ 1/1000 ของหนึ่งวินาที
การวัดเวลา: ใช้ในการวัดระยะเวลาที่ผ่านไป เพื่อควบคุมการทำงานของโปรแกรมให้เกิดขึ้นในช่วงเวลาที่กำหนด เช่น การกระพริบ LED ในช่วงเวลาที่แน่นอน
การอ่านค่าเซ็นเซอร์ในช่วงเวลาที่กำหนด เป็นต้น
การสร้างการหน่วงเวลา: แม้ว่าจะมีฟังก์ชัน delay() ที่ใช้ในการหน่วงเวลา แต่ฟังก์ชัน millis() จะให้ความยืดหยุ่นมากกว่าในการสร้างการหน่วงเวลา
ที่ซับซ้อนหรือการทำงานหลายอย่างพร้อมกัน
การควบคุมการทำงานแบบไม่บล็อก (Non-blocking): เมื่อใช้ millis() ร่วมกับโครงสร้างการควบคุม เช่น if-else หรือ switch-case
จะทำให้โปรแกรมสามารถทำสิ่งอื่นๆ ได้ในขณะที่รอให้เวลาผ่านไป ไม่เหมือนกับการใช้ delay() ที่จะทำให้โปรแกรมหยุดทำงานชั่วคราว
// Full code IR LCD1602 RPM
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
int ir_pin =15; //D8
int ir_val;
int PPR=3; // Pulse per rotation
unsigned long previousMillis = 0; // Variable to store previous time
unsigned int rpm = 0; // Variable to store RPM value
ICACHE_RAM_ATTR int counter=0;
void ICACHE_RAM_ATTR IRinterrupt(){
counter++;
}
void setup(){
// initialize LCD
lcd.init();
lcd.backlight();
attachInterrupt(digitalPinToInterrupt(ir_pin), IRinterrupt, FALLING);
Serial.begin(9600);
}
void loop()
{
unsigned long currentMillis = millis();
//จับเวลา 1 วินาที ถ้าครบ ก็หยุดการทำงานของ ตัวนับ counter
if (currentMillis - previousMillis >= 1000) {
detachInterrupt(digitalPinToInterrupt(ir_pin));
rpm = (counter / PPR) * 60; // Calculate RPM perminute
counter = 0;
attachInterrupt(digitalPinToInterrupt(ir_pin), IRinterrupt, FALLING);
previousMillis = currentMillis;
lcd.clear();
lcd.setCursor(0,0);
lcd.print("RPM=");
lcd.print(rpm);
Serial.println(rpm);
delay(100);
}
}
Ref:
https://randomnerdtutorials.com/interrupts-timers-esp8266-arduino-ide-nodemcu/
https://www.allnewstep.com/article/61/nodemcu-esp8266-esp8285-arduino-32-esp8266-nodemcu-interrupt
ความคิดเห็น
แสดงความคิดเห็น