วันอังคารที่ 23 กันยายน พ.ศ. 2557

สร้าง Class C++ ของ Class StringQueue

การสร้าง Class C++ ที่ใช้เป็นโครงสร้างข้อมูลแบบ Queue (คิว) ลักษณะการทำงานแบบ เข้าก่อนออกก่อน หรือ First In First Out (FIFO)เพื่อใช้งานสำหรับ Arduino


โจทย์สำหรับการทดลอง


1) เขียนโค้ดสำหรับบอร์ด Arduino โดยสร้างเป็น C++ Class ดังต่อไปนี้
=> Class StringQueue เป็นโครงสร้างข้อมูลแบบ Queue สำหรับเก็บ String objects สร้างคลาส StringQueue และทดสอบการทำงานโดยใช้โค้ดตัวอย่างต่อไปนี้ และทดสอบโดยใช้ฮาร์ดแวร์จริง (ใช้บอร์ด Arduino และแสดงผลผ่าน Serial Monitor ของ Arduino IDE)

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

อุปกรณ์ทดลอง (Apparatus)

      อุปกรณ์     
         จำนวน         
LED 5mm.
2


ตัวต้านทาน 10 กิโลโอห์ม 


(น้ำตาล ดำ ส้ม ทอง)
1


BREADBOARD 


บอร์ดทดลองอิเล็กทรอนิกส์
1
Arduino Uno R3 
1
ปุ่มกด
1
สาย USB Cable
1
สายไฟต่อวงจร
-

ตัวต้านทานแบบปรับค่าได้
1
16x2 LCD Module
1

Arduino Sketch (1)


ส่วนแรกเป็นการประกาศคลาสชื่อ StringQueueมีเพียงเมธอดเดียวสำหรับใช้งานเป็น Constructor โดยรับอาร์มิวเมนต์ capacity ตามชนิดข้อมูลแบบ int มีชนิดข้อมูลเป็น boolean เพื่อตรวจสอบความจุของ Queue 

// class declaration ---------------------------------------------------------------------------------
#ifndef StringQueue_h
#define StringQueue_h

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

class StringQueue {
  public:
    StringStack( int capacity=10 ); // constructor
    bool enqueue( String s ); // put a String object on Queue
    bool dequeue( String &s ); // get a String object from Queue
    int size_Queue(); // return the number of String objects on the Queue
    boolean isEmpty(); // return true if Queue is empty, otherwise false
    boolean isFull(); // return true if Queue is full, otherwise false
  private:
    int capacity; // the max. capacity of the Queue
    int rear; // used to count the number of string objects stored
    int front;
    String *buf; // used to store String objects on Queue
    String array[10 ];
};
#endif
// end class delcaration ---------------------------------------------------------------------------

ส่วนที่สองเป็นการสร้างคลาสซึ่งเกี่ยวกับการสร้างเมธอดสมาชิกตามที่ได้ประกาศไว้ในส่วนแรก ให้สังเกตวิธีการอ้างอิงชื่อเมธอดสมาชิก


// class implementation----------------------------------------------------------------------------
#include "StringQueue.h"

StringQueue::StringQueue( int capacity ) {
  capacity = capacity;
  rear = 0;
  front = 0;

}  //constructor ของ class

bool StringQueue::enqueue( String s ) {
  if(rear >= 10 && front >= 10){
        rear =0;
        front =0;
        }
  if ( isEmpty() ) {
    array[rear] = s;
    rear ++;
    return true;
  }
  else {
    return false;
  }
}  

bool StringQueue::dequeue( String &s ) {
  if ( front < 10 && front < rear) {
     String *buf = &s;
    *buf = array[front];
    front ++;
    return true;
  }
  else {
     return false;
  }   
}  

int StringQueue::size_queue() {
  return rear-front;
}  

boolean StringQueue::isEmpty() {
  if(rear < 10){
    return true;
  }else{return false;}
}  

boolean StringQueue::isFull() {
  if(rear == capacity){
    return true;
  }else{return false;}
}  
// end class implementation----------------------------------------------------------------------

ในส่วนนี้ จะอธิบายโค้ดได้ดังนี้
StringQueue( int capacity )  คือ constructor ของ class
enqueue( String s ) : เป็นการใส่ข้อความ ลงใน Queue โดย rear คือ ตำแหน่งที่จะใส่  โดย rear จะเพิ่มค่าไปเรื่อยๆ ถ้ามีการใส่ข้อความ โดยที่ถ้า rear >=10 และ front >=10 จะทำการรีเซตค่าของทั้งสองตัวเป็นค่าเริ่มต้น
dequeue( String &s ) : เป็นการ นำค่าของตำแหน่ง front ออก โดยต่ำแหน่งแรกคือตำแหน่ง 0 และจะเพิ่มค่าไปเรื่อยๆ ถ้ามีการ dequeue  โดยที่ค่า front ต้องน้อยกว่า rear เสมอ ถึงจะทำการ dequeue ได้   Dequeue คือการเอาข้อความที่เข้าก่อน ออก
size_queue() : เป็นการหาขนาดของ queue
isEmpty()  : ตรวจสอบ queue ไม่มีความจุหรือไม่

