Tuesday, September 23, 2014

Arduino - StringQueue

สวัสดีครับ สำหรับวันนี้จะมาฝึกการสร้างและใช้งานคลาส string queue บนบอร์ด Arduino กันครับ โดยโจทย์มีดังนี้

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

(ใช้บอร์ด Arduino และแสดงผลผ่าน Serial Monitor ของ Arduino IDE)

StringQueue.h
#ifndef StringQueue_h
#define StringQueue_h

#include "Arduino.h"
#include <String.h>

class StringQueue {
  public:
    StringQueue(int capacity); //constructor
    boolean put(String s); // put a string to queue
    boolean get(String &s); // get a string from queue
    int size(); // return number of string in queue
    inline boolean isEmpty(); // return ture if queue is empty
    inline boolean isFull(); // return true if queue is full
  private:
    int _capacity; // max capacity of queue
    int count; // used to count the number of string in queue
    String buf[100]; // used to store string object in queue
};

#endif


StringQueue.cpp
#include "Arduino.h"
#include "StringQueue.h"

StringQueue::StringQueue(int capacity=10)
{
  _capacity = capacity;
  count = 0;
}

boolean StringQueue::put(String s)
{
  if(isFull()) {
    return false;
  }
  else {
    buf[count] = s;
    count++;
    return true;
  }
}

boolean StringQueue::get(String &s)
{
  String *address;
  
  if(isEmpty()) {
    return false;
  }
  else {
    address = &s;
    --count;
    *address = buf[0];
    
    for(int i = 0; i < count; i++) {
      buf[i] = buf[i + 1];
    }
    return true;
  }
}

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

inline boolean StringQueue::isEmpty()
{
  return (count == 0)? true : false;
}

inline boolean StringQueue::isFull()
{
  return (count == _capacity)? true : false;
}


StringQueue_task01.ino
#include "StringQueue.h"

int num = 10; // capacity
StringQueue squ(num);
char buf[16];
String str;

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

