Unicon03-047076

Page 1

Unicon  47

   ในการเขียนโปรแกรมสําหรับบอรด Unicon จะตองเขียนโปรแกรมโดยใชภาษาของ Arduino (Arduino programming language) ซึงตั ่ วภาษาของ Arduino เองก็นําเอาโอเพนซอรสโปรเจ็กตชื่อ wiring มาพัฒนาตอ ภาษาของ Arduino แบงไดเปน 2 สวนหลักคือ 1. โครงสรางภาษา (structure) ตัวแปรและคาคงที่ 2. ฟงกชั่น (function) ภาษาของ Arduino จะอางอิงตามภาษา C/C++ จึงอาจกลาวไดวาการเขียนโปรแกรมสําหรับ Arduino (ซึ่งก็รวมถึงบอรด UNicon) ก็คือการเขียนโปรแกรมภาษา C โดยเรียกใชฟงกชั่นและไลบรารีที่ทาง Arduino ไดเตรียมไวใหแลว ซึงสะดวก ่ และทําใหผูที่ไมมีความรูดานไมโครคอนโทรลเลอรอยางลึกซึง้ สามารถเขียน โปรแกรมสังงานได ่ ในบทนีจะอธิ ้ บายถึงโครงสรางโปรแกรมของ Arduino สําหรับผูอานที่มีพื้นความรูเกียวกั ่ บภาษา C ใหอานหัวขอ 3.1 แลวสามารถขามไปยังบทที่ 5 เพื่อทดลองเขียนโปรแกรมไดทันที

 โปรแกรมของ Arduino แบงไดเปนสองสวนคือ และ void setup() void loop()

โดยฟงกชัน่ setup() เมือโปรแกรมทํ ่ างานจะทําคําสังของฟ ่ งกชันนี ่ เพี ้ ยงครังเดี ้ ยว ใชในการกําหนดคา เริมต ่ นของการทํางาน สวนฟงกชัน่ loop() เปนสวนทํางาน โปรแกรมจะทําคําสังในฟ ่ งกชันนี ่ ต้ อเนืองกั ่ นตลอด เวลา โดยปกติใชกําหนดโหมดการทํางานของขาตางๆ กําหนดการสือสารแบบอนุ ่ กรม ฯลฯ สวนของ loop() เปนโคดโปรแกรมทีทํ่ างาน เชน อานคาอินพุต ประมวลผล สังงานเอาต ่ พุต ฯลฯ โดยสวนกําหนดคาเริมต ่ นเชน ตัวแปร จะตองเขียนทีส่ วนหัวของโปรแกรม กอนถึงตัวฟงกชัน่ นอกจากนันยั ้ งตองคํานึงถึงตัวพิมพเล็ก-ใหญของ ตัวแปรและชือฟ ่ งกชันให ่ ถูกตอง


48 

Unicon

3.1.1 สวนของฟงกชัน่ setup() ฟงกชั่นนี้จะเขียนที่สวนตนของโปรแกรม ทํางานเมือโปรแกรมเริ ่ ่มตนเพียงครั้งเดียว ใชเพื่อกําหนด คาของตัวแปร โหมดการทํางานของขาตางๆ เริ่มตนเรียกใชไลบรารี ฯลฯ ตัวอยางที่ 3-1 int buttonPin = 31; void setup() { Serial.begin(9600); pinMode(buttonPin, INPUT); } void loop() { if (digitalRead(buttonPin) == HIGH) Serial.println('H'); else Serial.println('L'); delay(1000); }

ในขณะที่โปรแกรมภาษา C มาตรฐานที่เขียนบน AVR GCC (เปนโปรแกรมภาษา C ทีใช ่ C คอมไพ เลอรแบบ GCC สําหรับไมโครคอนโทรลเลอร AVR) จะเขียนไดดังนี้ int main(void) { init(); setup();

ตรงกับ void

setup()

for (;;) loop();

ตรงกับ void

loop()

return ; }


Unicon  49

3.1.2 สวนของฟงกชัน่ loop() หลังจากทีเขี ่ ยนฟงกชั่น setup()ทีกํ่ าหนดคาเริมต ่ นของโปรแกรมแลว สวนถัดมาคือฟงกชั่น loop() ซึงมี ่ การทํางานตรงตามชือคื ่ อ จะทํางานตามฟงกชันนี ่ วนต ้ อเนืองตลอดเวลา ่ ภายในฟงกชันนี ่ จะมี ้ โปรแกรมของ ผูใช เพื่อรับคาจากพอรต ประมวล แลวสังเอาต ่ พุตออกขาตางๆ เพื่อควบคุมการทํางานของบอรด ตัวอยางที่ 3-2 int buttonPin = 31; // setup initializes serial and the button pin void setup() { Serial.begin(9600); pinMode(buttonPin, INPUT); } // loop checks the button pin each time, // and will send serial if it is pressed void loop() { if (digitalRead(buttonPin) == HIGH) Serial.println('H'); else Serial.println('L'); delay(1000); }

โปรแกรมจะวนทํางานในฟงกชั่น loop() ตลอดเวลา หลังจากทํางานใน ฟ งก ชั่ น setup() จึ งอาจสรุ ปได วา ฟ งก ชั่ น setup() คื อ ส วนตนของ โปรแกรมที่ใชในการประกาศ หรือตั้งคาการทํางานในตอนเริ่มตนทํางาน ในขณะที่ ฟงก ชั่ น loop() เป นเสมื อนส วนของโปรแกรมหลั กที่ ต องวน ทํางานอยางตอเนื่องตลอดเวลา อย างไรก็ตาม ในบางโปรแกรมอาจมีเฉพาะสวนของฟงกชั่น setup() และไมมีฟงกชั่น loop() ก็ได นั่นแสดงวา โปรแกรมนั้นๆ ตองการตั้งคา การทํางานหรื อกํ าหนดให มี การทํางานเพี ยงครั้ ง หรื อรอบเดี ยว แล ว จบการทํางานทันที


50 

