[TH] Arduino: data types

ในบทความนี้กล่าวถึงตัวแปร ประเภทของข้อมูลและค่าคงที่สำหรับใช้กับ Arduino ซึ่งเป็นพื้นฐานของการเขียนโปรแกรม ทั้งนี้เนื่องจากการเขียนโปรแกรมมีหลักการ ดังที่ Niklaus Wirth  ได้กล่าวไว้ตั้งแต่ ค.ศ. 1976 ในหนังสือ ว่า

Algorithms + Data Structures = Programs

หรือ

โปรแกรม = ข้อมูล + ขั้นตอนวิธี

ทั้งนี้ เนื่องจากโปรแกรมคือขั้นตอนวิธีการแก้ปัญหาที่นำข้อมูลมาประมวลผล ซึ่งเป็นสาเหตุสำคัญของความแตกต่างระหว่างการคำนวณกับโปรแกรม

ตัวแปร

ตัวแปร (Variable) เป็นหน่วยความจำประเภทเขียนและลบได้หรือหน่วยความจำแรม (RAM: Random Access Memory) ที่ถูกจองไว้สำหรับเก็บข้อมูลตามขนาดที่ระบุ และอ้างอิงด้วยค่าตำแหน่งเริ่มต้นของหน่วยความจำที่ใช้จัดเก็บข้อมูล แต่ภาษาเขียนโปรแกรมนิยมให้ผู้เขียนโปรแกรมสามารถตั้งชื่อเพื่อใช้แทนค่าตัวเลขตำแหน่งดังกล่าวเพื่อความสะดวกในการเขียนรหัสคำสั่ง โดยตัวแปรสามารถเปลี่ยนแปลงค่าได้ขณะที่โปรแกรมทำงาน หรือขณะที่ตัวแปรนั้นมีช่วงอายุการทำงาน

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

นอกจากนี้ ภาษา C++ ยอมให้สามารถประกาศตัวแปรใช้งานภายในเครื่องหมาย { และ } เพื่อเป็นตัวแปรภายในของเครื่องหมายดังกล่าว และตัวแปรที่สร้างขึ้นถูกยกเลิกเมื่อสิ้นสุดการทำงานในช่วงของ { และ }

ค่าคงที่

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

ประเภทของข้อมูล

ประเภทของข้อมูลเป็นการกำหนดวิธีการใช้งานหน่วยความจำตามที่ภาษาเขียนโปรแกรมกำหนด เช่น กำหนดให้หน่วยความจำขนาด 1 ไบต์ เรียกว่า char เพื่อเก็บข้อมูลตัวเลขจำนวนเต็มขนาด 8 บิต ที่มีค่า -,0,+ หรือกำหนดให้หน่วยความจำขนาด 1 ไบต์เรียกว่า byte สำหรับเก็บข้อมูลจำนวนเต็มขนาด 1 ไบต์ หรือ 8 บิต ที่มีค่า 0 ถึง + เป็นต้น

Arduino ใช้ภาษา C++ เป็นภาษาเขียนโปรแกรม ทำให้ประเภทของข้อมูลพื้นฐานของภาษา C++ จึงเหมือนกัน เพียงแต่ Arduino ถูกใช้กับไมโครคอนโทรลเลอร์ที่มีความแตกต่างกัน เช่น เป็นหน่วยประมวลผลที่มีขนาดแตกต่างกัน มีปริมาณหน่วยความจำแรมที่แตกต่างกัน เป็นต้น ทำให้เมื่อเขียนโปรแกรมกับไมโครโปรเซสเซอร์ของบอร์ด Arduino Uno กับ ESP8266 จึงมีความแตกต่างกัน เนื่องจากตัวหนึ่งเป็นหน่วยประมวลผลแบบ 8 บิต ขณะที่อีกตัวเป็นแบบ 32 บิต และปริมาณหน่วยความจำของ Arduino Uno ที่ใช้ ATmega328P มีแรมเพียง 2KB ขณะที่ ESP8266 มีหน่วยความจำแรมสำหรับผู้ใช้ใช้งานอยู่ 80KB ดังนั้น ในการพัฒนาโปรแกรมจะต้องพิจารณาการใช้หน่วยความจำหรือสร้างตัวแปรให้มีขนาดที่เหมาะสมกับประเภทของข้อมูลที่ใช้งาน และเมื่อเขียนแล้วใช้งานกับ ESP8266 ได้ แต่เมื่อนำมาใช้กับ ATmega328P อาจจะประสบปัญหาเรื่องหน่วยความจำไม่พอ

