7. C++ พื้นฐาน: ฟังก์ชันและอาร์เรย์
แยกโค้ดเป็นฟังก์ชันที่รับค่าและคืนค่า ค่าเริ่มต้นของพารามิเตอร์ ส่งฟังก์ชันให้ฟังก์ชันอื่น และอาร์เรย์
ฟังก์ชันและอาร์เรย์ สรุปก่อนอ่าน
- ฟังก์ชัน ชุดคำสั่งที่ตั้งชื่อไว้ เหมือนปุ่ม "ซักผ้า" ที่กดทีเดียวทำหลายขั้นตอน (อธิบายจากศูนย์ใน อ่านโค้ดให้ออก)
- อาร์เรย์ แถวของกล่องหลายใบที่ใช้ชื่อเดียวกัน แยกกันด้วยเลขลำดับ เหมือนตู้ล็อกเกอร์ที่มีเลขกำกับ
- ในโค้ดโดรน ใช้เก็บระยะบินหลายรอบ เช่น
forwardDistanceCM[4]แล้วเรียกด้วยเลขรอบ
1. ฟังก์ชัน
ฟังก์ชัน (function) คือชุดคำสั่งที่ตั้งชื่อไว้ เรียกชื่อเมื่อไรก็ทำงานชุดนั้น มีไว้ไม่ให้เขียนซ้ำ และให้ชื่อบอกว่ากำลังทำอะไร
// Servo_Degree.ino
int servo_degree_to_pulse(int angle) {
angle = constrain(angle, SERVO_DEGREE_MIN, SERVO_DEGREE_MAX);
return map(angle, SERVO_DEGREE_MIN, SERVO_DEGREE_MAX,
SERVO_DEGREE_MIN_PULSE, SERVO_DEGREE_MAX_PULSE);
}ส่วนประกอบ
intหน้าชื่อ คือ ชนิดที่คืนกลับ (return type)servo_degree_to_pulseคือชื่อ(int angle)คือ พารามิเตอร์ ค่าที่รับเข้ามาreturnส่งผลกลับไปที่ผู้เรียก และจบฟังก์ชันทันที
เรียกใช้
int us = servo_degree_to_pulse(90); // us = 1520constrain(angle, 0, 180) ตัดค่าให้อยู่ในช่วง ใครส่ง 200 มา ก็ถูกปรับเป็น 180 map แปลงจากช่วงหนึ่งไปอีกช่วงหนึ่ง (0–180 เป็น 490–2550) เป็นฟังก์ชันที่ Arduino มีให้อยู่แล้ว
ตัวอย่างชีวิตจริง: เครื่องชงกาแฟกดปุ่มเดียว
คุณไม่ต้องรู้ว่าเครื่องบดเมล็ดยังไง กดปุ่ม "ลาเต้" ก็ได้กาแฟ ฟังก์ชันคือปุ่ม ชุดคำสั่งภายในคือขั้นตอนที่ซ่อนอยู่ drone.takeOff() ก็เหมือนกัน
void: ไม่คืนค่า
ถ้าฟังก์ชันทำงานเฉยๆ ไม่มีผลลัพธ์ ใช้ void
// config.hpp
static inline void hold_now(uint16_t ms = 250){
pArduino->set_direction(7,2);
delay(ms);
}ค่าเริ่มต้น (default argument)
uint16_t ms = 250 แปลว่าถ้าไม่ใส่ค่า ให้ใช้ 250
hold_now(); // รอ 250 ms
hold_now(400); // รอ 400 msคลาส Arduino ใช้เทคนิคนี้ทุกที่ ดู protocol.hpp
void move_forward_cm(uint16_t distance_cm, uint8_t speed = 2);move_forward_cm(100) = บินหน้า 100 cm ที่ความเร็ว 2
static inline คืออะไร
เจอบ่อยหน้าฟังก์ชันใน config.hpp ไม่ต้องกังวลมาก จำสั้นๆ ว่า static = ใช้ได้เฉพาะในไฟล์นี้ inline = ขอให้คอมไพเลอร์แปะโค้ดลงตรงที่เรียกเลย ไม่ต้องกระโดด ไฟล์ .hpp ที่ถูก include หลายที่ควรใส่สองคำนี้ เพื่อไม่ให้เจอ error นิยามซ้ำ
ส่งฟังก์ชันไปให้ฟังก์ชันอื่น
ฟังก์ชันก็เป็นค่าที่ส่งต่อได้ ส่ง "ชื่อฟังก์ชัน" ไม่ใส่วงเล็บ ไปให้อีกฟังก์ชันถือไว้เรียกทีหลัง นี่คือวิธีผูกปุ่มรีโมทของชมรม
// DroneEasy.hpp
void onKey1(void (*handler)(void)) const;
// Drone_Mission.ino
drone.onKey1(DroneMission_KEY_1_handle);void (*handler)(void) อ่านว่า "handler คือตัวชี้ไปยังฟังก์ชันที่ไม่รับอะไรและไม่คืนอะไร" DroneMission_KEY_1_handle ไม่มีวงเล็บ เพราะต้องการส่งตัวฟังก์ชัน ไม่ใช่เรียกมัน ถ้าเขียน DroneMission_KEY_1_handle() โดรนจะลงมือบินทันทีตอนบูต
2. อาร์เรย์
อาร์เรย์ (array) คือแถวของกล่องชนิดเดียวกันที่เรียกด้วยเลขลำดับ (index) ที่ เริ่มจาก 0
// Drone_Mission.ino
int forwardDistanceCM[4] = { 352, 352, 352, 352 };
int backwardDistanceCM[4] = { 252, 252, 252, 252 };int a = forwardDistanceCM[0]; // 352 ช่องแรก
forwardDistanceCM[2] = 360; // แก้ช่องที่สามอาร์เรย์ไว้คู่กับ for ได้ดี ตัวอย่างบวกทุกช่อง (ทดสอบคอมไพล์สำหรับ Nano แล้ว)
int forwardDistanceCM[4] = { 352, 352, 352, 352 };
int total() {
int sum = 0;
for (int i = 0; i < 4; i++) {
sum += forwardDistanceCM[i];
}
return sum;
}
void setup() {
Serial.begin(9600);
Serial.println(total()); // 1408
}
void loop() {}ใช้ i < 4 ไม่ใช่ i <= 4 เพราะช่องสุดท้ายคือ [3]
ทำไมโค้ดชมรมใช้อาร์เรย์
ภารกิจมีหลายรอบ แต่ละรอบระยะเท่ากันหรือต่างกันก็ได้ เก็บในอาร์เรย์ แล้วเลือกด้วยเลขรอบ ปรับระยะจุดเดียวไม่ต้องไล่แก้หลายที่ ในไฟล์มีตัวนับรอบ k2_round และ payload_round10 อยู่ด้วย
ลองทำ
- เขียนฟังก์ชัน
int half(int x)คืนครึ่งหนึ่งของxเรียกhalf(300)ควรได้ 150 - เพิ่มพารามิเตอร์ที่มีค่าเริ่มต้น
int half(int x, int divisor = 2)แล้วเรียกhalf(300, 3)(คำตอบ: 100) - เปิดไฟล์
Test_ball.inoนับดูว่ามีการเรียกrelease_servo_angleกี่ครั้ง แล้วลองคิดว่าถ้าเก็บค่าพัลส์ไว้ในอาร์เรย์ จะสั้นลงอย่างไร
พังตรงไหนบ่อย
- เลขลำดับเกิน
forwardDistanceCM[4]อ่านนอกอาร์เรย์ ได้ค่ามั่ว ไม่มี error ให้ - ลืม
returnฟังก์ชันที่ต้องคืนค่า คอมไพล์ผ่านแต่ผลที่ได้เป็นค่าสุ่ม - ใส่วงเล็บตอนส่งฟังก์ชันไปผูกปุ่ม เรียกทันทีแทนที่จะรอปุ่ม
- ประกาศฟังก์ชันหลังใช้ Arduino IDE จัดการให้ในไฟล์
.inoแต่ใน.cppต้องเขียนประกาศไว้ก่อน - ชื่อฟังก์ชันซ้ำข้ามไฟล์
.inoดู โครงสร้างโปรเจกต์