- Details
- Written by Super User
- Category: Microcontroller & Microprocessor
- Hits: 152
ESP32 Universal Controller
- Details
- Written by Super User
- Category: Microcontroller & Microprocessor
- Hits: 412
แนะนำเรื่องการใช้ I2C สำหรับ Arduino, ESP32 และ Micro Python
ความสัมพันธ์ :
I2C เป็นโปรโตคอลการสื่อสารที่ถูกออกแบบมาเพื่อใช้ในการเชื่อมต่ออุปกรณ์อิเล็กทรอนิกส์ในระบบแบบแปลงข้อมูลแบบมาสเตอร์-สแลฟ (Master-Slave) ซึ่งหมายความว่ามีอุปกรณ์หลัก (Master) และอุปกรณ์ย่อย (Slave) ที่เชื่อมต่อกันผ่านสาย SDA และ SCL.
- Master (ผู้ควบคุมหลัก): อุปกรณ์หลักใช้ในการส่งคำสั่งและข้อมูลไปยังอุปกรณ์ย่อย (Slave) โดยอาศัย I2C address ของแต่ละอุปกรณ์. Master กำหนดความเร็วในการสื่อสาร (บางครั้งเรียกว่า Baud rate) และควบคุมการสื่อสารโดยรวมในเครือข่าย I2C.
- Slave (ผู้ควบคุมย่อย): อุปกรณ์ย่อยรอรับคำสั่งและข้อมูลจาก Master โดยอ้างอิงถึง I2C address ของตัวเอง. Slave จะตอบสนองกับคำสั่งของ Master และส่งข้อมูลกลับหา Master ตามที่ได้รับคำสั่ง.
ความจำเป็น :
การใช้งาน I2C มีความจำเป็นในหลายสถานการณ์ เช่น:
- การสื่อสารกับอุปกรณ์นิ่ง (Peripherals): I2C มักถูกใช้ในการสื่อสารกับอุปกรณ์เซ็นเซอร์และโมดูลต่าง ๆ ที่อยู่ในระบบภายนอก เช่น อุปกรณ์เก็บข้อมูลแบบ EEPROM, อุปกรณ์เรนเดอร์แสดงผล OLED, หรือเซ็นเซอร์อุณหภูมิ.
- การเชื่อมต่อหลายอุปกรณ์: I2C ช่วยให้คุณสามารถเชื่อมต่อหลายอุปกรณ์ไปยังไมโครคอนโทรลเลอร์เดียว โดยใช้แค่สองสายเท่านั้น นี่เป็นประโยชน์ในโปรเจกต์ที่มีหลายอุปกรณ์ที่ต้องการการสื่อสาร.
- ประหยัดพื้นที่: I2C เป็นโปรโตคอลที่ใช้เส้นสายน้อยกว่า การสื่อสารแบบอื่น ๆ เช่น SPI (Serial Peripheral Interface) หรือ UART (Universal Asynchronous Receiver-Transmitter) ซึ่งทำให้เหมาะสำหรับโปรเจกต์ที่มีพื้นที่จำกัด.
- ความสะดวกและเร็ว: I2C มีความสะดวกในการใช้งานและมีความเร็วในการสื่อสารที่เพียงพอสำหรับส่วนใหญ่ของโปรเจกต์.
- การติดตั้งและการใช้งาน: มีไลบรารีที่มีอยู่สำหรับ I2C บนหลายไมโครคอนโทรลเลอร์ที่ทำให้ง่ายต่อการติดตั้งและการใช้งาน.
ดังนั้น I2C เป็นโปรโตคอลที่มีประโยชน์มากในการเชื่อมต่อและควบคุมอุปกรณ์อิเล็กทรอนิกส์ในโปรเจกต์ที่ต้องการการสื่อสารระหว่างไมโครคอนโทรลเลอร์และอุปกรณ์อื่น ๆ ในระบบของคุณโดยมีความสะดวกและประหยัดพื้นที่อีกด้วย.
การใช้งาน I2C (Inter-Integrated Circuit) เป็นหนึ่งในวิธีที่ดีในการเชื่อมต่ออุปกรณ์อิเล็กทรอนิกส์ต่าง ๆ กับไมโครคอนโทรลเลอร์เช่น Arduino, ESP32 และไมโครไพทอล เนื้อหาในบทความนี้จะช่วยคุณเริ่มต้นในการใช้งาน I2C เบื้องต้นสำหรับเครื่องมือเหล่านี้
1. I2C เบื้องต้น
I2C เป็นมาตรฐานสื่อสารที่ออกแบบมาเพื่อใช้ในการเชื่อมต่ออุปกรณ์อิเล็กทรอนิกส์ในระบบแบบแปลงข้อมูลแบบมาสเตอร์-สแลฟ. มันใช้สายสองเส้นสำหรับการสื่อสาร - SDA (Serial Data Line) และ SCL (Serial Clock Line). นี่คือขั้นตอนพื้นฐานในการใช้งาน I2C:
- ให้ตรวจสอบความถูกต้องของการต่อสาย SDA และ SCL ระหว่างอุปกรณ์ที่คุณต้องการเชื่อมต่อและไมโครคอนโทรลเลอร์ของคุณ (Arduino, ESP32, หรือไมโครไพทอล).
- ต้องมีข้อมูลที่แน่นอนเกี่ยวกับที่อยู่ I2C ของอุปกรณ์ (หรือที่เรียกว่า I2C address) ซึ่งต้องระบุในโค้ดของคุณ.
- คุณต้องเขียนโค้ดในไมโครคอนโทรลเลอร์เพื่อส่งข้อมูลไปยังอุปกรณ์ I2C หรือรับข้อมูลจากอุปกรณ์ I2C โดยใช้ไลบรารีหรือไลบรารีที่มีอยู่สำหรับแต่ละไมโครคอนโทรลเลอร์.
2. การใช้ I2C บน Arduino
การต่อสาย
- ใน Arduino, สาย SDA และ SCL ประกอบด้วยขา A4 และ A5 ตามลำดับ.
การเขียนโค้ด
- คุณสามารถใช้ Wire Library ใน Arduino ในการเขียนโค้ดสำหรับ I2C.
#include <Wire.h>
void setup() {
Wire.begin(); // เริ่มต้นการใช้งาน I2C
// สามารถเพิ่มการตั้งค่าอื่น ๆ ตามต้องการ
}
void loop() {
// โค้ดเชื่อมต่อกับอุปกรณ์ I2C และสื่อสารข้อมูลได้ที่นี่
}
3. การใช้ I2C บน ESP32
อ้างอิง : https://espressif-docs.readthedocs-hosted.com/projects/arduino-esp32/en/latest/api/i2c.html
การต่อสาย
- ใน ESP32, สาย SDA และ SCL ประกอบด้วยขา GPIO 21 และ GPIO 22 ตามลำดับ.
การเขียนโค้ด
- คุณสามารถใช้ไลบรารี Wire.h ใน ESP32 เช่นเดียวกับ Arduino.
#include <Wire.h>
void setup() {
Wire.begin(); // เริ่มต้นการใช้งาน I2C
// สามารถเพิ่มการตั้งค่าอื่น ๆ ตามต้องการ
}
void loop() {
// โค้ดเชื่อมต่อกับอุปกรณ์ I2C และสื่อสารข้อมูลได้ที่นี่
}
4. การใช้ I2C บน Micro Python
การต่อสาย
- การต่อสาย I2C บนไมโครไพทอลจะขึ้นอยู่กับบอร์ดคอนโทรลเลอร์ที่คุณใช้. คุณต้องทำการต่อสาย SDA และ SCL ไปยังขาที่เหมาะสมของบอร์ด.
การเขียนโค้ด
- คุณต้องใช้ไลบรารี I2C ที่เหมาะสำหรับไมโครไพทอล ที่อาจต่างกันไปตามบอร์ดและไมโครคอนโทรลเลอร์ที่คุณใช้.
นี่คือการเริ่มต้นเบื้องต้นในการใช้งาน I2C สำหรับ Arduino, ESP32, และไมโครไพทอล โปรดทราบว่าการใช้งาน I2C อาจต้องปรับแต่งตามอุปกรณ์และโครงการของคุณ. ตรวจสอบเอกสารและคู่มือที่เกี่ยวข้องของผู้ผลิตไมโครคอนโทรลเลอร์และอุปกรณ์ I2C เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับการใช้งาน I2C ในบทบาทที่คุณต้องการใช้งาน.
Code :
#include <Arduino.h>
#include <Wire.h>
// กำหนดที่อยู่ I2C สำหรับอุปกรณ์สามตัว
#define SLAVE_ADDRESS_1 8
#define SLAVE_ADDRESS_2 9
#define SLAVE_ADDRESS_3 10
void setup() {
Wire.begin(); // กำหนดค่าเริ่มต้นให้การสื่อสารผ่าน I2C
Serial.begin(9600); // กำหนดค่าเริ่มต้นให้การสื่อสารผ่านช่องทางอีกช่องหนึ่งสำหรับการดีบัค
}
void loop() {
// จัดการการสื่อสารกับแต่ละอุปกรณ์แยกกัน
handleDevice1(SLAVE_ADDRESS_1);
handleDevice2(SLAVE_ADDRESS_2);
handleDevice3(SLAVE_ADDRESS_3);
// โค้ดเพิ่มเติมสำหรับงานที่ซ้ำกัน
}
void handleDevice1(int address) {
// สื่อสารกับอุปกรณ์ 1 (ที่อยู่อาณาเขต: SLAVE_ADDRESS_1)
Wire.beginTransmission(address); // เริ่มการสื่อสารกับอุปกรณ์
// ส่งคำสั่งหรือข้อมูลที่เฉพาะกับอุปกรณ์ 1
Wire.write("คำสั่งสำหรับอุปกรณ์ 1");
Wire.endTransmission(); // สิ้นสุดการสื่อสาร
}
void handleDevice2(int address) {
// สื่อสารกับอุปกรณ์ 2 (ที่อยู่อาณาเขต: SLAVE_ADDRESS_2)
Wire.beginTransmission(address); // เริ่มการสื่อสารกับอุปกรณ์
// ส่งคำสั่งหรือข้อมูลที่เฉพาะกับอุปกรณ์ 2
Wire.write("คำสั่งสำหรับอุปกรณ์ 2");
Wire.endTransmission(); // สิ้นสุดการสื่อสาร
}
void handleDevice3(int address) {
// สื่อสารกับอุปกรณ์ 3 (ที่อยู่อาณาเขต: SLAVE_ADDRESS_3)
Wire.beginTransmission(address); // เริ่มการสื่อสารกับอุปกรณ์
// ส่งคำสั่งหรือข้อมูลที่เฉพาะกับอุปกรณ์ 3
Wire.write("คำสั่งสำหรับอุปกรณ์ 3");
Wire.endTransmission(); // สิ้นสุดการสื่อสาร
}
- Details
- Written by Super User
- Category: Microcontroller & Microprocessor
- Hits: 968
การควบคุม RC servo ด้วย PID Control เป็นเรื่องที่น่าสนใจและเป็นประโยชน์สำหรับผู้ที่สนใจในการพัฒนาโปรเจ็คทางด้าน อิเล็กทรอนิกส์ และ โรบอทิกส์ สำหรับผู้เริ่มต้น มีข้อแนะนำดังนี้:
-
เริ่มจากพื้นฐาน:
- ความหมายของ RC servo และ ทำไมต้องใช้ PID Control
- ศึกษาการทำงานของ RC servo รวมถึงการเชื่อมต่อไฟฟ้า
-
ทฤษฎี PID Control:
- ความหมายของ P, I, D และ วิธีการทำงานของแต่ละส่วน
- การปรับ PID constants และวิธีการดูแล้วว่า constants ใดทำให้การควบคุมดีขึ้น
-
การเขียนโค้ด:
- ตัวอย่างโค้ดที่ง่ายสำหรับควบคุม RC servo ด้วย PID
- อธิบายการทำงานของโค้ดในแต่ละส่วน
-
ปฏิบัติการ:
- การเชื่อมต่อ RC servo กับ ESP32 และอุปกรณ์อื่น ๆ
- วิธีการปรับปรุงและประสิทธิภาพในการควบคุม
-
การทดสอบและการปรับแต่ง:
- วิธีการทดสอบระบบ เช่น การใช้ฟังก์ชันแตกต่าง ๆ และการปรับค่าต่าง ๆ
- สาเหตุที่ PID ไม่ทำงานดีในบางเวลา และวิธีการแก้ไข
-
เคสตัวอย่างและโปรเจคที่เกี่ยวข้อง:
- ตัวอย่างโปรเจคที่สามารถประยุกต์ใช้ PID Control กับ RC servo
- การพัฒนาและประยุกต์ใช้ในความเป็นจริง
Single RC Servo Control with PID
//ESP32 CPU with Arduino IDE
#include <ESP32_Servo.h>
#include <PID_v1.h>
Servo throttleServo;
const int throttlePin = 14; // The digital pin where the servo is connected
const int sensorPin = 4; // The digital pin where the sensor is connected
const double setPointRPM = 6800.0; // Store setpoint RPM as double
double measuredRPM = 0;
volatile int pulseCount = 0;
unsigned long lastPulseTime = 0;
// PID parameters
double kp = 1.0; // Proportional constant
double ki = 0.1; // Integral constant
double kd = 0.1; // Derivative constant
double throttleOutput; // Declare throttleOutput here
double actualSetPointRPM = setPointRPM; // Create a double variable for setpoint RPM
PID pid(&measuredRPM, &throttleOutput, &actualSetPointRPM, kp, ki, kd, DIRECT);
const int minServoValue = 0; // Minimum servo value
const int maxServoValue = 180; // Maximum servo value
void setup() {
Serial.begin(115200);
throttleServo.attach(throttlePin);
pinMode(sensorPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(sensorPin), handleInterrupt, FALLING);
// Set the output limits for the PID controller
pid.SetOutputLimits(minServoValue, maxServoValue);
// Set the mode of the PID controller to AUTOMATIC
pid.SetMode(AUTOMATIC);
}
void loop() {
unsigned long currentTime = millis();
if (currentTime - lastPulseTime >= 1000) {
measuredRPM = pulseCount * (60000.0 / (currentTime - lastPulseTime));
lastPulseTime = currentTime;
pulseCount = 0;
pid.Compute(); // Compute the PID output
throttleServo.write(throttleOutput);
Serial.print("Measured RPM: ");
Serial.print(measuredRPM);
Serial.print("\tThrottle Output: ");
Serial.println(throttleOutput);
printPIDValues(kp, ki, kd); // Print PID gains for debugging
}
}
void handleInterrupt() {
pulseCount++;
}
void printPIDValues(double Kp, double Ki, double Kd) {
Serial.print("P: "); Serial.print(Kp);
Serial.print("\tI: "); Serial.print(Ki);
Serial.print("\tD: "); Serial.println(Kd);
}
Multi RC Servo Control with PID
//ESP32 CPU with Arduino IDE
#include <ESP32_Servo.h>
#include <PID_v1.h>
struct ServoControl {
Servo servo;
int servoPin;
int sensorPin;
double setPointRPM;
double kp;
double ki;
double kd;
// Runtime variables
PID* pid;
double measuredRPM = 0;
volatile int pulseCount = 0;
unsigned long lastPulseTime = 0;
double throttleOutput;
double input;
double output;
double setpoint;
ServoControl(int sPin, int sensor, double sp, double p, double i, double d)
: servoPin(sPin), sensorPin(sensor), setPointRPM(sp), kp(p), ki(i), kd(d) {}
};
ServoControl controls[] = {
ServoControl(14, 4, 6800.0, 1.0, 0.1, 0.1),
ServoControl(15, 5, 6800.0, 1.2, 0.05, 0.2),
ServoControl(16, 17, 6800.0, 1.2, 0.05, 0.2)
};
void IRAM_ATTR handleInterrupt0() { controls[0].pulseCount++; }
void IRAM_ATTR handleInterrupt1() { controls[1].pulseCount++; }
void IRAM_ATTR handleInterrupt2() { controls[2].pulseCount++; }
typedef void (*ISR)(void);
ISR interruptHandlers[] = {
handleInterrupt0,
handleInterrupt1,
handleInterrupt2 // Fixed to correct interrupt handler
};
void initServo(ServoControl &control, int index) {
control.servo.attach(control.servoPin);
pinMode(control.sensorPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(control.sensorPin), interruptHandlers[index], FALLING);
control.input = control.measuredRPM;
control.output = control.throttleOutput;
control.setpoint = control.setPointRPM;
control.pid = new PID(&control.input, &control.output, &control.setpoint, control.kp, control.ki, control.kd, DIRECT);
control.pid->SetOutputLimits(0, 180);
control.pid->SetMode(AUTOMATIC);
}
void setup() {
Serial.begin(115200);
for (int i = 0; i < sizeof(controls)/sizeof(controls[0]); i++) {
initServo(controls[i], i);
}
}
void adjustPIDViaSerial() {
if (Serial.available()) {
String input = Serial.readStringUntil('\n');
int servoID;
char parameter;
double value;
sscanf(input.c_str(), "%d,%c,%lf", &servoID, ¶meter, &value);
if(servoID >= 0 && servoID < sizeof(controls)/sizeof(controls[0])) {
switch (parameter) {
case 'P': controls[servoID].kp = value; break;
case 'I': controls[servoID].ki = value; break;
case 'D': controls[servoID].kd = value; break;
}
controls[servoID].pid->SetTunings(controls[servoID].kp, controls[servoID].ki, controls[servoID].kd);
Serial.println("PID values updated!");
} else {
Serial.println("Invalid servo ID!");
}
}
}
void loop() {
adjustPIDViaSerial();
for (int i = 0; i < sizeof(controls)/sizeof(controls[0]); i++) {
ServoControl& control = controls[i];
unsigned long currentTime = millis();
if (currentTime - control.lastPulseTime >= 1000) {
control.measuredRPM = control.pulseCount * (60000.0 / (currentTime - control.lastPulseTime));
control.lastPulseTime = currentTime;
control.pulseCount = 0;
control.input = control.measuredRPM;
control.pid->Compute();
control.servo.write(control.output);
Serial.print("Servo #");
Serial.print(i);
Serial.print(" - Measured RPM: ");
Serial.print(control.measuredRPM);
Serial.print("\tThrottle Output: ");
Serial.println(control.output);
}
}
}
- Details
- Written by Super User
- Category: Microcontroller & Microprocessor
- Hits: 345
การขัดจังหวะ (Interrupt) เป็นคุณสมบัติอย่างหนึ่งของไมโครโปรเซสเซอร์ที่ช่วยให้การประมวลผลข้อมูลเป็นไปอย่างมีประสิทธิภาพมากขึ้น โดยเป็นการหยุดการทำงานที่ดำเนินอยู่ในปัจจุบันชั่วคราว เพื่อไปจัดการกับเหตุการณ์สำคัญบางอย่างที่เกิดขึ้น เช่น การกดปุ่มบนแป้นพิมพ์ การมาถึงของข้อมูลจากอุปกรณ์ภายนอก เป็นต้น เมื่อจัดการกับเหตุการณ์สำคัญเสร็จแล้ว ไมโครโปรเซสเซอร์จะกลับมาทำงานที่ดำเนินอยู่เดิมต่อไป
การขัดจังหวะสามารถแบ่งออกได้เป็น 2 ประเภทหลักๆ คือ
- การขัดจังหวะจากอุปกรณ์ภายนอก (External Interrupt) เป็นการขัดจังหวะที่เกิดจากอุปกรณ์ภายนอก เช่น การกดปุ่มบนแป้นพิมพ์ การมาถึงของข้อมูลจากอุปกรณ์ภายนอก เป็นต้น
- การขัดจังหวะจากซอฟต์แวร์ (Software Interrupt) เป็นการขัดจังหวะที่เกิดจากซอฟต์แวร์ เช่น การเรียกใช้ฟังก์ชัน interrupt ในโปรแกรม
หลักการทำงานของการขัดจังหวะ มีดังนี้
- อุปกรณ์ภายนอกหรือซอฟต์แวร์จะส่งสัญญาณขัดจังหวะไปยังไมโครโปรเซสเซอร์
- ไมโครโปรเซสเซอร์จะหยุดการทำงานที่ดำเนินอยู่ในปัจจุบันชั่วคราว
- ไมโครโปรเซสเซอร์จะบันทึกค่าสถานะการทำงานปัจจุบันลงในหน่วยความจำ
- ไมโครโปรเซสเซอร์จะเปลี่ยนเส้นทางการประมวลผลไปยังโปรแกรมย่อยการขัดจังหวะ
- โปรแกรมย่อยการขัดจังหวะจะจัดการกับเหตุการณ์สำคัญที่เกิดขึ้น
- โปรแกรมย่อยการขัดจังหวะจะส่งสัญญาณกลับไปยังไมโครโปรเซสเซอร์
- ไมโครโปรเซสเซอร์จะกลับมาทำงานที่ดำเนินอยู่เดิม
การขัดจังหวะช่วยให้การประมวลผลข้อมูลเป็นไปอย่างมีประสิทธิภาพมากขึ้น โดยช่วยลดเวลาในการรอคอยของอุปกรณ์ภายนอกหรือซอฟต์แวร์ เนื่องจากไมโครโปรเซสเซอร์จะไม่รอให้ทำงานที่ดำเนินอยู่ในปัจจุบันเสร็จสิ้นก่อนจึงไปจัดการกับเหตุการณ์สำคัญที่เกิดขึ้น
นอกจากนี้ การขัดจังหวะยังช่วยให้สามารถจัดการกับเหตุการณ์สำคัญต่างๆ ได้อย่างทันท่วงที เช่น การกดปุ่มบนแป้นพิมพ์ การมาถึงของข้อมูลจากอุปกรณ์ภายนอก เป็นต้น
ไมโครคอนโทรลเลอร์ ESP32 พัฒนาโดย Espressif Systems มีระบบขัดจังหวะที่ยืดหยุ่นมาก IRAM_ATTR เป็นคำหลักที่ใช้ระบุว่าควรวางฟังก์ชันเฉพาะไว้ใน RAM ภายในของ ESP32 เพื่อการดำเนินการที่รวดเร็วยิ่งขึ้น โดยเฉพาะอย่างยิ่งที่สำคัญอย่างยิ่งสำหรับ Interrupt Service Routines (ISR) เพื่อให้แน่ใจว่าฟังก์ชันดังกล่าวสามารถทำงานได้อย่างรวดเร็วและไม่ถูกขัดจังหวะโดยการทำงานของหน่วยความจำแฟลช .
จำนวน "ชุดการขัดจังหวะ" ที่สามารถรองรับได้:
- จำนวนการขัดจังหวะของฮาร์ดแวร์: ESP32 มีพิน GPIO จำนวนหนึ่ง ซึ่งส่วนใหญ่สามารถกำหนดค่าให้เป็นแหล่งสัญญาณขัดจังหวะภายนอกได้ ตามทฤษฎีแล้ว หมายความว่า GPIO เกือบทุกพินสามารถมีรูทีนขัดจังหวะของตัวเองได้ อย่างไรก็ตาม จำนวนที่แน่นอนอาจน้อยกว่าเล็กน้อย เนื่องจากพินบางตัวอาจมีฟังก์ชันพิเศษหรืออาจไม่ปรากฏบนทุกโมดูล
- การขัดจังหวะที่ใช้ร่วมกัน: เป็นไปได้ที่พิน GPIO หลายอันจะแชร์รูทีนขัดจังหวะเดียว ซึ่งทำได้โดยการตรวจสอบว่าพินใดที่ทำให้เกิดการขัดจังหวะภายใน ISR
- การขัดจังหวะของซอฟต์แวร์และการแจ้งเตือนงาน: นอกเหนือจากการขัดจังหวะด้วยฮาร์ดแวร์แล้ว ESP32 ยังรองรับการขัดจังหวะที่เรียกใช้ซอฟต์แวร์และการแจ้งเตือนงานอีกด้วย สิ่งเหล่านี้ใช้ภายในสภาพแวดล้อม FreeRTOS ที่กรอบงาน ESP-IDF ใช้ โดยทั่วไปแล้วจะไม่ถูกระบุว่าเป็น "การขัดจังหวะ" ในความหมายของไมโครคอนโทรลเลอร์แบบดั้งเดิม แต่มีจุดประสงค์ที่คล้ายกัน
- ข้อจำกัดของ RAM ภายใน (IRAM): แม้ว่าคุณจะสามารถกำหนด ISR ได้จำนวนมาก แต่โปรดจำไว้ว่า IRAM ของ ESP32 นั้นมีจำกัด หากคุณวางฟังก์ชันมากเกินไปหรือฟังก์ชันขนาดใหญ่ใน IRAM โดยใช้ IRAM_ATTR พื้นที่ว่างของคุณอาจหมด คุณต้องจัดการพื้นที่นี้อย่างรอบคอบเพื่อให้แน่ใจว่า ISR ที่สำคัญและฟังก์ชันที่สำคัญอื่นๆ สามารถเหมาะสมได้
ดังนั้น แม้ว่าจะไม่มี "จำนวนชุดของการขัดจังหวะ" ที่เข้มงวดซึ่ง ESP32 สามารถรองรับได้ แต่จำนวนดังกล่าวก็ถูกกำหนดโดยพิน GPIO ที่มีอยู่ซึ่งสามารถตั้งค่าเป็นแหล่งการขัดจังหวะ กลไกการขัดจังหวะระดับซอฟต์แวร์อื่นๆ และความพร้อมใช้งานของ IRAM ช่องว่าง.
อ้างอิงถึงการใช้IRAM_ATTR คำหลักสำหรับรูทีนการบริการขัดจังหวะ (ISR) บน ESP32 โดยทั่วไปจะทำเพื่อให้แน่ใจว่า ISR ถูกจัดเก็บไว้ใน RAM ภายใน (IRAM) ของ ESP32 เพื่อให้สามารถดำเนินการได้อย่างรวดเร็วและไม่ได้รับผลกระทบจากการทำงานของแฟลชที่อาจเกิดขึ้น
อธิบายให้ชัดเจนกว่านี้:
เมื่อเกิดการขัดจังหวะระบบจะต้องตอบสนองทันที อย่างไรก็ตาม ใน ESP32 หากโค้ดของคุณดำเนินการจากหน่วยความจำแฟลช อาจเกิดข้อขัดแย้งได้หากการดำเนินการอื่น เช่น การเขียนหรืออ่านแฟลชเกิดขึ้นพร้อมกัน เมื่อ ISR ไม่ได้อยู่ใน IRAM และกำลังดำเนินการแฟลชเมื่อเกิดการขัดจังหวะ การตอบสนองของการขัดจังหวะอาจล่าช้า ซึ่งอาจนำไปสู่การพลาดการขัดจังหวะหรือปัญหาอื่นๆ
เพื่อป้องกันสิ่งนี้ ควรวางโค้ดสำคัญเช่น ISR ไว้ใน IRAM เพื่อให้แน่ใจว่าการตอบสนองของการขัดจังหวะจะเกิดขึ้นทันที และไม่ต้องรอการทำงานของแฟลชใดๆ
นี่เป็นตัวอย่างง่ายๆ ของวิธีที่คุณอาจใช้IRAM_ATTR ด้วย ISR:
void IRAM_ATTR handleInterrupt() {
// Your ISR code here
}
โดยการวางIRAM_ATTR ก่อนคำจำกัดความฟังก์ชัน ISR คุณกำลังสั่งให้ ESP-IDF (กรอบการพัฒนาอย่างเป็นทางการสำหรับ ESP32) เพื่อวางจัดการขัดจังหวะ ทำงานใน RAM ภายใน ช่วยให้มั่นใจถึงการดำเนินการที่รวดเร็วเมื่อเกิดการขัดจังหวะ
อย่างไรก็ตาม โปรดทราบว่า IRAM มีขนาดจำกัด ดังนั้นให้ใช้IRAM_ATTR อย่างรอบคอบและเฉพาะสำหรับฟังก์ชันที่ความเร็วในการดำเนินการเป็นสิ่งสำคัญ เช่น ISR หากคุณใช้งานมากเกินไป พื้นที่ IRAM ของคุณจะหมด ซึ่งจะส่งผลให้เกิดข้อผิดพลาดในการคอมไพล์
ตัวอย่าง 5 buttons
// Define 5 buttons
struct Button {
const uint8_t PIN;
uint32_t numberKeyPresses;
bool pressed;
};
Button buttons[] = {
{18, 0, false},
{19, 0, false},
{20, 0, false},
{21, 0, false},
{22, 0, false}
};
// ISR for all buttons
void IRAM_ATTR handleInterrupt() {
for (int i = 0; i < 5; i++) {
if (digitalRead(buttons[i].PIN) == LOW) { // If button is pressed
buttons[i].numberKeyPresses++;
buttons[i].pressed = true;
}
}
}
void setup() {
Serial.begin(115200);
// Attach interrupt for all buttons
for (int i = 0; i < 5; i++) {
pinMode(buttons[i].PIN, INPUT_PULLUP);
attachInterrupt(buttons[i].PIN, handleInterrupt, FALLING);
}
}
void loop() {
for (int i = 0; i < 5; i++) {
if (buttons[i].pressed) {
Serial.printf("Button %d has been pressed %u times\n", i + 1, buttons[i].numberKeyPresses);
buttons[i].pressed = false;
}
}
}
อธิบาย Code นี้:
- อาร์เรย์ปุ่ม ใช้สำหรับเก็บข้อมูลทั้ง 5 ปุ่ม
- รูทีนบริการขัดจังหวะครั้งเดียวจัดการขัดจังหวะ ใช้สำหรับปุ่มทั้งหมด ภายใน ISR นี้ จะมีการตรวจสอบแต่ละปุ่มเพื่อดูว่าปุ่มใดถูกกด
- ในระหว่างติดตั้งแต่ละปุ่มจะถูกเตรียมใช้งานเป็นอินพุตพร้อมกับตัวต้านทานแบบดึงขึ้นภายใน และเชื่อมโยงกับรูทีนบริการขัดจังหวะ
- Loop ฟังก์ชั่นตรวจสอบสถานะของปุ่มแต่ละปุ่ม และหากกด จะแสดงผลจำนวนครั้งที่กด
ตรวจสอบให้แน่ใจว่า Pin ที่คุณใช้ (18, 19, 20, 21, 22 ในตัวอย่างนี้) พร้อมใช้งานสำหรับจุดประสงค์นี้บนบอร์ด/โมดูล ESP32 เฉพาะของคุณ ถ้าไม่คุณสามารถเปลี่ยนเป็นหมุดอื่นที่เหมาะสมได้
REF .
https://lastminuteengineers.com/handling-esp32-gpio-interrupts-tutorial/
- Details
- Written by Super User
- Category: Microcontroller & Microprocessor
- Hits: 1380
https://github.com/curiores/ArduinoTutorials/tree/main/SolarCharger