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

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


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

Thursday, August 28, 2014

การทดลองใช้งานบอร์ด Arduino เพื่อควบคุมแสงจาก RGB Led

สวัสดีครับ วันนี้จะมานำเสนอผลการทดลองใช้งานบอร์ด Arduino เพื่อควบคุมแสงจาก Led แบบ RGB กันนะครับ ซึ่งโจทย์มีอยู่ว่า

1) จงเขียนโค้ดสำหรับ Arduino และวงจรที่ทำงานได้ตามข้อกำหนดต่อไปนี้ [RGB LED / PWM-based Dimming]

  • วงจรทำงานโดยใช้ระดับแรงดันสำหรับ I/O ที่ 5V เท่านั้น
  • มีปุ่มกด 3 ปุ่ม (ให้ชื่อว่า R, G, B) ทำงานแบบ Pull-up (active-low) ให้ต่อวงจรปุ่มกดเอง เพื่อใช้งานกับบอร์ด Arduino
  • มีเอาต์พุต 3 ขา ต่อกับวงจร RGB LED (จะใช้แบบ Common-Anode หรือ Common-Cathode ก็ได้) พร้อมตัวต้านทานจำกัดกระแส 3 ตัว
  • เขียนโค้ดด้วยภาษา C++ สำหรับ Arduino เพื่อสร้าง Class ที่มีชื่อว่า "RGB_LED"
  • กำหนดให้ constructor สำหรับคลาส RGB_LED เป็นดังนี้ RGB_LED( int red_pin, int_green_pin, int blue_pin ); โดยรับค่ามาเป็นหมายเลขของ I/O pins สำหรับ 3 ขาของ Arduino ที่จะถูกใช้งานเป็นเอาต์พุตแบบ PWM
  • มีเมธอดอย่างเช่นvoid setRed( int duty_cycle ), void setGreen( int duty_cycle ),void setBlue( int duty_cycle ) เพื่อใช้กำหนดค่า duty cycle ของขาเอาต์พุต PWM และใช้ในการกำหนดความสว่างของแต่ละสี ใช้คำสั่ง analogWrite() ในการกำหนดค่า
  • กำหนดสมาชิก instance members ตามความจำเป็น เช่น ค่า duty cycles สำหรับแต่ละสี
  • ใช้คลาสดังกล่าวในการเขียนโค้ด (สร้าง object จากคลาสดังกล่าวและเรียกใช้เมธอด) เพื่อสาธิตการทำงานร่วมกับฮาร์ดแวร์จริง
  • เมื่อกดปุ่ม R, G หรือ B แล้วปล่อยแต่ละครั้ง จะทำให้ค่า duty cycle ของสีดังกล่าวเพิ่มขึ้นทีละ 8 ถ้าค่า duty cycle เกิน 255 ให้วนกลับมาเริ่มที่ 0 ใหม่ (ค่าเริ่มต้นสำหรับ duty cycles เป็น 0)

2) เหมือนข้อ 1 แต่เปลี่ยนพฤติกรรมการกดปุ่ม: ถ้ากดปุ่ม R, G หรือ B ค้างไว้อย่างน้อย 100 msec จะเพิ่มค่าขึ้นทีละ 8 (แล้วเริ่มนับเวลาใหม่) ถ้าค่า duty cycle เกิน 255 ให้วนกลับมาเริ่มที่ 0 ใหม่


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

  • บอร์ด Arduino Uno (สามารถใช้รุ่นอื่นแทนได้)
  • RGB Led (Common Anode)
  • ปุ่มกด X3
  • ตัวต้านทาน 330 Ω X3 (ใช้กับ RGB Led)
  • ตัวต้านทาน 10 KΩ X3 (ใช้กับปุ่มกด)
  • Breadboard

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

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


