หน้าเว็บ

วันพฤหัสบดีที่ 25 กันยายน พ.ศ. 2557

StringQueue กับบอร์ด Arduino

โจทย์ปัญหา 
  1. เขียนโค้ดสำหรับบอร์ด Arduino โดยสร้างเป็น C++ Class ดังต่อไปนี้ => Class StringQueue เป็นโครงสร้างข้อมูลแบบ Queue สำหรับเก็บ String objects สร้างคลาส StringQueue และทดสอบการทำงานโดยใช้โค้ดตัวอย่างต่อไปนี้ และทดสอบโดยใช้ฮาร์ดแวร์จริง (ใช้บอร์ด Arduino และแสดงผลผ่าน Serial Monitor ของ Arduino IDE)  
  2. ใช้คลาส StringQueue ในข้อแรก นำมาเขียนโค้ด Arduino เพื่อให้มีพฤติกรรมการทำงานดังนี้ กำหนดให้มีความจุเช่น 10 ข้อความ  
    1. บอร์ด Arduino มีวงจรปุ่มกด Get ทำงานแบบ Active-Low (ใช้ตัวต้านทานแบบ Pull-up, 10k)  
    2. ผู้ใช้สามารถส่งข้อความ (ภาษาอังกฤษ) ทีละบรรทัด (ไม่เกิน 16 ตัวอักขระต่อบรรทัด) จาก คอมพิวเตอร์ โดยส่งผ่าน Serial Monitor ของ Arduino IDE ไปยังบอร์ด Arduino ใช้ baudrate 115200  
    3. ข้อความแต่ละบรรทัดที่ถูกส่งไปยัง Arduino จะถูกจัดเก็บใน StringQueue ถ้าไม่เต็มความจุ แต่ถ้าเต็มความจุ ไม่สามารถเก็บข้อความใหม่ได้ Arduino จะต้องส่งข้อความ "Full" กลับมา และมี LED "Full" ติด  
    4.  เมื่อมีการกดปุ่ม Get แล้วปล่อยหนึ่งครั้ง ข้อความแรก (ถ้ามี) ของ StringQueue จะถูกดึงออกมาแล้วส่งผ่าน Serial Monitor ไปยังคอมพิวเตอร์ และนำไปแสดงผลบนจอ 16x2 LCD ที่ต่อกับบอร์ด Arduino ด้วย แต่ถ้าไม่ข้อความใดๆ Arduino จะต้องส่งข้อความ "Empty" กลับมา เมื่อกดปุ่มแล้วปล่อย และให้มี LED "Empty" ติด  
    5. บรรทัดแรกของ LCD แสดงข้อความที่ถูกอ่านออกมาล่าสุดจาก StringQueue บรรทัดที่สอง ให้แสดงจำนวนข้อความที่มีอยู่ใน StackQueue ในขณะนั้น  
    6. การเขียนโค้ดเพื่อใช้งาน LCD สามารถใช้ไลบรารี่ของ Arduino ได้
 
ผลการทดลอง 
        หลังจากได้ทำการออกแบบการทำงานของวงจรแล้ว จึงดำเนินการแบ่งโค้ดสำหรับ class StringQueue ออกเป็น 2 ไฟล์ คือ StringQueue.h และ StringQueue.cpp ซึ่งมีรายละเอียดดังต่อไปนี้ 
  • ไฟล์ StringQueue.h ใช้สำหรับการประกาศคลาส, ฟังก์ชัน และตัวแปรต่างๆ ที่ต้องการใช้งาน 
โดยมีรายละเอียดของโค้ดดังต่อไปนี้
// class declaration
#ifndef StringQueue_H
#define StringQueue_H

#include <String.h>
using namespace std;
#include <stdbool.h>
#include <inttypes.h>

#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

class StringQueue {
        private:
                int capacity; // the max capacity of the queue
                int count; // used to count the number of string object stored
                int in;  // used to count index for add String object
                int out;  // used to count index for get String object
                String *buf; // used to store String object in queue
  
        public:
                StringQueue(int capacity = 10); // constructor method
                bool enqueue(String s);  // add a String object in queue
                bool dequeue(String &s); // get a String object from queue
                int size();   // return the number of String object in the queue
                bool isEmpty();   // return true if stack is empty, otherwise false
                bool isFull();   // return true if stack is Full, otherwise false
};
#endif;