void loop() {

 Serial.print( "\nPut strings: " );
  for ( int i=0; i < num; i++ ) {
    str = String( (i+1)*10 );
    if ( !squ.put( str ) ) {
      Serial.println( "\nPut 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 ( squ.get( str ) ) {
      str.toCharArray( buf, 16 );
      Serial.print( buf );
      Serial.print( " " );
    } else {
      Serial.println( "\nGet string error!" );
      break;
    }
    delay(50);
  }
  
  delay(500);
  
}


สำหรับอุปกรณ์ที่ใช้มีดังนี้
  • บอร์ด Arduino Uno (สามารถใช้รุ่นอื่นแทนได้)
  • สาย USB
  • ปุ่มกด
  • LCD Display

ซอฟต์แวร์ที่ใช้
  • Arduino IDE
  • Text Editor หรือ IDE สำหรับเขียนภาษา C/C++
  • Fritzing (สำหรับวาดผังวงจร)


ผลการรันโปรแกรม





โจทย์ข้อที่ 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 ในขณะนั้น

โค้ดสำหรับข้อสอง
StringQueue_task02.ino
#include "StringQueue.h"
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

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

const int button = 6;
int buttonState = 0;
int lastButtonState = HIGH;

const int emptyLed = 7;
const int fullLed = 8;

char buf[16];
String str;

void setup() {
  pinMode(button,INPUT);
  pinMode(emptyLed, OUTPUT);
  pinMode(fullLed, OUTPUT);
  Serial.begin(115200);
  lcd.begin(16, 2);
  
  lcd.clear();
  lcd.setCursor(0, 1);
  lcd.print("queue size: " + String(squ.size()));
  lcd.setCursor(0, 0);
  lcd.print("status: Empty");
  
  digitalWrite(emptyLed,HIGH);
  digitalWrite(fullLed,LOW);
}

void loop(){
  
  if (Serial.available() > 0){
    str = Serial.readString();
    if (str.length() > 16){
      str = str.substring(0, 16);
    }
    if (!squ.put(str)){
      Serial.println("Full");
      
      lcd.clear();
      lcd.setCursor(0, 1);
      lcd.print("queue size: " + String(squ.size()));
      lcd.setCursor(0, 0);
      lcd.print("status: Full");
      
      digitalWrite(fullLed,HIGH);
      
    }else {
      Serial.print("Put string: ");
      Serial.println(str);
      
      lcd.clear();
      lcd.setCursor(0, 1);
      lcd.print("queue size: " + String(squ.size()));
      
      digitalWrite(emptyLed,LOW);
    }
  }
  
  str = NULL;
  
  buttonState = digitalRead(button);
  
  // check button released
  if (buttonState == HIGH && lastButtonState == LOW) { 
    if(squ.get(str)){
      str.toCharArray(buf, 16);
      Serial.print("Get string: ");
      Serial.println(buf);
     
      lcd.clear();
      lcd.setCursor(0, 1);
      lcd.print("queue size: " + String(squ.size()));
      lcd.setCursor(0, 0);
      lcd.print(buf);
      
      digitalWrite(fullLed,LOW);
      
    }else {
      Serial.println("Empty");
      
      lcd.clear();
      lcd.setCursor(0, 1);
      lcd.print("queue size: " + String(squ.size()));
      lcd.setCursor(0, 0);
      lcd.print("status: Empty");
      
      digitalWrite(emptyLed,HIGH);   
    }
  }
  lastButtonState = buttonState;
     
}


ผลการทดลอง


ผังวงจร

ขณะที่ไม่มีข้อความอยู่ใน queue จะแสดงข้อความ Empty และ led green ติด

วงจรขณะที่ข้อความใน queue เต็ม จะแสดงค่า Full และ led Red ติด

ดาวน์โหล Source code ทั้งหมดได้ ที่นี่

Friday, September 12, 2014

Arduino - StringStack

สวัสดีครับ สำหรับวันนี้จะมาฝึกการสร้างและใช้งานคลาส stack บน Arduino กันครับ โดยโจทย์มีดังนี้  

โจทย์ข้อ 1
เขียนโค้ดสำหรับบอร์ด Arduino โดยสร้างเป็น C++ Class ดังต่อไปนี้ => 
Class StringStack เป็นโครงสร้างข้อมูลแบบ Stack (กองซ้อน) สำหรับเก็บ String objects (http://arduino.cc/en/Reference/StringObject) และกำหนด API สำหรับคลาสดังกล่าว เป็นดังนี้

StringStack.h
#ifndef StringStack_h
#define StringStack_h

#include "Arduino.h"
#include <String.h>

class StringStack {
  public:
    StringStack( int capacity ); // constructor
    boolean put( String s ); // put a String object on stack
    boolean get( String &s ); // get a String object from stack
    inline int size(); // return the number of String objects on the stack
    inline boolean isEmpty(); // return true if stack is empty, otherwise false
    inline boolean isFull(); // return true if stack is full, otherwise false
  private:
    int _capacity; // the max. capacity of the stack
    int count; // used to count the number of string objects stored
    String buf[100]; // used to store String objects on stack
};

#endif

จงสร้างคลาส StringStack และทดสอบการทำงานโดยใช้โค้ดตัวอย่างต่อไปนี้ และทดสอบโดยใช้ฮาร์ดแวร์จริง (ใช้บอร์ด Arduino และแสดงผลผ่าน Serial Monitor ของ Arduino IDE)

StringStack_task01.ino
#include "StringStack.h"

int num = 10; // capacity

StringStack st( num );

void setup() {

  Serial.begin(115200);
}

char buf[20];

String str;

void loop() {


  Serial.print( "\nPut strings: " );
  for ( int i=0; i < num; i++ ) {
    str = String( (i+1)*10 );
    if ( !st.put( str ) ) {
      Serial.println( "\nPut 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.get( str ) ) {
      str.toCharArray( buf, 20 );
      Serial.print( buf );
      Serial.print( " " );
    } else {
      Serial.println( "\nGet string error!" );
      break;
    }
    delay(50);
  }
  delay(500);
}

สำหรับอุปกรณ์ที่ใช้มีดังนี้

  • บอร์ด Arduino Uno (สามารถใช้รุ่นอื่นแทนได้)
  • สาย USB
  • ปุ่มกด (สำหรับข้อ 2)



ซอฟต์แวร์ที่ใช้


  • Arduino IDE
  • text editor หรือ IDE สำหรับเขียนภาษา C/C++
  • Fritzing

โดยการทดลองนี้จะใช้แค่บอร์ด Arduino และสาย USB เชื่อมต่อกับคอมพิวเตอร์เท่านั้น


code ที่เขียนขึ้นเอง

StringStack.cpp
#include "Arduino.h"
#include "StringStack.h"

StringStack::StringStack(int capacity=10)
{
_capacity = capacity;
count = 0;
}

boolean StringStack::put(String s)
{
if (isFull()) {
return false;
}
else {
buf[count] = s;
count++;
return true;
}
}

boolean StringStack::get(String &s)
{
String *address;

if (isEmpty()) {
return false;
}
else {
address = &s;
--count;
*address = buf[count];
return true;
}
}

inline int StringStack::size()
{
return count;
}

inline boolean StringStack::isEmpty()
{
return (count == 0)? true : false;
}

inline boolean StringStack::isFull()
{
return (count == _capacity)? true : false;
}

ผลการรันโปรแกรม

ผลการรันโดยใช้ serial monitor


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

โค้ดสำหรับข้อ 2
StringStack_task02.ino
#include "StringStack.h"

const int button = 2;
int num = 10; // capacity
StringStack st( num );

int buttonState = 0;
int lastButtonState = HIGH;

void setup() {
  pinMode(button,INPUT);
  Serial.begin(115200);
}

char buf[20];
String str;

void loop(){
  
  if (Serial.available() > 0){
    str = Serial.readString();
    if (str.length() > 20){
      str = str.substring(0, 20);
     }
     if (!st.put(str)){
       Serial.println("Full");
     }else{
       Serial.print("Put string: ");
       Serial.println(str);
     }
  }
  
  str = NULL;
  buttonState = digitalRead(button);
  // check button released
  if (buttonState == HIGH && lastButtonState == LOW) { 
    if(st.get(str)){
      str.toCharArray( buf, 20 );
      Serial.print( "Get string: " );
      Serial.println( buf ); 
    }else {
      Serial.println( "Empty" );
    }
  }
  lastButtonState = buttonState;
}

ผลการทดลอง


วงจรปุ่มกดแบบ Pull-up (Active Low)


ต่อวงจรปุ่มกดและเชื่อมต่อบอร์ด Arduino กับคอมพิวเตอร์ผ่านสาย USB

ผลการรันโปรแกรม


สามารถดาวน์โหลดโค้ดทั้งหมดได้ ที่นี่