โดยวงจรนี้เป็นวงจรที่สามารถผสมแสงสีของ RGB Led ได้ด้วยการควบคุมความเข้มของแสงจากปุ่มกด ซึ่งจะเริ่มจากค่าความสว่างสูงสุดและค่อยๆ ลดลงเมื่อกดปุ่ม ซึ่งสามารถกดแยกเป็นสีๆ ได้ โดยจะกดแล้วปล่อยหรือกดค้างไว้ก็ได้ (เปลี่ยนระดับทุก 100 msec) พร้อมกันนั้นในส่วนของโค้ดโปรแกรมจะมีส่วนของการเรียกใช้งานคลาสของภาษา C++ อยู่ด้วย ซึ่งมีดังต่อไปนี้


RGB_LED.h

#ifndef RGB_LED_h
#define RGB_LED_h

#include "Arduino.h"


class RGB_LED{

     public:
             RGB_LED (int red_pin, int green_pin, int blue_pin);
             void setRed(int duty_cycle);
             void setGreen(int duty_cycle);
             void setBlue(int duty_cycle);
     private:
             int _red_pin;
             int _green_pin;
             int _blue_pin;
};
#endif


RGB_LED.cpp

#include "Arduino.h"
#include "RGB_LED.h"

RGB_LED::RGB_LED(int red_pin, int green_pin, int blue_pin)
{
     pinMode(red_pin, OUTPUT);
     pinMode(green_pin, OUTPUT);
     pinMode(blue_pin, OUTPUT);

     _red_pin = red_pin;
     _green_pin = green_pin;
     _blue_pin = blue_pin;
}

void RGB_LED::setRed(int duty_cycle)
{
     analogWrite(_red_pin, duty_cycle);
}

void RGB_LED::setGreen(int duty_cycle)
{
     analogWrite(_green_pin, duty_cycle);
}

void RGB_LED::setBlue(int duty_cycle)
{
     analogWrite(_blue_pin, duty_cycle);
}


ส่วนของโค้ด Arduino

rgbButtonWcpp.ino

#include "rgb_led .h"

const int R = 3;
const int G = 5;
const int B = 6;

// instance of class RGB_LED
RGB_LED rgbLed(11, 10, 9);

// 0 = brightiest, 255 = dimmiest
int dutyCycleR = 0;
int dutyCycleG = 0;
int dutyCycleB = 0;

void setup(){
     // Initialize button pin

     pinMode(R, INPUT);
     pinMode(G, INPUT);
     pinMode(B, INPUT);

     // Set Initiate duty cycle to 0
     rgbLed.setRed(dutyCycleR);
     rgbLed.setGreen(dutyCycleG);
     rgbLed.setBlue(dutyCycleB);
}

void loop(){

     // Red section
     if (isButtonPressed(R)){
          dutyCycleR = addDutyCycle(dutyCycleR);
          rgbLed.setRed(dutyCycleR);
          delay(100);
     }

     // Green section
     if (isButtonPressed(G)){
          dutyCycleG = addDutyCycle(dutyCycleG);
          rgbLed.setGreen(dutyCycleG);
          delay(100);
     }

     // Blue section
     if (isButtonPressed(B)){
          dutyCycleB = addDutyCycle(dutyCycleB);
          rgbLed.setBlue(dutyCycleB);
          delay(100);
     }
}

boolean isButtonPressed(int buttonPin){
     int buttonState = digitalRead(buttonPin);

     // check button press (active low)
     if (buttonState == LOW){
          return true;
     }
     else {
          return false;
     }
}

int addDutyCycle(int dutyCycle){
     // increase duty cycle for 8
     int dc = dutyCycle + 8;

     if (dc > 255){
          dc = 0;
     }
     return dc;
}



ภาพวงจรที่ออกแบบไว้โดยใช้โปรแกรม Fritzing


ภาพจากการทดลองจริง


รูปวงจรจริง



ขณะที่บอร์ดเริ่มต้นทำงานไฟจาก Led จะเป็นแสงสีขาวที่เกิดจากการผสมกันของแสงสามสี



เมื่อกดปุ่มลดระดับความเข้มของแสงสีแดงลงจะได้เป็นแสงสีเขียวอ่อน



แสงสีม่วงที่ได้จากแสงสีแดงผสมกับแสงสีน้ำเงิน



ตัวอย่างแสงสีฟ้าอ่อนสวยๆ


สำหรับ source code ทั้งหมดสามารถโหลดได้ ที่นี่