ประเภทข้อมูลพื้นฐานที่กล่าวถึงในบทความนี้ได้แก่

  • boolean มีขนาด 8 บิต เก็บค่า true หรือ false
  • char มีขนาด 8 บิต เก็บค่าตัวเลขจำนวนเต็มแบบมีเครื่องหมาย จึงสามารถเก็บค่าได้ในช่วง -128 ถึง 127
  • unsigned char มีขนาด 8 บิต เก็บค่าตัวเลขจำนวนเต็มแบบไม่มีเครื่องหมายลบ จึงสามารถเก็บค่าได้ในช่วง 0 ถึง 255
  • byte มีขนาด 8 บิต เก็บค่าตัวเลขจำนวนเต็มแบบไม่มีเครื่องหมายลบ จึงสามารถเก็บค่าได้ในช่วง 0 ถึง 255
  • int มีขนาด 16 บิต เก็บค่าตัวเลขจำนวนเต็มแบบมีเครื่องหมาย จึงสามารถเก็บค่าได้ในช่วง -32,768 ถึง 32,767
  • unsigned int มีขนาด16 บิต เก็บค่าตัวเลขจำนวนเต็มแบบไม่มีเครื่องหมายลบ จึงสามารถเก็บค่าได้ในช่วง 0 ถึง 65,535
  • word มีขนาด 16 บิต เก็บค่าตัวเลขจำนวนเต็มแบบมีเครื่องหมาย จึงสามารถเก็บค่าได้ในช่วง -32,768 ถึง 32,767
  • word มีขนาด16 บิต เก็บค่าตัวเลขจำนวนเต็มแบบไม่มีเครื่องหมายลบ จึงสามารถเก็บค่าได้ในช่วง 0 ถึง 65,535
  • long มีขนาด 32 บิต เก็บค่าตัวเลขจำนวนเต็มแบบมีเครื่องหมาย จึงสามารถเก็บค่าได้ในช่วง -2,147,483,648 ถึง 2,147,483,647
  • unsigned long มีขนาด 32 บิต เเก็บค่าตัวเลขจำนวนเต็มแบบไม่มีเครื่องหมายลบ จึงสามารถเก็บค่าได้ในช่วง 0 ถึง 4,294,967,295
  • float มีขนาด 32 บิต เก็บค่าตัวเลขทศนิยมแบบ single precision ในช่วงค่า -3.4028235E38 ถึง 3.4028235E38
  • double มีขนาด 64 บิต เก็บค่าตัวเลขทศนิยมแบบ double precision ในช่วงค่า -3.4028235E38 ถึง 3.4028235E38

การตั้งชื่อและการประกาศตัวแปร/ค่าคงที่

การตั้งชื่อของตัวแปรและค่าคงที่มีกฏของการตั้งชื่อดังนี้

  • ต้องไม่ซ้ำกับคำเฉพาะของภาษา C++
  • ต้องไม่ซ้ำกับชื่อที่ตั้งในขอบการใช้งานเดียวกัน แต่ถ้าตั้งชื่อเดียวกันแต่อันหนึ่งเป็นของภายนอกกับภายในฟังก์ชัน หรืออยู่ภายนอก { } กับภายใน สามารถตังชื่อเหมือนกันได้ โดยการอ้างถึงชื่อภายนอกจะใช้เครื่องหมาย :: นำหน้าชื่อ แต่ไม่แนะนำให้ตั้งชื่อเหมือนกันเพื่อป้องกันความสับสน
  • ขึ้นต้นด้วย _ หรือตัวอักษรภาษาอังกฤษ
  • สามารถผสมเครื่องหมาย _ หรือตัวเลขเข้าไปในชื่อได้โดยสามารถเรียงต่อกันไปได้
  • ตัวอักษรพิมพ์เล็กกับพิมพ์ใหญ่ให้ความหมายเป็นคนละตัวกัน