การทำงานของโค้ด 
  • ในส่วน private  
    • ประกาศตัวแปรแบบ int ชื่อ capacity ใช้สำหรับระบุขนาดของ queue  
    • ประกาศตัวแปรแบบ int ชื่อ count ใช้สำหรับนับจำนวน String object ที่มีอยู่ใน queue  
    • ประกาศตัวแปรแบบ int ชื่อ in ใช้สำหรับระบุ index ในการเพิ่ม String object ลงใน queue  
    • ประกาศตัวแปรแบบ int ชื่อ out ใช้สำหรับระบุ index ในการนำ String object ออกจาก queue  
    • ประกาศตัวแปร pointer แบบ String ชื่อ buf ใช้สำหรับเก็บข้อมูล String object ใน queue 
  • ในส่วน public  
    • ประกาศฟังก์ชันชื่อ StringQueue เป็น constructor method สำหรับสร้าง object และรับค่าเป็น int ใช้สำหรับกำหนดขนาดของ queue  
    • ประกาศฟังก์ชันชื่อ enqueue แล้วรับค่าเป็น String ใช้สำหรับการเพิ่ม String object ลงใน queue ถ้าเพิ่มได้สำเร็จจะ return ค่าเป็น true แต่ถ้าไม่สามารถเพิ่มได้จะ return ค่าเป็น false  
    • ประกาศฟังก์ชันชื่อ dequeue แล้วรับค่าเป็นที่อยู่ของ String ใช้สำหรับการนำ String object ออกจาก queue แล้วนำค่าที่ได้ไปเป็นข้อมูลของ String ตามที่อยู่ที่รับเข้ามา ถ้าสามารถนำค่าออกจาก queue ได้สำเร็จจะ return ค่าเป็น true แต่ถ้าไม่สามารถนำค่าออกจาก queue ได้จะ return ค่าเป็น false  
    • ประกาศฟังก์ชันชื่อ size ใช้สำหรับบอกจำนวน String object ที่มีอยู่ใน queue  
    • ประกาศฟังก์ชันชื่อ isEmpty ใช้สำหรับบอกว่า queue นั้นว่างอยู่หรือไม่ ถ้าหากว่า queue ไม่มีข้อมูลอยู่เลยจะ return ค่าเป็น true แต่ถ้าหากใน queue มีข้อมูลอยู่ก็จะ retuen ค่าเป็น false  
    • ประกาศฟังก์ชันชื่อ isFull ใช้สำหรับบอกว่า queue นั้นเต็มหรือไม่ ถ้าหากว่า queue มีข้อมูลอยู่จนเต็มจะ return ค่าเป็น true แต่ถ้าหาก queue ยังมีที่ว่างอยู่จะ return ค่าเป็น false 

  • ไฟล์ StringQueue.cpp สำหรับการนำฟังก์ชันต่างๆ ที่ประกาศไว้ในไฟล์ StringQueue.h มาสร้างให้ฟังก์ชันเหล่านั้นสามารถทำงานตามฟังก์ชันการทำงานที่กำหนดไว้ 
ซึ่งมีรายละเอียดของโค้ดดังต่อไปนี้
#include "StringQueue.h"

StringQueue::StringQueue(int capacity){
        this->capacity = capacity;
        count, in, out = 0;
        buf = new String[capacity];
}

bool StringQueue::enqueue(String s){
        if (!isFull()){
                *(buf + in) = s;
                count += 1;
                in += 1;
                if (in == capacity){
                        in = 0;
                }
                return true;
        }
        else {
                return false;
        }
}

bool StringQueue::dequeue(String &s){
        if (!isEmpty()){
                s = *(buf + out);
                count -= 1;
                out += 1;
                if (out == capacity){
                        out = 0;
                }
                return true;
        }
        else {
                return false;
        }
}

int StringQueue::size(){
        return count;
}

bool StringQueue::isEmpty(){
        if (in == out && count <= 0){
                return true;
        }
        else {
                return false;
        }
}