Unicon

 3.2.1 คําสั่ง if ใชทดสอบเพื่อกําหนดเงือนไขการทํ ่ างานของโปรแกรม เชน ถาอินพุตมีคามากกวาคาที่กําหนดไวจะ ใหทําอะไร โดยมีรูปแบบการเขียนดังนี้ if (someVariable > 50) { // do something here }

ตัวโปรแกรม จะทดสอบวาถาตัวแปร someVariable มีคามากกวา 50 หรือไม ถาใชใหทําอะไร ถาไม ใชใหขามการทํางานสวนนี้ การทํางานของคําสั่งนีจะทดสอบเงื ้ ่อนไข ที่เขียนในเครื่องหมายวงเล็บ ถาเงื่อนไขเปนจริง ทําตามคํา สั่งที่เขียนในวงเล็บปกกา ถาเงื่อนไขเปนเท็จ ขามการทํางานสวนนีไป ้ สวนของการทดสอบเงือนไขที ่ เขี ่ ยนอยูภายในวงเล็บ จะตองใชตัวกระทําเปรียบเทียบตางๆ ดังนี้ x == y (x เทากับ y) x != y (x ไมเทากับ y) x < y (x นอยกวา y) x > y (x มากกวา y) x <= y (x นอยกวาหรือเทากับ y) x >= y (x มากกวาหรือเทากับ y) เทคนิคสําหรับการเขียนโปรแกรม ในการเปรียบเทียบตัวแปรใหใชตัวกระทํา == (เชน if (x==10) ) หามเขียนผิดเปน = (เชน if(x=10) ) คําสั่งที่เขียนผิดในแบบที่สองนี้ ทําใหผลการทดสอบเปนจริงเสมอ และเมื่อผานคําสั่งนีแล ้ ว x มีคาเทากับ 10 ทําใหการทํางานของโปรแกรมผิดเพียนไป ้ ไมเปนตามที่กําหนดไว เราสามารถใชคําสั่ง if ในคําสั่งควบคุมการแยกเสนทางของโปรแกรม โดยใชคําสั่ง if....else


Unicon  51

3.2.2 คําสั่ง

if...else

ใชทดสอบเพื่อกําหนดเงื่อนไขการทํางานของโปรแกรมไดมากกวาคําสัง่ if ธรรมดา โดยสามารถ กําหนดไดวา ถาเงื่อนไขเปนจริงใหทําอะไร ถาเปนเท็จใหทําอะไร เชน ถาคาอินพุตอะนาลอกที่อานไดนอย กวา 500 ใหทําอะไร ถาคามากกวาหรือเทากับ 500 ใหทําอีกอยาง จะเขียนคําสั่งไดดังนี้ ตัวอยางที่ 3-3 if (pinFiveInput < 500) { // do Thing A } else { // do Thing B }

หลังคําสั่ง else สามารถตามดวยคําสั่ง if สําหรับการทดสอบอื่นๆ ทําใหรูปแบบคําสังกลายเป ่ น if....else...if เปนการทดสอบเงื่อนไขตางๆ เมื่อเปนจริงใหทําตามที่ตองการ ดังตัวอยางตอไปนี้ ตัวอยางที่ 3-4 if (pinFiveInput < 500) { // do Thing A } else if (pinFiveInput >= 1000) { // do Thing B } else { // do Thing C }

หลังคําสัง่ else สามารถตามดวยคําสั่ง if ไดไมจํากัดจํานวน (สามารถใชคําสั่ง switch case แทนคําสั่ง if...else...if สําหรับการทดสอบเงื่อนไขจํานวนมากๆ ได) ่ เลย ใหทําอะไร เมื่อใช คําสั่ง if...else แลว ตองกําหนดดวยวาถาทดสอบไมตรงกับเงือนไขใดๆ โดยใหกําหนดที่คําสั่ง else ตัวสุดทาย


52 

Unicon

3.2.3 คําสั่ง

for()

คําสังนี ่ ใช ้ เพือสั ่ งให ่ คําสังที ่ อยู ่ ภายในวงเล็  บปกกาหลัง for มีการทํางานซํากั ้ นตามจํานวนรอบทีต่ องการ คําสังนี ่ มี้ ประโยชนมากสําหรับการทํางานใดๆ ทีต่ องทําซํากั ้ นและทราบจํานวนรอบของการทําซําที ้ แน ่ นอน มักใช คูกั บตัวแปรอะเรยในการเก็บสะสมคาทีอ่ านไดจากขาอินพุตอะนาลอกหลายๆ ขาทีมี่ หมายเลขขาตอเนืองกั ่ น รูปแบบของคําสั่ง for() แบงได 3 สวนดังนี้ for (initialization; condition; increment) { //statement(s); }

เริ่มตนดวย initialization ใชกําหนดคาเริมต ่ นของตัวแปรควบคุมการวนรอบ ในการทํางานแตละรอบ ่ อลดคาตัวแปรตามที่สั่ งใน จะทดสอบ condition ถ าเงื่อนไขเปนจริงทําตามคําสั่งในวงเล็บปกกา แลวมาเพิมหรื ่ ก ทําซํ้าจนกวาเงือนไขเป ่ นเท็จ increment แลวทดสอบเงือนไขอี ตัวอยางที่ 3-5 for (int i=1; i <= 8; i++) { // statement using the value i; }

คําสัง่ for ของภาษา C ยืดหยุนกว  าคําสัง่ for ของภาษาคอมพิวเตอรอืนๆ ่ มันสามารถละเวนบางสวน หรือทังสามส ้ วนของคําสัง่ for ได อยางไรก็ตามยังตองมีเซมิโคลอน นอกจากนั้นยังนําคําสังภาษา ่ C++ ทีมี่ ตัวแปร ทีไม ่ เกียวข ่ องมาเขียนในสวนของ initialization, condition และ increment ของคําสัง่ for ได

3.2.4 คําสั่ง

switch-case

ใชทดสอบเงื่อนไขเพื่อกําหนดการทํางานของโปรแกรม ถาตัวแปรที่ทดสอบตรงกับเงื่อนไขใดก็ให ทํางานตามที่กําหนดไว พารามิเตอร var ตัวแปรทีต ่ องการทดสอบวาตรงกับเงื่อนไขใด default ถาไมตรงกับเงือนไขใดๆ ่ เลยใหทําคําสังต ่ อทายนี้ break เปนสวนสําคัญมาก ใชเขียนตอทาย case ตางๆ เมือพบเงื ่ อนไขนั ่ นแล ้ วทําตามคําสังต ่ างๆ แล วใหหยุดการทํางานของคําสั่ง switch-case ถาลื มเขียน break เมื่อพบเงื่อนไขทําตามเงื่อนไขแลว โปรแกรมจะทํางานตามเงื่อนไขตอไปเรือยๆ ่ จนกวาจะพบคําสั่ง break


Unicon  53

ตัวอยางที่ 3-6 switch (var) { case 1: //do something when var == 1 break; case 2: //do something when var == 2 break; default: // if nothing else matches, do the default }

3.2.5 คําสั่ง while เปนคําสังวนรอบ ่ โดยจะทําคําสังที ่ ่เขียนในวงเล็บปกกาอยางตอเนือง ่ จนกวาเงือนที ่ เขี ่ ยนในวงเล็บของ คําสั่ง while() จะเปนเท็จ คําสั่งที่ใหทําซํ้าจะตองมีการเปลียนแปลงค ่ าตัวแปรที่ใชทดสอบ เชน มีการเพิ่ม คาตัวแปร หรือมีเงื่อนไขภายนอก เชน อานคาจากตัวตรวจจับไดเรียบรอยแลว ใหหยุดการอานคา มิฉะนั้น เงื่อนไขในวงเล็บของ while() เปนจริงตลอดเวลา ทําใหคําสั่ง while ทํางานวนรอบไปเรื่อยๆ ไมรูจบ รูปแบบคําสัง่ while(expression) { // statement(s) }

พารามิเตอร expression

เปนคําสั่งทดสอบเงื่อนไข (ถูกหรือผิด)

ตัวอยางที่ 3-7 var = 0; while(var < 200) { // do something repetitive 200 times var++; }


54 

Unicon

 ประกอบดวยตัวกระทํา 5 ตัวคือ + (บวก),- (ลบ), * (คูณ), / (หาร) และ % (หารเอาเศษ)

3.3.1 ตัวกระทําทางคณิตศาสตร บวก ลบ คูณ และหาร ใชหาคาผลรวม ผลตาง ผลคูณ และผลหารคาของตัวถูกกระทําสองตัว โดยใหคําตอบมีประเภทตรงกับ ตัวถูกกระทําทั้งสองตัว เชน 9/4 ใหคําตอบเทากับ 2 เนืองจากทั ่ ้ง 9 และ 4 เปนตัวแปรเลขจํานวนเต็ม (int) นอกจากนีตั้ วกระทําทางคณิตศาสตรอาจทําใหเกิดโอเวอรโฟลว (overflow) ถาผลลัพธทีได ่ มีขนาดใหญ เกินกวาจะสามารถเก็บในตัวแปรประเภทนัน้ ถาตัวทีถู่ กกระทําตางประเภทกันผลลัพธไดเปนจะมีขนาดใหญขึน้ เทากับประเภทของตัวแปรทีใหญ ่ ทีสุ่ ด (เชน 9/4 = 2 หรือ 9/4.0 = 2.25) รูปแบบคําสัง่ result = value1 + value2; result = value1 - value2; result = value1 * value2; result = value1 / value2;

พารามิเตอร value1 : เปนคาของตัวแปรหรือคาคงที่ใดๆ value2: เปนคาของตัวแปรหรือคาคงที่ใดๆ ตัวอยางที่ 3-8 y = y + 3; x = x - 7; i = j * 6; r = r / 5;

เทคนิคสําหรับการเขียนโปรแกรม  เลือกขนาดของตัวแปรใหใหญพอสําหรับเก็บคาผลลัพธที่มากที่สุดของการคํานวณ ้ ากลับ และวนกลับอยางไร ตัวอยางเชน (0 ไป 1)  ตองทราบวาที่คาใดตัวแปรที่เก็บจะมีการวนซําค หรือ (0 ไป -32768)  สําหรับการคําณวณที่ตองการเศษสวนใหใชตัวแปรประเภท float แตใหระวังผลลบเชน ตัวแปรมี ขนาดใหญ คํานวณไดชา  ใชตัวกระทํา cast เชน (int)myfloat ในการเปลียนประเภทของตั ่ วแปรชัวคราวขณะที ่ โปรแกรม ่ ทํางาน


Unicon  55

3.3.2 ตัวกระทํา % หารเอาเศษ ใชหาคาเศษที่ไดของการหารเลขจํานวนเต็ม 2 ตัว ตัวกระทําหารเอาเศษไมสามารถใชงานกับตัวแปร เลขทศนิยม (float) รูปแบบคําสัง่ result = value1 % value2;

พารามิเตอร value1 - เปนตัวแปรประเภท byte,char,int หรือ long value2 - เปนตัวแปรประเภท byte,char,int หรือ long ผลที่ได เศษจากการหารคาเลขจํานวนเต็ม เปนขอมูลชนิดเลขจํานวนเต็ม ตัวอยางที่ 3-9 x = 7 % 5; x = 9 % 5;

// x now contains 2 // x now contains 4

x = 5 % 5;

// x now contains 0

x = 4 % 5;

// x now contains 4

ตัวกระทําหารเอาเศษนีใช ้ ประโยชนมาก ในงานทีต่ องการใหเหตุการณเกิดขึนด ้ วยชวงเวลาทีสมํ ่ าเสมอ ่ หรือใชทําใหหนวยความจําทีเก็ ่ บตัวแปรอะเรยเกิดการลนคากลับ (roll over) ตัวอยางที่ 3-10 // check a sensor every 10 times through a loop void setup() { i++; if ((i % 10) == 0) { x = analogRead(sensPin); // read sensor every ten times through loop } } // setup a buffer that averages the last five samples of a sensor int senVal[5]; // create an array for sensor data int i, j; // counter variables long average; // variable to store average ... void loop() { // input sensor data into oldest memory slot sensVal[(i++) % 5] = analogRead(sensPin); average = 0; for (j=0; j<5; j++) { average += sensVal[j]; // add samples } average = average / 5; // divide by total }


56 

Unicon

  ใชประกอบกับคําสั่ง if() และ while() เพื่อทดสอบเงื่อนไขหรือเปรียบเทียบคาตัวแปรตาง โดย จะเขียนเปนนิพจนอยูภายในเครื่องหมาย () x == y (x เทากับ y) x != y (x ไมเทากับ y) x < y (x นอยกวา y) x > y (x มากกวา y) x <= y (x นอยกวาหรือเทากับ y) x >= y (x มากกวาหรือเทากับ y)

 ใชในการเปรียบเทียบของคําสั่ง if() มี 3 ตัวคือ &&, || และ !

3.5.1 && (ตรรกะ และ) ใหคาเปนจริงเมื่อผลการเปรียบเทียบทั้งสองขางเปนจริงทั้งคู ตัวอยางที่ 3-11 if (x > 0 && x < 5) { // ... }

ใหคาเปนจริงเมื่อ x มากกวา 0 และนอยกวา 5 (มีคา 1 ถึง 4)

3.5.2 && (ตรรกะ หรือ) ใหคาเปนจริง เมื่อผลการเปรียบเทียบพบวา มีตัวแปรใดเปนจริงหรือเปนจริงทั้งคู ตัวอยางที่ 3-12 if (x > 0 || y > 0) { // ... }

ใหผลเปนจริงเมื่อ x หรือ y มีคามากกวา 0


Unicon  57

3.5.3 ! (ใชกลับผลเปนตรงกันขาม) ใหคาเปนจริง เมื่อผลการเปรียบเทียบเปนเท็จ ตัวอยางที่ 3-13 if (!x) { // ... }

ใหผลเปนจริงถา x เปนเท็จ (เชน ถา x = 0 ใหผลเปนจริง)

3.5.4 ขอควรระวัง && ถาลืมเขียน ระวังเรืองการเขี ่ ยนโปรแกรม ถาตองการใชตัวกระทําตรรกะและ ตองเขียนเครืองหมาย ่ เปน & จะเปนตัวกระทําและระดับบิตกับตัวแปร ซึงให ่ ผลที่แตกตาง เชนกันในการใชตรรกะหรือใหเขียนเปน || (ขีดตั้งสองตัวติดกัน) ถาเขียนเปน | (ขีดตังตั ้ วเดียว) จะหมายถึงตัวกระทําหรือระดับบิตกับตัวแปร ตัวกระทํา NOT ระดับบิต (~) จะแตกตางจากตัวกลับผลใหเปนตรงขาม (!) ใหเลือกใชใหถูกตอง ตัวอยางที่ 3-14 if (a >= 10 && a <= 20){} // true if a is between 10 and 20

  ตัวกระทํ าระดับจะนําบิ ตของตัวแปรมาประมวลผล ใชประโยชนในการแกปญหาดานการเขียน โปรแกรมไดหลากหลาย ตัวกระทําระดับของภาษา C (ซึ่งรวมถึง Arduino) มี 6 ตัวไดแก & (bitwise AND), ่ ตไปทางขวา) และ >> (เลือนบิ ่ ตไปทางซาย) | (OR), ^ (Exclusive OR), ~ (NOT), << (เลือนบิ

3.6.1 ตัวกระทําระดับบิต AND (&) คําสัง่ AND ในระดับบิตของภาษา C เขียนไดโดยใช & หนึงตั ่ ว โดยตองเขียนระหวางนิพจนหรือตัว แปรที่เป นเลขจํานวนเต็ม การทํางานจะนําขอมูลแตละบิตของตัวแปรทั้งสองตัวมากระทําทางตรรกะและ (AND) โดยมีกฎดังนี้ ถาอินพุตทังสองตั ้ วเปน “1” ทั้งคูเอาต  พุตเปน “1” กรณีอืนๆ ่ เอาตพุตเปน “0” ดังตัวอยางตอไปนี้ ใน การดูใหคูของตั  วกระทําตามแนวตัง้ 0 0

0 1

1 0

1 1

Operand1 Operand2

—————————— 0

0

0

1

Returned result


58 

Unicon

ใน Arduino ตัวแปรประเภท int จะมีขนาด 16 บิต ดังนันเมื ้ อใช ่ ตัวกระทําระดับบิต AND จะมีการกระทํา ตรรกะและพรอมกันกับขอมูลทั้ง 16 บิต ดังตัวอยางในสวนของโปรแกรมตอไปนี้ ตัวอยางที่ 3-15 int a =

92; // in binary: 0000000001011100

int b = 101; // in binary: 0000000001100101 int c = a & b;

// result: 0000000001000100 // or 68 in decimal.

ในตัวอยางนี้จะนําขอมูลทัง้ 16 บิตของตัวแปร a และ b มากระทําทางตรรกะ AND แลวนําผลลัพธ ทีได ่ ทัง้ 16 บิตไปเก็บที่ตัวแปร c ซึงได ่ คาเปน 01000100 ในเลขฐานสองหรือเทากับ 68 ฐานสิบ นิยมใชตัวกระทําระดับบิต AND เพือเลื ่ อกขอมูลบิตทีต่ องการ (อาจเปนหนึงบิ ่ ตหรือหลายบิต) จากตัวแปร int ซึงการเลื ่ อกเพียงบางบิตนีจะเรี ้ ยกวา masking

3.6.2 ตัวกระทําระดับบิต OR (|) คําสังระดั ่ บบิต OR ของภาษาซีเขียนไดโดยใชเครืองหมาย ่ ่ ว โดยตองเขียนระหวางนิพจนหรือตัว |หนึงตั แปรทีเป ่ นเลขจํานวนเต็ม การทํางานจะนําขอมูลแตละบิตของตัวแปรทังสองตั ้ วมากระทําทางตรรกะหรือ (OR)โดย มีกฎดังนี้ ถาอินพุตตัวใดตัวหนึงหรื ่ อทังสองตั ้ วเปน “1” เอาตพุตเปน “1” กรณีทีอิ่ นพุตเปน “0” ทังคู ้ เอาต  พุตจึงจะ เปน “0” ดังตัวอยางตอไปนี้ 0

0

1

1

Operand1

0

1

0

1

Operand2

—————————— 0 1 1 1

Returned result

ตัวอยางที่ 3-16 สวนของโปรแกรมแสดงการใชตัวกระทําระดับบิต OR int a =

92; // in binary: 0000000001011100

int b = 101; // in binary: 0000000001100101 int c = a | b;

// result: 0000000001111101 // or 125 in decimal.

ตัวอยางที่ 3-17 โปรแกรมแสดงการใชตัวกระทําระดับบิต AND และ OR ตัวอยางงานทีใช ่ ตัวกระทําระดับบิต AND และ OR เปนงานที่โปรแกรมเมอรเรียกวา Read-ModifyWrite on a port สําหรับไมโครคอนโทรลเลอร 8 บิต คาทีอ่ านหรือเขียนไปยังพอรตมีขนาด 8 บิต ซึงแสดงค ่ า อินพุตที่ขาทัง้ 8 ขา การเขียนคาไปยังพอรตจะเขียนคาครั้งเดียวไดทัง้ 8 บิต ตัวแปรชือ่ PORTD เปนคาทีใช ่ แทนสถานะของขาดิจิตอลหมายเลข 0,1,2,3,4,5,6,7 ถาบิตใดมีคาเปน 1 ทําให ขานั้นมี ค าลอจิ กเปน HIGH (อย าลื มกําหนดใหขาพอรตนั้นๆ ทํางานเปนเอาตพุตดวยคําสั่ง pinMode() กอน) ดังนั้นถากําหนดคาให PORTD = B00110001; ก็คือตองการใหขา 2,3 และ 7 เปน


Unicon  59

HIGH ในกรณีนีไม ้ ตองเปลียนค ่ าสถานะของขา 0 และ 1 ซึงปกติ ่ แลวฮารดแวรของ Arduino ใชในการสื่อ สารแบบอนุกรม ถาไปเปลียนค ่ าแลวจะกระทบตอการสื่อสารแบบอนุกรม อัลกอริธึมสําหรับโปรแกรมเปนดังนี้  อานคาจาก PORTD แลวลางคาเฉพาะบิตที่ตองการควบคุม (ใชตัวกระทําแบบบิต AND) ่ ไขจากขางตนมารวมกับคาบิตที่ตองการควบคุม (ใชตัวกระทําแบบบิต OR)  นําคา PORTD ทีแก ซึ่งเขียนเปนโปรแกรมไดดังนี้ int i; // counter variable int j; void setup() { DDRD = DDRD | B11111100; // set direction bits for pins 2 to 7, // leave 0 and 1 untouched (xx | 00 == xx) // same as pinMode(pin,OUTPUT) for pins 2 to 7 Serial.begin(9600); } void loop() { for (i=0; i<64; i++) { PORTD = PORTD & B00000011; // clear out bits 2 - 7, leave pins 0 // and 1 untouched (xx & 11 == xx) j = (i << 2); // shift variable up to pins 2 - 7 // to avoid pins 0 and 1 PORTD = PORTD | j; // combine the port information with // the new information for LED pins Serial.println(PORTD, BIN); // debug to show masking delay(100); } }


60 

Unicon

3.6.3 คําสั่งระดับบิต Exclusive OR (^) เปนโอเปอรเตอรพิเศษที่ไมคอยไดใชในภาษา C/C++ ตัวกระทําระดับบิต exclusive OR (หรือ XOR) จะเขียนโดยใชสัญลักษณเครื่องหมาย ^ ตัวกระทํานีมี้ การทํางานใกลเคียงกับตัวกระทําระดับบิต OR แตตาง กันเมืออิ ่ นพุตเปน “1” ทั้งคูจะให  เอาตพุตเปน “0” แสดงการทํางานไดดังนี้ 0 0

0 1

1 0

1 1

—————————— 0 1 1 0

Operand1 Operand2 Returned result

หรื อกล าวได อี กอย างว า ตั วกระทํ าระดั บบิ ต XOR จะให เอาตพุ ต เปน “0” เมื่ออินพุตทังสองตั ้ วมีคาเหมือนกัน และใหเอาตพุตเปน “1” เมื่ออินพุตทังสองมี ้ คาตางกัน ตัวอยางที่ 3-18 int x = 12;

// binary: 1100

int y = 10; int z = x ^ y;

// binary: 1010 // binary: 0110, or decimal 6

ตัวกระทําระดับบิต XOR จะใชมากในการสลับคาบางบิตของตัวตัวแปร int เชน กลับจาก “0” เปน “1” หรือกลับจาก “1” เปน “0” เมื่อใชตัวกระทําระดับบิต XOR ถาบิตของ mask เปน “1” ทําใหบิตนั้นถูกสลับคา ถา mask มีคาเปน “1” บิตนั้นมีคาคงเดิม ตัวอยางตอไปนีเป ้ นโปรแกรมแสดงการสั่งใหขาดิจิตอล 5 (Di 5) มีการกลับลอจิกตลอด เวลา ตัวอยางที่ 3-19 // Blink_Pin_5 // demo for Exclusive OR void setup() { DDRD = DDRD | B00100000; // set digital pin five as OUTPUT Serial.begin(9600); } void loop() { PORTD = PORTD ^ B00100000; // invert bit 5 (digital pin 5), // leave others untouched delay(100); }


Unicon  61

3.6.4 ตัวกระทําระดับบิต NOT (~) ตัวกระทําระดับบิต NOT จะเขียนโดยใชสัญลักษณเครืองหมาย ่ ~ ตัวกระทํานีจะใช ้ งานกับตัวถูกกระทํา เพียงตัวเดียวที่อยูขวามือ โดยทําการสลับบิตทุกบิตใหมีคาตรงกันขามคือ จาก “0” เปน “1” และจาก “1” เปน “0” ดังตัวอยาง 0 1 —————

Operand1

1 0 ~ operand1 int a = 103; // binary: 0000000001100111 int b = ~a;

// binary: 1111111110011000

เมื่อกระทําแลว ทําใหตัวแปร b มีคา -104 (ฐานสิบ) ซึงคํ ่ าตอบที่ไดติดลบเนื่องจากบิตทีมี่ ความสําคัญ สูงสุด (บิตซายมือสุด) ของตัวแปร int อันเปนบิตแจงวาตัวเลขเปนบวกหรือลบ มีคาเปน “1” แสดงวา คาที่ได นีติ้ ดลบ โดยในคอมพิวเตอรจะเก็บคาตัวเลขทั้งบวกและลบตามระบบทูคอมพลีเมนต (2’s complement) การประกาศตัวแปร int ซึงมี ่ ความหมายเหมือนกับการประกาศตัวแปรเปน signed int ตองระวังคาของ ตัวแปรจะติดลบได

3.6.5 คําสั่งเลือนบิ ่ ตไปทางซาย (<<) และเลือนบิ ่ ตไปทางขวา (>>) ในภาษา C/C++ มีตัวกระทําเลื่อนบิตไปทางซาย << และเลื่อนบิตไปทางขวา >> ตัวกระทํานีจะสั ้ ง่ เลือนบิ ่ ตของตัวถูกกระทําทีเขี ่ ยนดานซายมือไปทางซายหรือไปทางขวาตามจํานวนบิตทีระบุ ่ ไวในดานขวามือ ของตัวกระทํา รูปแบบคําสัง่ variable << number_of_bits variable >> number_of_bits

พารามิเตอร variable เปนตัวแปรเลขจํานวนเต็มทีมี ่ จํานวนบิตนอยกวาหรือเทากับ 32 บิต (หรือตัวแปรประเภท byte, int หรือ long) ตัวอยางที่ 3-20 int a = 5;

// binary: 0000000000000101

int b = a << 3;

// binary: 0000000000101000, // or 40 in decimal

int c = b >> 3;

// binary: 0000000000000101, // or back to 5

ตัวอยางที่ 3-21 เมื่อสั่งเลื่อนคาตัวแปร x ไปทางซายจํานวน y บิต (x << y) บิตขอมูลทีอยู ่ ด านซายสุดของ x จํานวน y ตัวจะหายไป เนื่องจากถูกเลื่อนหายไปทางซายมือ int a = 5; int b = a << 14;

// binary: 0000000000000101 // binary: 0100000000000000


62 

Unicon

การเลื่อนบิตไปทางซายทําใหคาของตัวแปรดานซายมือของตัวกระทําถูกคูณดวยคาสองยกกําลังบิต ทีเลื ่ อนไปทางซ ่ ายมือ ดังนี้ 1 <<

0

==

1

1 << 1 <<

1 2

== ==

2 4

1 << ...

3

==

8

1 <<

8

==

256

1 << 9 1 << 10

== 512 == 1024

...

เมื่อสังเลื ่ ่อนตัวแปร x ไปทางขวามือจํานวน y บิต (x >> y) จะมีผลแตกตางกันขึ้นกับประเภทของ ตัวแปร ถา x เปนตัวแปรประเภท int คาที่เก็บไดมีทั้งคาบวกและลบ โดยบิตซายมือสุดจะเปน sign bit ถาเปน คาลบคาบิตซายมือสุดจะมีคาเปน 1 กรณีนีเมื ้ ่อสังเลื ่ ่อนบิตไปทางขวามือแลวโปรแกรมจะนําคา sign bit นีมา ้ เติมใหกับบิตทางซายมือสุดไปเรื่อยๆ ปรากฏการณนีเรี ้ ยกวา sign extension มีตัวอยางดังนี้ ตัวอยางที่ 3-22 int x = -16; int y = x >> 3;

// binary: 1111111111110000 // binary: 1111111111111110

ถาตองการเลือนบิ ่ ตไปทางขวามือแลวใหคา 0 มาเติมยังบิตซายมือสุด (ซึ่งจะเกิดกับกรณีที่ตัวแปรเปน ประเภท unsigned int) เราสามารถทําไดโดยใชการเปลียนประเภทตั ่ วแปรชั่วคราว (typecast) เพื่อเปลี่ยนใหตัว แปร x เปน unsigned int ชั่วคราวดังตัวอยางตอไปนี้ int x = -16;

// binary: 1111111111110000

int y = unsigned(x) >> 3; // binary: 0001111111111110

ถาคุณระมัดระวังเรื่อง sign extension แลว คุณสามารถใชตัวกระทําเลื่อนบิตไปทางขวามือสําหรับการ หารคาตัวแปรดวย 2 ยกกําลังตางๆ ไดดังตัวอยาง int x = 1000; int y = x >> 3;

// integer division of // 1000 by 8, causing y = 125.


Unicon  63

 3.7.1

;

(เซมิโคลอน - semicolon)

ใชเขียนแจงวา จบคําสั่ง ตัวอยางที่ 3-23 int a = 13;

บรรทัดคําสั่งที่ลืมเขียนปดทายดวยเซมิโคลอน จะทําใหแปลโปรแกรมไมผาน โดยตัวแปรภาษาอาจ จะแจงใหทราบวา ไมพบเครื่องหมายเซมิโคลอน หรือแจงเปนการผิดพลาดอืนๆ ่ บางกรณีทีตรวจสอบบรรทั ่ ด ที่แจงวาเกิดการผิดพลาดแลวไมพบที่ผิด ใหตรวจสอบบรรทัดกอนหนานัน้

3.7.2 {

}

(วงเล็บปกกา - curly brace)

เครื่องหมายวงเล็บปกกา เปนสวนสําคัญของภาษาซี โดยมีการใชงานตางตําแหนง สรางความสับสน ใหกับผูที่เริ่มตน วงเล็บป กกาเปด { จะตองเขียนตามดวยวงเล็บปกกาปด } ดวยเสมอ หรือที่เรียกวาวงเล็บตองครบคู ในซอฟตแวร Arduino IDE ที่ใชเขียนโปรแกรมจะมีความสามารถในการตรวจสอบการครบคูของเครื  องหมาย ่ วงเล็บ ผูใชงานเพียงแคคลิกที่วงเล็บ มันจะแสดงวงเล็บที่เหลือซึงเป ่ นคูของมัน สําหรับโปรแกรมเมอรมือใหม และโปรแกรมเมอรทีย่ ายจากภาษา BASIC มาเปนภาษา C มักจะสับสน กับการใชเครื่องหมายวงเล็บ แทที่จริงแลวเครื่องหมายปกกาปดนี้เทียบไดกับคําสั่ง RETURN ของ subroutine (function) หรือแทนคําสั่ง ENDIF ในการเปรียบเทียบ และแทนคําสั่ง NEXT ของคําสั่งวนรอบ FOR เนืองจากมี ่ การใชวงเล็บปกกาไดหลากหลาย ดังนันเมื ้ อต ่ องการเขียนคําสังที ่ ต่ องใชเครืองหมายวงเล็ ่ บ เมือ่ เขียนวงเล็บเปดแลวใหเขียนเครื่องหมายวงเล็บปดทันที ถัดมาจึงคอยเคาะปุม Enter ในระหวางเครื่องหมาย วงเล็บเพือขึ ่ นบรรทั ้ ดใหม แลวเขียนคําสังที ่ ต่ องการ ถาทําไดตามนีวงเล็ ้ บจะครบคูแน  นอน สําหรับวงเล็บที่ไมครบคู ทําใหเกิดการผิดพลาดตอนคอมไพลโปรแกรม ถาเปนโปรแกรมขนาดใหญ จะหาที่ ผิ ดไดยาก ตําแหนงที่ อยู ของเครื่องหมายวงเล็บแตละตัวจะมีผลอยางมากตอไวยากรณของภาษา คอมพิวเตอร การยายตําแหนงวงเล็บไปเพียงหนึงหรื ่ อสองบรรทัด ทําใหตัวโปรแกรมทํางานผิดไป


64 

Unicon

ตําแหนงที่ใชวงเล็บปกกา ฟงกชั่น (Function) void myfunction(datatype argument){ statements(s) }

คําสั่งวนรอบ (Loops) while (boolean expression) { statement(s) } do { statement(s) } while (boolean expression); for (initialisation; termination condition; incrementing expr) { statement(s) }

คําสั่งทดสอบเงือนไข ่ (condition) if (boolean expression) { statement(s) } else if (boolean expression) { statement(s) } else { statement(s) }

3.7.3 // และ /*...* หมายเหตุบรรทัดเดียวและหลายบรรทัด เปนสวนของโปรแกรมทีผู่ ใชเขียนเพิมเติ ่ มวาโปรแกรมทํางานอยางไร โดยสวนทีเป ่ นหมายเหตุจะไม ถูกคอมไพล ไมนําไปประมวลผล มีประโยชนมากสําหรับการตรวจสอบโปรแกรมภายหลังหรือใชแจงใหเพือน ่ รวมงานหรือบุคคลอืนทราบว ่ าบรรทัดนี้ใชทําอะไร ตัวหมายเหตุภาษา C มี 2 ประเภทคือ (1) หมายเหตุบรรรทัดเดียว เขียนเครื่องสเลช // 2 ตัวหนาบรรทัด (2) หมายเหตุหลายบรรทัด เขียนเครื่องหมายสเลช / คูกั บดอกจัน * ครอมขอความที่เปนหมายเหตุ เชน /* blabla */


Unicon  65

3.7.4 #define เปนคําสั่งทีใช ่ งานมาก ในการกําหนดคาคงที่ใหกับโปรแกรม ในการกําหนดคาคงทีไม ่ ไดเปลืองพื้นที่ หนวยความจําของไมโครคอนโทรลเลอรแตอยางไร เมื่อถึงขันตอนแปลภาษาคอมไพเลอร ้ จะแทนที่ตัวอักษร ขอความดวยคาที่กําหนดไว ใน Arduino จะใช คําสั่ง #define ตรงกับภาษา C รูปแบบ #define constantName value

อยาลืมเครืองหมาย ่ # ตัวอยางที่ 3-24 #define ledPin 3

เปนการกําหนดใหตัวแปร ledPin เทากับคาคงที่ 3 เทคนิคสําหรับการเขียนโปรแกรม ทายคําสั่ง #define ไมตองมีเครื่องหมายเซมิโคลอน ถาใสเกินแลวเวลาคอมไพลโปรแกรมจะแจง วาเกิดการผิดพลาดในบรรทัดถัดไป

3.7.5 #include ใชสังให ่ รวมไฟลอืนๆ ่ เขากับไฟลโปรแกรมหลักกอน แลวจึงทําการคอมไพลโปรแกรม รูปแบบคําสัง่ #include <file> #include “file”

ตัวอยางที่ 3-25 #include <stdio.h> #include "lcd.h"

บรรทัดแรกจะสั่งใหเรียกไฟล stdio.h มารวมกับไฟลโปรแกรมหลัก โดยคนหาไฟลจากตําแหนงทีเก็ ่ บ ไฟลระบบของ Arduino โดยปกติเปนไฟลมาตรฐานที่มาพรอมกับ Arduino บรรทัดที่ 2 สั่งใหรวมไฟล lcd.h มารวมกับไฟลโปรแกรมหลัก โดยหาไฟลจากตําแหนงที่อยูของไฟล  ภาษา C หลักกอน ปกติเปนไฟลทีผู่ ใชสรางขึ้นเอง

Unicon-Note3/1 ในการแกไขโปรแกรมใน Arduino มีขอแนะนําวา อยาแกไขบรรทัดนั้นทันที ใหทําบรรทัดนั้นเปนหมายเหตุกอน แลวจึงแกไขโปรแกรมในบรรทัดนั้น


66 

Unicon

 ตัวแปรเปนตัวอักษรหลายตัวๆ ทีกํ่ าหนดขึนในโปรแกรมเพื ้ อใช ่ ในการเก็บคาขอมูลตางๆ เชน คาทีอ่ าน ไดจากเตัวตรวจจับที่ตออยูกับขาพอรตอะนาลอกของ Arduino ตัวแปรมีหลายประเภทดังนี้

3.8.1 char : ตัวแปรประเภทตัวอักขระ เปนตัวแปรที่มีขนาด 1 ไบต (8 บิต) มีไวเพื่อเก็บคาตัวอักษร ตัวอักษรในภาษาซีจะเขียนอยูในเครื่อง หมายคําพูดขีดเดียว เชน ‘A’ (สําหรับขอความ ที่ประกอบจากตัวอักษรหลายตัวเขียนตอกันจะเขียนอยูในเครือง ่ หมายคําพูดปกติ เชน “ABC”) คุณสามารถสังกระทํ ่ าทางคณิตศาสตรกับตัวอักษรได ในกรณีจะนําคารหัส ASCII ของตัวอักษรมาใช เชน ‘A’ +1 มีคาเทากับ 66 เนืองจากค ่ ารหัส ASCII ของตัวอักษร A เทากับ 65 รูปแบบคําสัง่ char sign = ' ';

พารามิเตอร char var = ‘x’;

คือชือของตั ่ วแปรประเภท char ทีต่ องการ ่ องการกําหนดใหกับตัวแปร ในทีนี่ เป ้ นตัวอักษรหนึงตั ่ ว x คือคาทีต var

3.8.2 byte : ตัวแปรประเภทตัวเลบ 8 บิตหรือ 1 ไบต ตัวแปร byte ใชเก็บคาตัวเลขขนาด 8 บิต มีคาไดจาก 0 - 255 ตัวอยางที่ 3-26 byte b = B10010111;

// “B” is the binary formatter (151 decimal)

3.8.3 int : ตัวแปรประเภทตัวเลขจํานวนเต็ม ยอจาก interger ซึงแปลว ่ าเลขจํานวนเต็ม int เปนตัวแปรพื้นฐานสําหรับเก็บตัวเลข ตัวแปรหนึงตั ่ วมี ขนาด 2 ไบต เก็บคาไดจาก -32,768 ถึง 32,767 (คาตําสุ ่ ดจาก -215 คาสูงสุดจาก (215- 1) ในการเก็บคาตัวเลขติดลบ จะใชเทคนิคที่เรียกวา ทูคอมพลีเมนต (2’s complement) บิตสูงสุดบางที จะเรียกวาเปนบิตเครื่องหมายหรือ sign bit ถามีคาเปน “1” แสดงวาคาติดลบ ใน Arduino จะจัดการกับตัวเลขคาติดลบใหเอง ทําใหนําคาตัวแปรไปคํานวณไดอยางถูกตอง อยางไร ก็ตามเมื่อนําตัวเลขคาติดลบนี้ไปเลือนบิ ่ ตไปทางขวา (>>) จะมีปญหาเรื่องคาของตัวเลขที่ผิดพลาด รูปแบบคําสัง่ int var = val;

พารามิเตอร ่ วแปรประเภท int ทีต่ องการ var คือชือของตั ่ องการกําหนดใหกับตัวแปร val คือคาทีต


Unicon  67

ตัวอยางที่ 3-27 int ledPin = 31;

เทคนิคสําหรับการเขียนโปรแกรม เมื่อตัวแปรมีคามากกวาคาสูงสุดที่เก็บได จะเกิดการ “ลนกลับ” (roll over) ไปยังคาตํ่าสุดที่เก็บได และเมื่อมีคานอยกวาคาตํ่าสุดที่เก็บไดจะลนกลับไปยังคาสูงสุด ดังตัวอยางตอไปนี้ ตัวอยางที่ 3-28 int x x = -32,768; x = x - 1; x = 32,767; x = x + 1;

// x now contains 32,767 // - rolls over in neg. direction // x now contains -32,768 - rolls over

3.8.4 unsigned int : ตัวแปรประเภทเลขจํานวนเต็มไมคิดเครื่องหมาย ตัวแปรประเภทนีคล ้ ายกับตัวแปร int ตรงทีใช ่ หนวยความจํา 2 ไบต แตจะเก็บเลขจํานวนเต็มบวกเทานัน้ โดยเก็บคา 0 ถึง 65,535 (216 -1) รูปแบบคําสัง่ unsigned int var = val;

พารามิเตอร คือชือของตั ่ วแปร int ทีต่ องการ ่ องการกําหนดใหกับตัวแปร val คือคาทีต ตัวอยางที่ 3-29 var

unsigned int ledPin = 31;

เทคนิคสําหรับการเขียนโปรแกรม เมือตั ่ วแปรมีคามากกวาคาสูงสุดจะลนกลับไปคาตําสุ ่ ด และเมือมี ่ คานอยกวาคาตํ่าสุดจะลนกลับเปน คาสูงสุด ดังตัวอยาง ตัวอยางที่ 3-30 unsigned int x x = 0; x = x - 1; // x now contains 65535 // - rolls over in neg direction x = x + 1; // x now contains 0 - rolls over


68 

Unicon

3.8.5 long : ตัวแปรประเภทเลขจํานวนเต็ม 32 บิต เปนตัวแปรเก็บคาเลขจํานวนเต็มที่ขยายความจุเพิ่มจากตัวแปร int โดยตัวแปร long หนึงตั ่ วกินพื้นที่ หนวยความจํา 32 บิต (4 ไบต) เก็บคาไดจาก -2,147,483,648 ถึง 2,147,483,647 รูปแบบคําสัง่ long var = val;

พารามิเตอร ่ วแปร long ที่ตองการ var คือชือของตั ่ องการกําหนดใหกับตัวแปร val คือคาทีต ตัวอยางที่ 3-31 long time; void setup() { Serial.begin(9600); } void loop() { Serial.print("Time: "); time = millis(); Serial.println(time); //prints time since program started delay(1000); // wait a second so as not to send massive amounts of data }

3.8.6 unsigned long : ตัวแปรประเภทเลขจํานวนเต็ม 32 บิต แบบไมคิดเครื่องหมาย เปนตัวแปรเก็บคาเลขจํานวนเต็มบวก ตัวแปรหนึงตั ่ วกินพืนที ้ หน ่ วยความจํา 32 บิต (4 ไบต) เก็บคาไดจาก 0 ถึง 4,294,967,295 หรือ 232 -1 รูปแบบคําสัง่ unsigned long var = val;

พารามิเตอร var คือชือของตั ่ วแปร unsigned long ทีต่ องการ val คือคาทีต ่ องการกําหนดใหกับตัวแปร ตัวอยางที่ 3-32 long time; void setup() { Serial.begin(9600); } void loop() { Serial.print("Time: "); time = millis(); Serial.println(time); //prints time since program started delay(1000); // wait a second so as not to send massive amounts of data }


Unicon  69

3.8.7 float : ตัวแปรประเภทเลขทศนิยม เปนตัวแปรสําหรับเก็บคาเลขเลขทศนิยม นิยมใชเก็บคาสัญญาณอะนาลอกหรือคาที่ตอเนือง ่ ตัวแปร Ạº ¹Õ éà¡çº ¤è Òä´éÅÐàÍÕ Â´ ¡ Çè ÒµÑ Çá» Ã int â´ Âà¡çº ¤è Òä´éã¹ ªèǧ 3.4028235 x 1038 ถึง -3.4028235 x 1038 ตัวแปร หนึงตั ่ วจะใชพื้นทีหน ่ วยความจํา 32 บิต (4 ไบต) ในการคํานวณคณิตศาสตรกับตัวแปร float จะชากวาการคํานวณของตัวแปร int ดังนันพยายามหลี ้ ก เลียงการคํ ่ านวณกับตัวแปร float เชน ในคําสั่งวนรอบที่ทํางานดวยความเร็วสูงสุดสําหรับฟงกชั่นทางเวลาที่ ตองแมนยําอยางมาก โปรแกรมเมอรบางคนจะทําการแปลงตัวเลขทศนิยมใหเปนเลขจํานวนเต็มกอนแลวจึง คํานวณเพื่อใหทํางานไดเร็วขึน้ จะเห็นไดวาการคํานวณคณิตศาสตรของเลข floating point จะมีการใชงานมากสําหรับการคํานวณคา ขอมูลที่รับจากภายนอกซึงเป ่ นตัวเลขทศนิยม ซึงทางผู ่ ศึกษาระบบไมโครคอนโทรลเลอรมักจะมองขามไป รูปแบบคําสัง่ float var = val;

พารามิเตอร ่ วแปร float ทีต่ องการ var คือชือของตั ่ องการกําหนดใหกับตัวแปร val คือคาทีต ตัวอยางที่ 3-33 float myfloat; float sensorCalbrate = 1.117;

ตัวอยางที่ 3-34 int x; int y; float z; x = 1; y = x / 2;

// y now contains 0, // integers can’t hold fractions

z = (float)x / 2.0; // z now contains .5 // (you have to use 2.0, not 2)

Unicon-Note3/2 ในฟงกชั่น serial.println() ของการสงคาตัวแปรไปยังพอรตอนุกรม จะตัดตัวเลขเศษทศนิยมออกใหเหลือเปน เลขจํานวนเต็ม ถาตองการเพิ่มความละเอียดใหนําคาตัวแปรคูณดวย 10 ยกกําลังตางๆตามที่ตองการ


70 

Unicon

3.8.8 double : ตัวแปรประเภทเลขทศนิยมความละเอียดสองเทา เปนตัวแปรทศนิยมความละเอียดสองเทา มีขนาด 8 ไบต คาสูงสุดทีเก็่ บไดคือ 1.7976931348623157 x 10308 ใน Arduino มีหนวยความจําจํากัด จึงไมนิยมใชตัวแปรประเภทนี้

3.8.9 string : ตัวแปรประเภทขอความ เปนตัวแปรเก็บขอความ ซึงในภาษาซี ่ จะนิยามเปนอะเรยของตัวแปรประเภท char ตัวอยางที่ 3-35 ตัวอยางการประกาศตัวแปรสตริง char Str1[15]; char Str2[8] = {‘a’,‘r’,‘d’,‘u’,‘i’,‘n’,‘o’}; char Str3[8] = {‘a’,‘r’,‘d’,‘u’,‘i’,‘n’, ‘o’,’\0'}; char Str4[ ] = “arduino”; char Str5[8] = “arduino”; char Str6[15] = “arduino”;

เปนการประกาศตัวแปรสตริงโดยไมไดกําหนดคาเริมต ่ น  Str2 ประกาศตัวแปรสตริงพรอมกําหนดคาใหกับขอความทีละตัวอักษร จากตัวอยาง คอมไพเลอร จะเพิ่ม null character ใหเอง  Str3 ประกาศตัวแปรสตริงพรอมกําหนดคาใหกับขอความทีละตัวอักษร จากตัวอยาง เพิมค ่ า null string เอง  Str4 ประกาศตั วแปรสตริงคพรอมกําหนคคาตัวแปรในเครื่องหมายคําพูด จากตัวอยาง ไม ได กําหนดขนาดตัวแปร คอมไพเลอรจะกําหนดขนาดใหเองตามจํานวนตัวอักษร + 1 สําหรับ null string  Str5 ประกาศตัวแปรสตริงพรอมกําหนคคาตัวแปรในเครืองหมายคํ ่ าพูด จากตัวอยาง กําหนดขนาด ตัวแปรเอง  Str6 ประกาศตัวแปรสตริง โดยกําหนดขนาดเผื่อไวสําหรับขอความอื่นที่ยาวมากกวานี้  Str1

3.8.9.1 การเพิมตั ่ วอักษรแจงวาจบขอความ (null termination) ในตัวแปรสตริงของภาษาซี กําหนดใหตัวอักษรสุดทายเปนตัวแจงการจบขอความ (null string) ซึงก็ ่ คือตัวอักษร \0 ในการกําหนดขนาดของตัวแปร (คาในวงเล็บเหลี่ยม) จะตองกําหนดใหเทากับจํานวนตัวอักษร + 1 ดังในตัวแปร Str2 และ Str3 ในตัวอยางที่ 3-35 ที่ขอความ Arduino มีตัวอักษร 7 ตัว ในการประกาศตัว แปรตองระบุเปน [8] ในการประกาศตัวแปรสตริง ตองเผือพื ่ นที ้ สํ่ าหรับเก็บตัวอักษรแจงวาจบขอความ มิฉะนันคอมไพเลอร ้ จะแจงเตือนวาเกิดการผิดพลาด ในตัวอยางที่ 3-35 ตัวแปร Str1 และ Str6 เก็บขอความไดสูงสุด 14 ตัวอักษร

3.8.9.2 เครื่องหมายคําพูดขีดเดียวและสองขีด ปกติแลวจะกําหนดคาตัวแปรสตริงภายในเครื่องหมายคําพูด เชน "Abc" สําหรับตัวแปรตัวอักษร (char) จะกําหนดคาภายในเครืองหมายคํ ่ าพูดขีดเดียว 'A'


Unicon  71

3.8.10 ตัวแปรอะเรย (array) ตัวแปรอะเรยเปนตัวแปรหลายตัว ทีถู่ กเก็บรวมอยูในตั  วแปรชือเดี ่ ยวกัน โดยอางถึงตัวแปรแตละตัวดวย หมายเลขดัชนีทีเขี ่ ยนอยูในวงเล็บสี่เหลียม ่ ตัวแปรอะเรยของ Arduino จะอางอิงตามภาษาซี ตัวแปรอะเรยอาจ จะซับซอน แตใชแคตัวแปรอะเรยอยางงายจะตรงไปตรงมา ตัวอยางการประกาศตัวแปรอะเรย int myInts[6]; int myPins[] = {2, 4, 8, 3, 6}; int mySensVals[6] = {2, 4, -8, 3, 2}; char message[6] = “hello”;

เราสามารถประกาศตัวแปรอะเรยไดโดยยังไมกําหนดคาดังตัวแปร myInts ในตัวแปร myPins จะประกาศตัวแปรอะเรยโดยไมระบุขนาด ซึ่งทําไดเมื่อประกาศตัวแปรแลว กําหนดคาทันที เพื่อใหคอมไพเลอรนับวา ตัวแปรมีสมาชิกกีตั่ วและกําหนดคาไดถูกตอง ท ายที่ สุดคุณสามารถประกาศตัวแปรและกําหนดขนาดของตัวแปรอะเรยดังตัวแปร mySensVals ในการประกาศอะเรยของตัวแปร char จะตองเผื่อที่สําหรับเก็บคาตัวอักษรแจงวาจบขอความดวย

3.8.10.1 การใชงานตัวแปรอะเรย การใชงานตัวแปรอะเรยทําไดโดยการพิมพชื่อตัวแปร พรอมกับระบุคาดัชนีภายในเครื่องหมายวงเล็บ สี่เหลี่ยม คาดัชนีของตัวแปรอะเรยเริ่มตนดวยคา 0 ดังนันค ้ าของตัวแปร mySensVals มีคาดังนี้ mySensVals[0] == 2, mySensVals[1] == 4 , ฯลฯ การกําหนดคาใหกับตัวแปรอะเรย mySensVals[0] = 10;

การเรียกคาสมาชิกของตัวแปรอะเรย x = mySensVals[4];

Unicon-Note3/3 เทคนิคการเขียนโปรแกรมเกี่ยวกับตัวแปรอะเรย ในการเรี ยกใช ค าสมาชิ กของตั วแปรอะเรย ต องระวั งอยาอางถึงคาในวงเล็บที่เกินที่กําหนด อาทิ ประกาศ ตัวแปร int x[3] ตัวแปรมี 3 ตัว คือ x[0], x[1] และ x[2] ถาอางถึง x[3]จะเปนการอานคาจากหนวยความจํา ซึ่งกําหนดไวใชงานอยางอืน่ คาที่อานไดจะผิดพลาด การเขียนคาใหกับตัวแปรอะเรยตัวที่เกินกวากําหนดไว อาจทําใหโปรแกรมแฮงค (หยุดการทํางาน) หรือทํางานผิด เพี้ยนไป การอานหรือเขียนคาเกินคาดัชนีของตัวแปรอะเรยนี้ ทําใหเกิดบัก (ขอผิดพลาด) ที่ยากตอการคนหา


72 

Unicon

3.8.10.2 อะเรยและคําสั่งวนรอบ for โดยทั่วไปเราจะพบการใชงานตัวแปรอะเรยภายในคําสั่ง for โดยใชคาตัวแปรนับรอบของคําสั่ง for เปนคาดัชนีของตัวแปรอะเรย ดังตัวอยาง การพิมพคาสมาชิกแตละตัวของตัวแปรอะเรยผานพอรตอนุกรม ให เขียนโปรแกรมดังนี้ int i; for (i = 0; i < 5; i = i + 1) { Serial.println(myPins[i]); }

ตัวอยางโปรแกรมสาธิตการใชงานตัวแปรอะเรยทีสมบู ่ รณ ดูไดในตัวอยาง KnightRider ในหัวขอ Tutorials ในเว็บไซต www.arduino.cc

 ตัวแปรในภาษาซีที่ใชใน Arduino จะมีคุณสมบัติที่เรียกวา “ขอบเขตของตัวแปร” (scope) ซึงแตกต ่ าง จากภาษา BASIC ซึงตั ่ วแปรทุกตัวมีสถานะเทาเทียมกันหมดคือ เปนแบบ global

3.9.1 ตัวแปรโลคอลและโกลบอล ตัวแปรแบบโกลบอล (global variable) เปนตัวแปรทีทุ่ กฟงกชันในโปรแกรมรู ่ จัก โดยตองประกาศตัว แปรนอกฟงกชัน่ สําหรับตัวแปรแบบโลคอลหรือตัวแปรทองถิน่ เปนตัวแปรทีประกาศตั ่ วแปรอยูภายในเครื  ่อง หมายวงเล็บปกกาของฟงกชั่น และรูจักเฉพาะแคภายในฟงกชั่นนั้น เมื่อโปรแกรมเริ่มมีขนาดใหญและซับซอนมากขึน้ การใชตัวแปรโลคอลจะมีประโยชนมาก เนืองจาก ่ แนใจไดวามีแคฟงกชันนั ่ ้นเทานันที ้ สามารถใช ่ งานตัวแปร ชวยปองกันการเกิดการผิดพลาดเมือฟ ่ งกชั่นทําการ แกไขคาตัวแปรที่ใชงานโดยฟงกชั่นอืน่ ตัวอยางที่ 3-36 int gPWMval; void setup(){ // ... } void loop(){ int i; float f; }

// any function will see this variable

// "i" is only “visible” inside of "loop" // "f" is only “visible” inside of "loop"

3.9.2 ตัวแปรสแตติก (static) เปนคําสงวน (keyword) ทีใช ่ ตอนประกาศตัวแปรที่มีขอบเขตใชงานแคภายในฟงกชั่นเทานัน้ โดยตาง จากตัวแปรโลคอลตรงที่ตัวแปรแบบโลคอลจะถูกสรางและลบทิ้งทุกครั้งที่เรียกใชฟงกชั่น สําหรับตัวแปร สแตติกเมื่อจบการทํางานของฟงกชั่นคาตัวแปรจะยังคงอยู (ไมถูกลบทิ้ง) เปนการรักษาคาตัวแปรไวระหวาง การเรียกใชงานฟงกชั่น ตัวแปรที่ประกาศเปน static จะถูกสรางและกําหนดคาในครั้งแรกที่เรียกใชฟงกชั่น


Unicon  73

Unicon-Note3/4 การกําหนดคาคงที่เลขจํานวนเต็มเปนเลขฐานตางๆ ของ Arduino คาคงที่เลขจํานวนเต็มก็คือตัวเลขที่คุณเขียนในโปรแกรมของ Arduino โดยตรงเชน 123 โดยปกติแลวตัวเลขเหลา นี้จะเปนเลขฐานสิบ (decimal) ถาตองการกําหนดเปนเลขฐานอืนจะต ่ องใชเครื่องหมายพิเศษระบุ เชน ฐาน ตัวอยาง 10 (decimal) 123 2 (binary) B1111011 8 (octal) 0173 16 (hexadecimal) 0x7B Decimal ก็คือเลขฐานสิบ ซึ่งเราใชในชีวิตประจําวัน ตัวอยาง 101 == 101 decimal ((1 * 2^2) + (0 * 2^1) + 1) Binary เปนเลขฐานสอง ตัวเลขแตละหลักเปนไดแค 0 หรือ 1 ตัวอยาง B101 == 5 decimal ((1 * 2^2) + (0 * 2^1) + 1) เลขฐานสองจะใชงานไดไมเกิน 8 บิต (ไมเกิน 1 ไบต) มีคาจาก 0 (B0) ถึง 255 (B11111111) ถาตองการปอน เลขฐานสองขนาด 16 บิต (ตัวแปรประเภท int) จะตองปอนคาสองขั้นตอนดังนี้ myInt = (B11001100 * 256) + B10101010; // B11001100 is the high byte

Octal เปนเลขฐานแปด ตัวเลขแตละหลักมีคาจาก 0 ถึง 7 เทานัน้ ตัวอยาง 0101 == 65 decimal ((1 * 8^2) + (0 * 8^1) + 1) ขอควรระวังในการกําหนดคาคงที่ อยาเผลอใสเลข 0 นําหนา มิฉะนั้นตัวคอมไพเลอรจะแปลความหมายผิดไป วาคาตัวเลขเปนเลขฐาน 8 Hexadecimal (hex) เปนเลขฐานสิบหก ตัวเลขแตละหลักมีคาจาก 0 ถึง 9 และตัวอักษร A คือ 10, B คือ 11 ไปจนถึง F ซึ่งเทากับ 15 ตัวอยาง 0x101 == 257 decimal ((1 * 16^2) + (0 * 16^1) + 1)


74 

Unicon

 คาคงที่เปน กลุมตัวอักษรหรือขอความที่ไดกําหนดคาไวลวงหนาแลว ตัวคอมไพเลอรของ Arduino จะรูจักกับคาคงที่เหลานีแล ้ ว ไมจําเปนตองประกาศหรือกําหนดคาคงที่

3.10.1 HIGH, LOW : ใชกําหนดคาทางตรรกะ ในการอานหรือเขียนคาใหกับขาที่เปนดิจิตอล คาที่เปนไดมี 2 คาคือ HIGH หรือ LOW เทานัน้ HIGH เปนการกําหนดคาใหขาดิจิตอลนันมี ้ แรงดันเทากับ +5V ในการอานคา ถาอานได +3V หรือมากกวา ไมโครคอนโทรลเลอรจะอานคาไดเปน HIGH คาคงที่ของ HIGH ก็คือ “1” หรือเทียบเปนตรรกะ คือ จริง (TRUE) LOW เปนการกําหนดคาใหขาดิจิตอลนันมี ้ แรงดันเทากับ 0V ในการอานคา ถาอานได +2V หรือ นอยกวา ไมโครคอนโทรลเลอรจะอานคาไดเปน LOW คาคงที่ของ LOW ก็คือ “0” หรือเทียบเปนตรรกะคือ เท็จ (FALSE)

3.10.2 INPUT, OUTPUT : กําหนดทิศทางของขาพอรตดิจิตอล ขาพอรตดิจิตอลทําหนาที่ได 2 อยางคือ เปนอินพุต (INPUT) หรือเอาตพุต (OUTPUT) ซึงค ่ าคงที่นีก็้ ระบุไวชัดเจน

 3.11.1 cast : การเปลียนประเภทตั ่ วแปรชัวคราว ่ cast เปนตัวกระทําทีใช ่ สังให ่ เปลียนประเภทของตั ่ วแปรไปเปนประเภทอืน่ และบังคับใหคํานวณคาตัว แปรเปนประเภทใหม รูปแบบคําสัง่ (type)variable

เมื่อ

เปนประเภทของตัวแปรใดๆ (เชน int, float, long) Variable เปนตัวแปรหรือคาคงที่ใดๆ ตัวอยางที่ 3-37 Type

int i; float f; f = 3.6; i = (int) f; // now i is 3

ในการเปลี่ยนประเภทตัวแปรจาก float เปน int คาทีได ่ จะถูกตัดเศษออก ดังนัน้ (int)3.2 และ (int)3.7 มีคาเทากันคือ 3


Unicon  75

3.11.2 sizeof : แจงขนาดของตัวแปร ใชแจงบอกจํานวนไบตของตัวแปรที่ตองการทราบคา ซึงเป ่ นทังตั ้ วแปรปกติและตัวแปรอะเรย รูปแบบคําสัง่ เขียนไดทังสองแบบดั ้ งนี้ sizeof(variable) sizeof variable

เมื่อ Variable คือตัวแปรปกติหรือตัวแปรอะเรย (int, float, long) ทีต่ องการทราบขนาด ตัวอยางที่ 3-38 ตัวกระทํา sizeof มีประโยชนอยางมากในการจัดการกับตัวแปรอะเรย (รวมถึงตัวแปรสตริง) ตัวอยาง ตอไปนีจะพิ ้ มพขอความออกทางพอรตอนุกรมครั้งละหนึงตั ่ วอักษร ใหทดลองเปลี่ยนขอความ char myStr[] = "this is a test"; int i; void setup() { Serial.begin(9600); } void loop() { for (i = 0; i < sizeof(myStr) - 1; i++) { Serial.print(i, DEC); Serial.print(" = "); Serial.println(myStr[i], BYTE); } }


76 

Unicon

 คําสงวนคือ คาคงที่ ตัวแปร และฟงกชั่นทีได ่ กําหนดไวเปนสวนหนึงของภาษา ่ C ของ Arduino หาม นําคําเหลานีไปตั ้ ้งชื่อตัวแปรแสดงไดดังนี้ # Constants HIGH LOW INPUT OUTPUT SERIAL DISPLAY PI HALF_PI TWO_PI LSBFIRST MSBFIRST CHANGE FALLING RISING false true null # Port Constants DDRB PINB PORTB DDRC PINC PORTC DDRD PIND PORTD # Datatypes boolean byte char class default do double int long private protected public return short signed static

switch throw try unsigned void while # Other += + [] = & &= | |= , // ?: << < <= log && ! || ^ ^= ++ != % /* * {} — / /** . = == < <= () >> ; abs acos

analogRead analogWrite attachInterrupts asin atan atan2 available begin bit bitRead bitWrite bitSet bitClear boolean byte case ceil char char class constrain cos default delay delayMicroseconds detachInterrupts digitalWrite digitalRead else exp false find findUntil float floor for HALF_PI if int log loop

map max micros millis min new noInterrupts noTone

null parseInt parseFloat pinMode print println pulseIn radians read readBytes readBytesUntil return round serial serial1 serial2 serial3 setTimeout Setup shiftIn shiftOut sin sq sqrt tan this tone true write # USB Keyboard Mouse press release releaseAll accept click move isPressed


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.