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