สวัสดีครับ หลายๆท่านอาจเคยได้เห็นฟังก์ชัน map() กันมาบ้างแล้วจากตัวอย่างเช่น การรับค่า analog จากเซนเซอร์ต่างๆ อย่างความชื้น แล้วมาแปลงเป็นเปอร์เซ็น ตัวอย่าง code การแปลงความชื้นมาเป็นเปอร์เซ็น ข้างล่างนี้
เมื่ออัพโหลดแล้วลองอ่านค่าก็จะออกมาเป็นเปอร์เซ็นจำนวนเต็มให้เสร็จสรรพ

หลักการก็ไม่มีอะไรมาก ฟังก์ชัน map เป็นฟังก์ชัน เปลี่ยนค่าจากช่วงนึง ไปเป็นอีกช่วงหนึ่ง เช่น ค่าของเราจากที่อ่านได้ 0-1023 เราต้องการให้มันออกมาเป็น 0-100 ก็ใช้คำสั่ง map ซึ่งจะต้องกำหนดค่าต่างๆเรียกว่า parameters (พารามิเตอร์) ดังนี้
int newvalue = map ( value, fromLow, fromHigh, toLow, toHigh )
โดยพารามิเตอร์
- value คือค่าเดิมที่อาจจะอ่านได้จาก analogread หรือค่าจากตัวแปรใด ๆ ที่เราต้องการเปลี่ยนมัน
- fromLow คือค่าต่ำสุดของค่าเดิม
- fromHigh คือค่าสูงสุดของค่าเดิม
- toLow คือค่าต่ำสุดของค่าใหม่ที่เราต้องการเมื่อค่าเก่ามีค่าต่ำสุด
- toHigh ค่าค่าสูงสุดของค่าใหม่ที่เราต้องการเมื่อค่าเก่ามีค่าสูงสุด
เช่น กรณีค่าที่เราอ่านจากเซนเซอร์เดิมๆ ได้ 0-1023 แต่ต้องการปรับช่วง
ค่าเป็นตั้งแต่ 25-80 ก็ใส่ลงในฟังก์ชั่นเป็น
int val = map(analogRead(A7), 0, 1023, 25, 80);
ผลลัพธ์ของบรรทัดด้านบนคือ เมื่อเราอ่านค่า analog จากขา A7 ซึ่งมีค่าระหว่าง 0-1023 เราจะได้ค่าใหม่ที่อยู่ระหว่าง 25-80 ลงไปเก็บบนตัวแปร val นั่นเอง
เพื่อความเข้าใจ เราลองมาดูเบื้องหลังโค้ดของฟังก์ชัน map ที่เราใช้ข้างต้นว่าถูกเขียนมาอย่างไร ตามด้านล่างเลย
long map(long x, long in_min, long in_max, long out_min, long out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
วิธีการคำนวณนั่นคือการเอาค่าเดิมมาทำให้เป็นเปอร์เซ็น แล้วนำมาเทียบว่าอยู่ตรงไหนของค่าใหม่ ด้วยการคูณด้วยช่วงของค่าใหม่ จากนั้นบวกด้วยค่าต่ำสุดของค่าใหม่ เอาเป็นว่าวิธีการคำนวณไม่ได้มีปัญหาอะไร แต่ไอที่มีปัญหาให้ปวดหัวคือ เจ้าตัวแปรประเภท long ที่ใช้ต่างหาก
เราทราบกันดีว่า ตัวแปรประเภท long คือจำนวนเต็มตั้งแต่ -2,147,483,647 ถึง 2,147,483,647 ซึ่งหมายความว่า ฟังก์ชันนี้เราไม่สามารถใช้ตัวแปรทศนิยมในการคำนวณได้อย่างถูกต้อง เช่น
int val = map(analogRead(A7), 0, 1023, 0, 1000);
//แปลงจาก 0-1000 เป็น 0-1.0 ด้วยการหาร 1000 เก็บไว้ในตัวแปร float
float valf = val/1000.0;
float newval = map(valf, 0.0, 1.0, 0.0, 100.0);
Serial.println(newval);
เราจะได้ค่าที่เป็น 0 จาก newval ตลอดตามคาด นั่นเกิดจากตัวแปรประเภท long ไม่รู้จักทศนิยมที่อยู่ระหว่าง 0-1 นั่นเอง และการที่เราใช้ฟังก์ชั่น map เดิมๆ จะทำให้เราเสียความละเอียดของข้อมูลไปอีกด้วย จึงแนะนำให้เปลี่ยนไปใช้ฟังก์ชันที่ทำด้วยตัวแปร double หรือ float ยกตัวอย่างเช่น การสร้างฟังก์ชันใหม่ชื่อ mapf ด้านล่าง
โดยนำฟังก์ชั่นนี้ใส่ไว้นอก setup() และ loop() จากนั้น arduino จะดึงเอา prototype ของฟังก์ชันนี้มาใช้อัตโนมัต ซึ่งสามารถทดสอบได้ด้วยตัวเองด้วย code ด้านล่างนี้
เมื่อลองอัพโหลดและอ่านค่าดูจะพบว่าค่าที่ได้มาจะเป็นทศนิยมที่ละเอียดกว่าแบบใช้ฟังก์ชัน map เดิมๆ เพิ่มความแม่นยำเข้าไปอีก !

เราคงหลีกเลี่ยงการใช้ทศนิยมในการใช้งานจริงไม่ได้มากหรอกครับ การระมัดระวังการใช้ฟังก์ชันสำเร็จรูปของ Arduino ด้วยการทดสอบค่าหลายๆแบบ จะช่วยให้เราไม่ตกม้าตายง่ายๆ เซฟเวลาเกาหัวไปได้อีกนะครับ 
หวังว่าจะมีประโยชน์นะครับ มีคำถามสามารถสอบถามเข้ามาได้เลย
เลี้ยงกาแฟผมสักแก้ว : https://ko-fi.com/modulemore
reference
https://www.arduino.cc/reference/en/language/functions/math/map/ https://stackoverflow.com/questions/1819189/what-range-of-values-can-integer-types-store-in-c