bool StringQueue::isFull(){
        if (in == out && count >= capacity){
                return true;
        }
        else {
                return false;
        }
}

        สำหรับในไฟล์ StringQueue.cpp เราจะเขียนโค้ดของแต่ละฟังก์ชันเพื่อให้สามารถทำงานได้ตามที่กำหนดไว้ในไฟล์ StringQueue.h

        หลังจากที่สร้างไฟล์ StringQueue.h และไฟล์ StringQueue.cpp แล้ว จึงใช้โค้ดสำหรับ Arduino ดังต่อไปนี้เพื่อทดสอบการทำงานของ class StringQueue ที่สร้างขึ้น 
โค้ด Arduino สำหรับการทดสอบ class StringQueue
#include "StringQueue.h"

int num = 10;  //capacity
StringQueue st(num);

void setup(){
        Serial.begin(115200);
}

char buf[20];
String str;

void loop(){
        Serial.print("\nAdd strings: ");
  for(int i=0; i<num; i++){
    str = String((i+1)*10);
                if (!st.enqueue(str)){
                        Serial.println("\nAdd string error!");
                        break;
                }else{
                        Serial.print(str);
                        Serial.print(" ");
                }
                str = NULL;
             delay(50);
   }
   delay(500);
   Serial.print("\nGet strings: ");
   for(int i=0; i<num; i++){
      if(st.dequeue(str)){
        str.toCharArray(buf, 20);
         Serial.print(buf);
         Serial.print(" ");
      }else{
         Serial.println("\nGet string error!");
         break;
      }
      delay(50);
   }
   delay(500);
}

        สำหรับโค้ดทดสอบ class StringQueue นี้จะสร้าง queue ที่มีขนาด 10 แล้วทำการเพิ่มข้อมูลลงใน queue เป็นข้อความตัวเลขคือ 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 แล้วค่อยนำข้อมูลใน queue ออกมาทีละตัวเพื่อดูว่าลำดับในการนำข้อมูลออกถูกต้องหรือไม่ ซึ่งเอาต์พุตที่ได้จากการทดสอบได้ดังภาพด้านล่าง
ภาพเอาต์พุตจาก Serial Monitor สำหรับการทดสอบ class StringQueue

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

        หลังจากที่ได้ทำการทดสอบ class StringQueue แล้วพบว่ามีการเพิ่มข้อมูลใน queue และนำข้อมูลออกจาก queue ได้อย่างถูกต้องแล้ว เราจึงดำเนินการสร้างโค้ดสำหรับ Arduino เพื่อให้ทำงานได้ตามฟังก์ชันต่อไปนี้ 
  • มีวงจรปุ่มกด Get ทำงานแบบ Active-Low (ใช้ตัวต้านทานแบบ Pull-up, 10k)  
  • ผู้ใช้สามารถส่งข้อความ (ภาษาอังกฤษ) ทีละบรรทัด (ไม่เกิน 16 ตัวอักขระต่อบรรทัด) จาก คอมพิวเตอร์ โดยส่งผ่าน Serial Monitor ของ Arduino IDE ไปยังบอร์ด Arduino ใช้ baudrate 115200  
  • ข้อความแต่ละบรรทัดที่ถูกส่งไปยัง Arduino จะถูกจัดเก็บใน StringQueue ถ้าไม่เต็มความจุ แต่ถ้าเต็มความจุ ไม่สามารถเก็บข้อความใหม่ได้ Arduino จะต้องส่งข้อความ "Full" กลับมา และมี LED "Full" ติด  
  • เมื่อมีการกดปุ่ม Get แล้วปล่อยหนึ่งครั้ง ข้อความแรก (ถ้ามี) ของ StringQueue จะถูกดึงออกมาแล้วส่งผ่าน Serial Monitor ไปยังคอมพิวเตอร์ และนำไปแสดงผลบนจอ 16x2 LCD ที่ต่อกับบอร์ด Arduino ด้วย แต่ถ้าไม่ข้อความใดๆ Arduino จะต้องส่งข้อความ "Empty" กลับมา เมื่อกดปุ่มแล้วปล่อย และให้มี LED "Empty" ติด  
  • บรรทัดแรกของ LCD แสดงข้อความที่ถูกอ่านออกมาล่าสุดจาก StringQueue บรรทัดที่สอง ให้แสดงจำนวนข้อความที่มีอยู่ใน StackQueue ในขณะนั้น 
โค้ด Arduino สำหรับการทำงานตามฟังก์ชันที่กำหนด

#include <StringQueue.h>
#include "Wire.h" 
#include "LiquidCrystal_I2C.h"

LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display 

StringQueue textarray(5);
String recieved_text = "";
String str = NULL;

int Full = 8;
int Empty = 9;
int buttonState = HIGH;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 100;    // the debounce time; increase if the output flickers

void setup() {
         Serial.begin(115200);
         lcd.init();   
         lcd.backlight();
         pinMode(INPUT,4);
         pinMode(OUTPUT,5);
         pinMode(OUTPUT,7);
         delay(5);
         Serial.println("start"); 
}

void loop() {

         while (Serial.available()) {
                  delay(30);
                  char c = Serial.read();  //gets one byte from serial buffer
                  recieved_text += c; 
         }
         if (recieved_text.length() > 0) {
                  if(recieved_text.length() > 16){
                           recieved_text = recieved_text.substring(0,16);
                  }
 
                  if(!textarray.enqueue(recieved_text)){
                           Serial.println("FULL");
                           str = "FULL";
                           digitalWrite(Full,HIGH);
                  } else {
                           Serial.println("recieve " + recieved_text);
                           str = "";
                           digitalWrite(Full,LOW);
                           digitalWrite(Empty,LOW);
                  }
                  recieved_text = ""; //clears text for new text
         }
  
         int get_button = digitalRead(4);
         // If the switch changed, due to noise or pressing:
         if (get_button != lastButtonState) {
                  // reset the debouncing timer
                  lastDebounceTime = millis();
         }
         // *************debouce state**************
         if ((millis() - lastDebounceTime) > debounceDelay) {
                  // if the button state has changed:
                  if (get_button != buttonState) {
                           buttonState = get_button;
                           //if the new button state is HIGH
                           if (buttonState == HIGH) {
                                    if(!textarray.dequeue(str)){
                                             Serial.println("Empty");
                                             digitalWrite(Empty,HIGH);
                                             str = "Empty";
                                    } else {
                                             Serial.println("get " + str);
                                             digitalWrite(Empty,LOW);
                                             digitalWrite(Full,LOW);
                                    }
                           }
                  }
         }
         lastButtonState = get_button;
         lcd.clear();
         lcd.print(str);
         lcd.setCursor(0, 1);
         lcd.print(textarray.size());
         delay(10);
}


        หลังจากเขียนโค้ดสำหรับ Arduino แล้ว จึงทำการต่อวงจรดังต่อไปนี้เพื่อทำการทดสอบการทำงานของโค้ด Arduino 
ภาพสำหรับวงจร Arduino
 
ภาพแผงผังวงจร

ภาพสำหรับการต่อวงจรจริง

        หลังจากต่อวงจรและทดสอบโค้ดสำหรับ Arduino ได้ผลการทดลองดังภาพด้านล่าง 
  • เมื่อให้ queue มีขนาด 5 แล้วทดลองกดปุ่มเพื่อนำข้อมูลออกพบว่าใน Serial Monitor จะขึ้นข้อความ “Empty” จากนั้นทดลองใส่ข้อมูลเรื่อยจนเต็ม queue จะขึ้นข้อความ “FULL” และทดลองนำข้อมูลออกจาก queue จนหมด 
 
ภาพเอาต์พุตจาก Serial Monitor

  • เมื่อทดลองกดปุ่มในขณะที่ queue ยังไม่มีข้อมูลอยู่เลย
ภาพเอาต์พุตจาก Serial Monitor

  • เมื่อทดลองใส่ข้อมูลจนเต็ม queue ขนาด 5
ภาพเอาต์พุตจาก Serial Monitor

  • เมื่อทดลองใส่ข้อความที่มีขนาดเกิน 16 ตัวอักษรลงใน queue แล้วทดลองกดปุ่มเพื่อนำข้อมูลออกมาจาก queue พบว่าข้อความที่แสดงออกมามีขนาดเท่ากับ 16 ตัวอักษร ดังนั้นแสดงว่าใน queue จะเก็บข้อมูลที่มีขนาดตัวอักษรไม่เกิน 16 ตัวอักษร
ภาพจาก Serial Monitor แสดงการใส่ข้อความยาวเกิน 16 ตัวอักษร
ภาพจาก Serial Monitor เมื่อนำข้อมูลออกจาก queue

ไม่มีความคิดเห็น:

แสดงความคิดเห็น