การกำหนดค่า

กฏของการกำหนดค่าอยู่ในรูปแบบต่อไปนี้

L = R;

โดย
L คือ ชื่อตัวแปร
R คือ นิพจน์

การทำงานของการประกาศค่าจะกระทำทางด้านขวา หรือ R จนได้ผลลัพธ์ หลังจากนั้นนำผลลัพธ์ไปเก็บในตัวแปรทางฝั่ง L ซึ่งเป็นหน่วยความจำแรมที่กำหนดไว้

การประกาศตัวแปร

รูปแบบของการประกาศตัวแปรเป็นดังนี้

ชนิดของข้อมูล ชื่อตัวแปร;
ชนิดของข้อมูล ชื่อตัวแปร1, ชื่อตัวแปร2, … , ชื่อตัวแปรN;

ตัวอย่างการประกาศตัวแปรชื่อ voltage เพื่อเก็บค่าแรงดันซึ่งเป็นข้อมูลแบบทศนิยม โดยกำหนดค่าแรงดันเป็น 3.3 เขียนได้ดังนี้

float voltage;

void setup() {
  voltage = 3.3;
}

void loop() {
}

หรือ

float voltage = 3.3;

void setup() {
}

void loop() {
}

การประกาศค่าคงที่

รูปแบบของการประกาศค่าคงที่เป็นดังนี้

const ชนิดของข้อมูล ชื่อตัวแปร = ค่า;

ตัวอย่างการประกาศค่าคงที่ชื่อ voltage เพื่อเก็บค่าแรงดันซึ่งเป็นข้อมูลแบบทศนิยม โดยกำหนดค่าแรงดันเป็น 3.3 เขียนได้ดังนี้

const float voltage = 3.3;

void setup() {
}

void loop() {
}

โครงสร้างข้อมูล

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

จากนิยามของโปรแกรมทำให้เราต้องสร้างตัวแปรสำหรับเก็บข้อมูลที่เหมาะสมสำหรับใช้กับขั้นตอนวิธีของเราเพื่อแก้ไขปัญหาที่ต้องการ ซึ่งถ้าปัญหาที่ต้องแก้ไขมีความศับซ้อนต้องแบ่งการแก้ปัญหาเป็นหลายส่วน หรือต้องอาศัยขั้นตอนวิธีหลายขั้นตอน นั่นหมายความว่าในแต่ละขั้นตอนจะต้องมีกลุ่มของตัวแปรหรือโครงสร้างข้อมูลที่เกี่ยวข้องกับกระบวนการแก้ปัญหานั้น ๆ

โครงสร้างข้อมูลแถวลำดับ

แถวลำดับ (Arrays) เป็นการจองหน่วยความจำสำหรับเก็บข้อมูลประเภทเดียวกันไว้ภายใตีชื่อตัวแปรเดียวกัน และอ้างอิงด้วยค่าลำดับของชุดข้อมูล นั่นหมายความว่า

  • สมาชิกแต่ละตัวในตัวแปรแถวลำดับต้องเป็นข้อมูลประเภทเดียวกัน
  • ต้องมีการระบุจำนวนสมาชิกที่แน่นอนจำนวน n สมาชิก
  • สมาชิกแต่ละตัวอยู่เรียงกันไปตามลำดับจากลำดับที่ 0, 1, 2, … , n-1
  • ปริมาณหน่วยความจำจะต้องเพียงพอในการจัดเก็บข้อมูลทั้งหมด ถ้าไม่เพียงพอจะเกิดความผิดพลาดในการจองหน่วยความจำทำให้โปรแกรมไม่สามารถทำงานได้

การประกาศตัวแปรแถวลำดับมีรูปแบบการประกาศดังนี้

ชนิดข้อมูล ชื่อตัวแปร[จำนวนสมาชิก];

การเข้าถึงสมาชิกกระทำได้ด้วยรูปแบบการเข้าถึงดังนี้ โดยลำดับที่ต้องการเข้าถึงต้องเป็นตัวเลขจำนวนเต็มในช่วง 0 ถึง (n-1)