isFull() : ตรวจสอบ queue มีความจุเต็มหรือไม่


ส่วนที่สามเกี่ยวข้องกับการเขียนโค้ดทดสอบ (ไม่เกี่ยวข้องกับการนิยามและสร้างคลาส) โดยสร้างออปเจคจากคลาส StringQueue เขียนได้ดังนี้


// test code Problem1 -----------------------------------------------------------------------------
#include <StringQueue.h>
int num = 10; // capacity
StringQueue st( num );

void setup() {
  Serial.begin(115200);  //ตั้งค่า Baudrate
}
char buf[20];
String str;

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

เมื่อได้ทดลองการทำงานแล้ว ก็สามารถนำโค้ดดังกล่าว มาจัดแบ่งเป็นไฟล์ StringQueue.h สำหรับส่วนที่ประกาศคลาส และ StringQueue.cpp สำหรับส่วนที่สร้างคลาส และเก็บไฟล์ทั้งสองไว้ในไดเรคทรอรี่ชื่อเดียวกับคลาส ในการนำไปใช้งาน โค้ด Arduino Sketch ที่จะใช้คลาสดังกล่าว จะต้องประกาศการใช้งานดังนี้ #include<StringQueue.h>


ไฟล์ StringQueue.h , StringQueue.cpp  สำหรับนำไปใช้งานในลักษณะที่เป็นไลบรารี่สำหรับ Arduino  ใส่ไว้ภายใต้ไดเรคทรอรี่ชื่อ libraries ของ Arduino IDE)

โค้ดนี้ เป็นการทดสอบการทำงานของ queue โดยให้ queue เก็บค่า 10,20,30 บวกเพิ่มไปทีละ 10 จนกระทั่งครบ 100 เสร็จแล้วจะทำการ dequeue ออกมา คือนำข้อความตัวแรกสุดที่เข้าไปก่อน ออกมาก่อน จนกระทั่งถึงตัวสุดท้าย และทำอย่างนี้ไปเรื่อยๆ

ผลการทดลองการทำงาน (1)



Arduino Sketch (2)

การเขียนโค้ดทดสอบ โดยสร้างออปเจคจากคลาส StringQueue ให้มีคุณสมบัติตรงกับโจทย์สำหรับการทดลองข้อ 2 เขียนได้ดังนี้

// test code Problem2 -----------------------------------------------------------------------------
#include <StringQueue.h>
#include <LiquidCrystal.h>
int num = 10; // capacity
StringQueue st( num );

LiquidCrystal lcd(12,11,5,4,3,2);

int check=0; 
char count1;
int nub =0;
String count;
char buf[16];
String buff;
String str,str1;

//button
int empty_ledPin = 7;   // กำหนด pin สำหรับ LED เมื่อ Queue ว่าง         
int full_ledPin = 8;    // กำหนด pin สำหรับ LED เมื่อ Queueเต็ม
int button_Pin = 6;     // กำหนด pin สำหรับปุ่ม
int button = 0;         //กำหนดตัวแปรรับค่าจากปุ่ม ค่าเป็น 0
int state=0;


void setup() {
  Serial.begin(115200);
  pinMode(empty_ledPin, OUTPUT);      // กำหนดหน้าที่ของ pin led
  pinMode(full_ledPin, OUTPUT);
  pinMode(button_Pin, INPUT);     // กำหนดหน้าที่ของ pin ปุ่ม
  lcd.begin(16,2);
}

void loop(){
  button = digitalRead(button_Pin);  
  while(Serial.available()>0){
    count1 = (char)Serial.read();
    count = count + count1;   
    if(count1 == '\n'){
      check=1;
    }
  }  
  
  if(check==1){     
    str = count;
    str = str.substring(0,count.length()-1);
    str = str.substring(0,15);
    check=0;
    count ="";
    nub=0;
    
    if ( !st.enqueue( str ) ) {
      Serial.print( "\nFull" );
      Serial.println(' ');
      
      lcd.setCursor(0,0);
      lcd.clear();
      lcd.write("FULL");
      digitalWrite(full_ledPin,HIGH);
     }
    else {
      digitalWrite(empty_ledPin, LOW);
      Serial.print( "\nEnqueue strings: " );
      Serial.print( str );
      delay(100);
      }
    delay(50);
  }  

   //BUTTON
  if (button == LOW) { //Active LOW
    state=1; 
  }

  if(state==1 && button==HIGH){
    state=0;
    digitalWrite(full_ledPin, LOW); 
    
    if ( !st.dequeue( str ) ) {
      Serial.print( "\nEMPTY" );
      lcd.setCursor(0,0);
      lcd.clear();
      lcd.write("EMPTY");
      digitalWrite(empty_ledPin,HIGH);
      delay(100);  
    }
    else {
      str.toCharArray( buf, 16 );
      Serial.print( "\nDuqueue strings: " );
      Serial.print( buf );
      buff=buf;
      lcd.setCursor(0,0);
      lcd.clear();
      lcd.print(buff);
    }
    delay(50);
  }
  
  lcd.setCursor(0,1);
  lcd.print(st.size_queue()); 
}
// end test code Problem2------------------------------------------------------------------------