ชื่อตัวแปร[ ลำดับที่ต้องการเข้าถึง ]

การกำหนดค่าให้กับสมาชิกตัวที่ i ซึ่ง i จะต้องอยู่ในช่วง 0 ถึง (n-1) สามารถกระทำตามรูปแบบต่อไปนี้

ชื่อตัวแปร[ i ] = ค่า ;

กรณีที่ต้องการกำหนดค่าให้แถวลำดับตั้งแต่มีการประกาศตัวแปรสามารถเขียนได้ด้วยรูปแบบต่อไปนี้

ชนิดของข้อมูล ชื่อตัวแปร[n] = {ข้อมูล0, ข้อมูล1, … , ข้อมูลn-1 };

หรือ

ชนิดของข้อมูล ชื่อตัวแปร[] = {ข้อมูล0, ข้อมูล1, … , ข้อมูลn-1 }

ตัวอย่าง

ตัวอย่างการอ่านข้อมูลจากเซ็นเซอร์อุณหภูมิจำนวน 5 ครั้งโดยสมมุติให้แต่ละครั้งมีค่าอุณหภูมิดังนี้ 35, 34, 35, 38 และ 39 ให้ทำการคำนวณหาค่าเฉลี่ยของอุณหภูมิ เมื่อเขียนโดยวิธีปกติที่ไม่ใช่ตัวแปรแถวลำดับเขียนได้ดังนี้

void setup() {
  Serial.begin(115200);
  // Input (data)
  byte temp0, temp1, temp2, temp3, temp4;
  float avgTemp, sumTemp;
  temp0 = 35;
  temp1 = 34;
  temp2 = 35;
  temp3 = 38;
  temp4 = 39;
  // Process (algorithm)
  sumTemp = temp0+temp1+temp2+temp3+temp4;
  avgTemp = sumTemp / 5.0;
  // Output
  Serial.print("Temperature:");
  Serial.print(temp0);
  Serial.print(",");
  Serial.print(temp1);
  Serial.print(",");
  Serial.print(temp2);
  Serial.print(",");
  Serial.print(temp3);
  Serial.print(",");
  Serial.println(temp4);
  Serial.print("Sum of temperature:");
  Serial.println(sumTemp);
  Serial.print("Average of temperature:");
  Serial.println(avgTemp);
}

void loop() {
}

กรณีที่ใช้ตัวแปรแถวลำดับเขียนได้ดังนี้

void setup() {
  Serial.begin(115200);
  // Input (data)
  byte temp[] = {35,34,35,38,39};
  float avgTemp, sumTemp;
  // Process (algorithm)
  sumTemp = temp[0]+temp[1]+temp[2]+temp[3]+temp[4];
  avgTemp = sumTemp / 5.0;
  // Output
  Serial.print("Temperature:");
  Serial.print(temp[0]);
  Serial.print(",");
  Serial.print(temp[1]);
  Serial.print(",");
  Serial.print(temp[2]);
  Serial.print(",");
  Serial.print(temp[3]);
  Serial.print(",");
  Serial.println(temp[4]);
  Serial.print("Sum of temperature:");
  Serial.println(sumTemp);
  Serial.print("Average of temperature:");
  Serial.println(avgTemp);
}

void loop() {
}

จากโปรแกรมทั้ง 2 โปรแกรมให้ผลลัพธ์ของการทำงานเป็นดังนี้

สรุป

จากบทความนี้ผู้อ่านได้เรียนรู้เกี่ยวกับตัวแปร ค่าคงที่ และประเภทของข้อมูล พร้อมทั้งวิธีการประกาศตัวแปร/ค่าคงที่ รวมถึงเรื่องของโครงสร้างข้อมูลสำหรับใช้กับ Arduino ซึ่งเป็นพื้นฐานสำหรับใช้อ้างอิงในการเขียนโปรแกรม C++ ในบทความถัดไป สุดท้ายพวกเราหวังว่าผู้อ่านคงยังคงสนุกกับการเขียนโปรแกรมครับผม

เอกสารอ้างอิง

(C) 2020-2021, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ
ปรับปรุงเมื่อ 2021-05-23, 2021-06-08, 2021-09-18