ผลการทดลองการทำงาน (2)



ในส่วนนี้ จะอธิบายโค้ดได้ดังนี้
                
ในคำสั่ง void loop();  ส่วนนี้ เป็นส่วนที่ดูว่ามีการส่งค่ามาจาก Serial port มายังบอร์ด หรือไม่โดยจะรับมาเป็น char คือทีละตัว จนครบข้อความที่ส่งมา โดยข้อความสุดท้ายที่ส่ง จะลงท้ายด้วย \n เสมอ เพราะมีการกด enter  แล้วจึงให้ไปทำขั้นตอนต่อไป

ในเงื่อนไขการตรวจเช็ค Check() ใน state นี้ จะทำการตรวจเช็คว่า ข้อความที่รับมานั้น เกิน 16 ตัวอักษรหรือไม่ ถ้าเกินจะทำการตัดออกให้เหลือแค่ 16 ตัวอักษร  แล้วจะนำไปใส่ queue และมีการ แสดงข้อความที่ Serial monitor  ซึ่งถ้า queue เต็ม จะมีคำว่า Full ปรากฏ บนหน้าจอ Serial   monitor และหน้าจอ LCD แล้วไฟก็จะเป็น HIGH                 

button() ปุ่มกด คือเมื่อกดเป็น low จะไปยังstate ต่อไป เมื่อมายังstate ถัดมา คือกดแล้วปล่อย จะมีการทำงานโดยปุ่มกดนี้ จะเป็นการ dequeue คือ นำข้อความที่ใส่เข้าไปแรกสุดออกมาจากqueue มาแสดงบนหน้าจอ Serial monitor และ LCD โดยจะทำไป เรื่อยๆ ถ้ามีการกดและปล่อยอีก แต่ถ้า ในqueue ว่าง ก็จะ มีคำว่า “EMPTY” แสดงบนหน้าจอ Serial monitor และ LCD และไฟอีกดวงก็จะเป็น High  และในทุกครั้งที่มีการทำงาน จะมีการแสดง ขนาดของ queue บนหน้าจอ LCD เสมอไป


การทำงานของโค้ดทดสอบ
      
ส่งข้อความ (ภาษาอังกฤษ) ทีละบรรทัด (ไม่เกิน 16 ตัวอักขระต่อบรรทัด) จากคอมพิวเตอร์ โดยส่งผ่าน Serial Monitor ของ Arduino IDE ไปยังบอร์ด Arduino   ข้อความแต่ละบรรทัดที่ถูกส่งไปยัง Arduino จะถูกจัดเก็บใน StringQueue (เก็บไว้ในคิว) 

ถ้าเต็มความจุที่กำหนดไว้ จะไม่สามารถเก็บข้อความใหม่ได้ Arduino จะต้องส่งข้อความ "Full" กลับมายังคอมพิวเตอร์ และนำไปแสดงผลบนจอ 16x2 LCD ที่ต่อกับบอร์ด Arduino
     
กดปุ่มแล้วปล่อยหนึ่งครั้ง ข้อความแรก (ถ้ามี) ของ StringQueue จะถูกดึงออกมาแล้วส่งผ่าน Serial Monitor ไปยังคอมพิวเตอร์ และนำไปแสดงผลบนจอ 16x2 LCD ที่ต่อกับบอร์ด Arduino ด้วย แต่ถ้าไม่มีข้อความใดๆ Arduino จะส่งข้อความ "Empty" กลับมา เมื่อกดปุ่มแล้วปล่อย และให้มี LED "Empty" ติด บรรทัดแรกของ LCD แสดงข้อความที่ถูกอ่านออกมาล่าสุดจาก StringQueue บรรทัดที่สอง ให้แสดงจำนวนข้อความที่มีอยู่ใน StackQueue ในขณะนั้น



ผังวงจร 



  
 Breadboard View



Schematic View


รูปภาพ การต่อวงจรทดลองจริง




ผลแสดงการทดลอง



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

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