2017/09/19

Weekend Project – Arduino Temperature Meter V2

In the last tutorial, I have shown how to make a Temperature Meter which records highest, current, and lowest temperature with Arduino Mini Pro and a DS18B20 temperature probe.

One of the readers suggested me if I could record the highest and lowest temperatures measured into EEEPROM, then I won't lost the highest/lowest temperature once power is down. It's a good idea, but  I thought, it would be a greater idea if I kept both time stamp and high/low temperatures!
(Writing data to EEEPROM tutorial would be in V3....unfortunately...)

 So, I searched Arduino.cc website and found abundant information about DS1302/DS1307 RTC clock modules. Many people mentioned in forums that DS1302/DS1307 are not very precise and tend to draft of few seconds per week/month. However, DS1302 is quite affordable, so I bought 2 pieces from an auction sites and to give it a try. Reference DS1302RTC data at Arduino.cc

Functions added in Temperature V2:
  • Display date/time clock and date of week on top of LCD
  • Realtime display both Celsius and Fahrenheit 
All steps, material, and wiring here are only related DS1302 RTC module. If you want to learn how to build up the entire project, please check previous tutorial for how to wire up LCD, Arduino, and DS18B20 temperature probe from here:  Arduino-Temperature-Tutorial

During the experiment of adding RTC module, I have encountered few issues and got few advises and suggestions from Google+ communities: Google+ discussion

Few notices to share with you:
  • Arduino has internal Time library (Really, I don't know before I started this!)
  • Use the internal clock to count time elapsed 
  • Only update time from RTC module once a day
  • Remove unnecessary delay() commands to ensure every second is displayed




Material Needed: 
  • DS1302 RTC module 
  • Few jumper wires 



DS1302 RTC Module Wiring: 
  • VCC to Arduino VCC
  • GND to Arduino GND
  • CLK to Arduino pin 5
  • DAT to Arduino pin 6
  • RST to Arduino pin 7

Arduino Temperature Meter Schematic V2


Video Demonstration


Code: <
/*
Temperature Meter 2015-04-05

Material Needed: 
- Arudino Mini Pro * 1
- LCD Module 4 x 20 (J204A) * 1
- Temperature Probe (DS18B20) * 1 
- Protoboard * 1 
- 22k resistor * 1
- Few jumper wires

Wiring:
- Arduino-GND to GND 
- Arduino-VCC to VCC 
- Temperature probe-GND to GND 
- Temperature probe-VCC to VCC 
- Temperature probe-Data to 2.2K resistor to VCC 
- LCD-GND to GND 
- LCD-VCC to VCC 
- LCD-SDA to Arduino A4/SDA 
- LCD-SLC to Arduino A5/SLC 
- Protoboard VCC/GND to 5V DC power source 
- Slide switch to VCC/GND (For LCD on/Off, but not shown below)
*/
//Compatible with the Arduino IDE 1.0
//Library version:1.1
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
//Used for DS18S20 Temperature sensor
#include <OneWire.h>
#include <DallasTemperature.h>
//Used for DS1302 RTC Clock module
#include <DS1302RTC.h>
#include <Time.h>

//Init DS1302 Clock module
//Set pins: CLK(4), DAT(5), RST(6)
  int CE = 5;
  int IO = 6;
  int CLK = 7;
  
  String DayOfWeek;
  unsigned long previous_time;
  unsigned long secondsInDay = 86400 * 1000; //1000 millis seconds in a second!
  int sync = 0;
  
  DS1302RTC RTC(CE, IO, CLK);
 
  //init Arduino internal clock
  time_t t = now();
  

/*Define for DS18S20 data pins
*  This data pins needs to connect 220 Om resister and to 5V to work
*/
#define ONE_WIRE_BUS 4 

//Define for LCD display pins, SLC 3, SDA 2
#define SCL_CLOCK_PIN 3
#define SDA_DATA_PIN 2

//Initialize OneWire library for temperature sensor
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

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


float HighestTemp = 0.0;
float CurrentTemp = 0.0;
float LowestTemp = 0.0;

void setup()
{
  //Serial.begin(9600); 
  // start temperature sensor
  sensors.begin();
  sensors.requestTemperatures(); //get temperature
  // initialize the LCD
  //You may setup your own clock pin(SCL), data pin(SDA) 2013-12-14
  //Wire.beginOnPins(SCL_CLOCK_PIN, SDA_DATA_PIN);
  lcd.init();
  lcd.backlight();
  
  //Set lowest, highest temperatues 
  CurrentTemp  = sensors.getTempCByIndex(0);
  HighestTemp = CurrentTemp;
  LowestTemp = CurrentTemp;
  
  
  //Show Temperature Meter wording...
  lcd.setCursor(0,1);  
  lcd.print(F("Temperature Meter V2"));
  lcd.setCursor(0,2);  
  lcd.print(F("  by Stonez Chen"));  
  delay(2000);
  //clear LCD
  lcd.clear();
  
  lcd.setCursor(0,1);
  lcd.print(F("High:"));
  LCDshowNum(5,1,HighestTemp);    
     
  lcd.setCursor(0,2);
  lcd.print(F("Now:"));
  LCDshowNum(4,2,CurrentTemp);  
    
  lcd.setCursor(0,3);
  lcd.print(F("Low:"));
  LCDshowNum(4,3,LowestTemp); 
  
  
  
  
  //Check DS1302 Clcock module time
  if(RTC.haltRTC()){
      lcd.setCursor(0,0);  
      lcd.print(F("1302 Stop,do SetTime"));
  }

  //Read time from DS1302 moudle and setup internal clock
  setSyncProvider(RTC.get);
  while(timeStatus() != timeSet){ 
        setSyncProvider(RTC.get);
  }
  
  t = now();
  
  if(timeStatus() == timeSet){
        previous_time = millis();
        /*
        Serial.println("Init Year = " + String(year(t)));        
        Serial.println("Init Month = " + String(month(t)));
        Serial.println("Init Day = " + String(day(t)));        
        Serial.println("Init Hour = " + String(hour(t)));
        Serial.println("Init minute = " + String(minute(t)));
        Serial.println("Init second = " + String(second(t)));
        */

  }else{
        //Serial.println("Time not set!");
  }
 
}

void loop()
{ 
    unsigned long current_time = millis();
    unsigned long time_passed;

    //Sync clock every 24hr(secondsInDay)
    time_passed = current_time - previous_time;
    if(time_passed >= secondsInDay){
       setSyncProvider(RTC.get);
       sync++;
       previous_time = current_time;
    }
    
   //mark when RTC.get again!
  //Serial.print(" Time_passed = " + String(time_passed));
  //Serial.println(" Synced :" + String(sync));
  //lcd.setCursor(18,3);  
  //lcd.print(sync);
  
  //Print Date time on the first line
  lcd.setCursor(0,0);  
  lcd.print(printYMDHMS());

  
  sensors.requestTemperatures(); //get temperature

  //Get Current
  CurrentTemp = sensors.getTempCByIndex(0);
  LCDshowNum(4,2,CurrentTemp);   
  
  //Check if Hightest
  if(CurrentTemp > HighestTemp){
     HighestTemp = CurrentTemp;
     LCDshowNum(5,1,HighestTemp);     
  }

  //Chekc if Lowest
  if(CurrentTemp < LowestTemp){
    LowestTemp = CurrentTemp;
    LCDshowNum(4,3,LowestTemp);
  }
  delay(200);
  
}

/*
* LCDshowNum
* LCD display location: x, y
* Float n: temperature to display
*/
void LCDshowNum(int x, int y, float n){
  lcd.setCursor(x,y);
  lcd.print(n,1); //,1 means print 1 decimal
  lcd.print(char(223)); 
  lcd.print("C ");
  lcd.print(((n*1.8)+32),1);//,1 means print 1 decimal
  lcd.print(char(223)); 
  lcd.print("F ");
}

/*
* This function return YYMMDD HHMMSS string from internal clock
*/
String printYMDHMS(){
  
  String DayOfWeek = "";
  t = now(); //update internal clock
 
  switch (weekday(t)){
      case 7:
        DayOfWeek = " SA";
        break;
      case 6:
        DayOfWeek = " FR";
        break;
      case 5:
        DayOfWeek = " TH";
        break;
      case 4:
        DayOfWeek = " WE";
        break;          
      case 3:
        DayOfWeek = " TU";
        break;
      case 2:
        DayOfWeek = " MO";
        break; 
       case 1:
        DayOfWeek = " SU";
        break;         
    }

    return
      String(year(t)).substring(2,4) + '/' +
      String(print2digits(month(t))) + '/' +
      String(print2digits(day(t))) + ' ' +
      String(print2digits(hour(t))) + ':' +
      String(print2digits(minute(t))) + ':' +
      String(print2digits(second(t))) +
      DayOfWeek;
}
/*
* Add 0 to the single digit number to better align the text
*/

String print2digits(int number) {
  if (number >= 0 && number < 10){
    return '0'+String(number);
  }else{
    return(String(number));
  }
}



Copyright Notice:
You are welcome to share this tutorial with others, please retain author's name and URL link to this tutorial blog page. Thank you!

---------------------------------------------------------------------------------------------

自製 Arduino 溫度測量機 V2


在上一次的教學中, 我已示範過如何用 Arduino + 溫度測量棒 + LCD 來 自製溫度測量機 。
有讀者看到上一個教學後建議我把最高溫及最低溫的資訊記錄到EEEPROM裡,這樣高低溫資訊才不會遺失。 聽起來很不錯,但如果能把時間+高低溫也一起記錄下來, 應會更好。
所以我上網找了Arduino 與時間相關的資訊,也很快的找到了 DS1302/DS1307 RTC 時鐘模組可以記錄時間,而且即使系統斷電時,時鐘模組可以依靠著內建的 2302 水銀電池來維持時間運作。

搜尋資訊的同時,很多人都提到 DS1302/DS1307不是很準確,用一段時間就會慢個幾秒鐘, 但是它相對便宜,所以我就買了兩片DS1302回來試試囉!  請參考 DS1302 RTC 詳細介紹

溫度測量機 V2 新增功能

  • 顯示日期  時間  星期 
  • 顯示攝氏 及 華氏 
這次的的教學主要是以如何加入 DS1302 RTC 模組. 如果你要做一個完整的測量機,請先參考上一篇:  自製溫度測量機

把 DS1302 RTC 模組加入到電路中不難,但是我遇到了一些很奇怪的問題,如只能顯示單數秒之類的。還好 Google+ 社群裡有許多朋友給了我建議及方向,讓我能及時把程式寫好並測試完成 。相關討論 Google+ discussion

使用 DS1302 RTC 主要的注意事項如下:
  • Arduino 有內建 Time 程式庫 (說真的,開始寫程式時,我還真的不知道哩! Orz...)
  • 使用Arduino內建的時鐘來當計時器即可! 
  • 每天只要向 RTC 模組要一次時間來更新 Arduino內建時鐘即可
  • 檢視一下程式中如果用到 delay() 次數及時間長短,它會顯嚮秒數的顯示




所需材料: 
  • DS1302 RTC 時鐘模組 
  • 跳線數根 



DS1302 RTC 模組接線: 
  • VCC to Arduino VCC
  • GND to Arduino GND
  • CLK to Arduino pin 5
  • DAT to Arduino pin 6
  • RST to Arduino pin 7

Arduino 溫度測量機線路圖 V2


影片展示


程式碼: (請參考英文版部份)

Copyright Notice:
You are welcome to share this tutorial with others, please retain author's name and URL link to this tutorial blog page. Thank you!

2017/09/16

Testing Arduino POV (Persistent of Vision) | 試試 Arduino POV (視覺暫留)

I have been attracted to Arduino POV[1] for quite a while, but I didn't have a chance to actually make it myself.   Luckily, I found this easy to follow Arduino POV tutorial[2] on Instructable.com and within an hour, my son and me made two Arduino POV sets and have fun for the entire afternoon.


Material needed for this tutorial:

  • Arduino Nano * 1 (All other kinds of Arduino board will do)
  • LED * 7
  • 220 resistor * 7 
  • Jump wire ~ up to 10 (female to male)
  • Prefboard * 1 
  • Battery pack (If you would like have fun without tethered with USB)

Easy Wire Connection as follow:

  1. LED1 ~ LED7 negative pin to Prefboard GND
  2. Prefboard to Nano(or Uno) GND pin
  3. LED1 ~ LED7 postive pin to Nano(or Uno) D2 ~ D8 pin
  4. USB power to Nano USB port to supply power (or use a battery back to supply power)

Schematic: (I use www.tinkercad.com to draw this schematic below, just in case you interested.)



This is a fun a easy project! First, just connect LED cathode(negative) and resistors on the prefboard.
Then Preboard GND to Arduino Nano GND.


Then connect these LED positive pins to Arduino Nano.





As you can see in the picture below, I'v used Arduino Nano. It's lighter and smaller for portable devices.  I made the Red one and my son have choose the Green.



Programming logic:
When anyone sees an image, the image stays in the retina of the eyes for roughly 1/16th seconds. We can utilize the particular physical characteristic of human eyes, to crate the Arduino POV project. The basic idea is when we want to show a letter, Arduino shows each column of a letter at a time to form the letter to eyes.

See the illustration below on how to show a letter 'H'. First, Arduino displays column 1 to light up all 7 LEDs at timing 1. While column 1 image stays in human eyes, Arduino shows 2nd column, then 3, 4, and 5th columns at their respectively timing 2~5. Since all these images stays in human eyes temporarily, we will see the letter 'H'.



Actual LED image captured:



Arduino code here:
Just copy and past into Arduino IDE and it should work.
*Change your own message in the variable msgBody and remember to change msgLength*

/*
 Written by Ahmad Saeed on 22 August 2015
 
 This code is capable of displaying the following characters;
 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ .-_!%&#$,()@?
*/ 

//////////////////// Message to Customize  ///////////////////
#define msgLength 11                                       ///
String msgBody = "This is POV";                            ///
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////




#define delayInChar 3
#define delayBetweenChar 5
#define LED1 2
#define LED2 3
#define LED3 4
#define LED4 5
#define LED5 6
#define LED6 7
#define LED7 8

byte msgCode[(5 * msgLength) + 10];
boolean pintState;
int columnNum = -1;
String charToWrite;

void setup() {
  msgBody.toUpperCase();
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(LED4, OUTPUT);
  pinMode(LED5, OUTPUT);
  pinMode(LED6, OUTPUT);
  pinMode(LED7, OUTPUT);
}

void loop() {
//// Convert all text to binary array ////////////////////////
  if ( columnNum == -1 ) // This block needs to be done once//
  {                                                         //
    for (int c = 0; c < (msgBody.length()); c++)  {         //
      //Separate the following character                    //
      charToWrite = msgBody.substring(c, c + 1);            //
      //Send the separated characted to addChar function    //
      addChar(charToWrite);                                 //
    }                                                       //
      //Add a little space after each character             //
    addChar(" ");                                           //
    addChar(" ");                                           //
  }                                                         //  
//////////////////////////////////////////////////////////////

//// Display the binary arrays after all characters are coded //
  for (int c = 0; c < (sizeof(msgCode)); c++)  {              //
    pintState = (msgCode[c] / B1000000) % B10;                //
    digitalWrite(LED1, pintState);                            //
                                                              //
    pintState = (msgCode[c] / B100000) % B10;                 //
    digitalWrite(LED2, pintState);                            //
                                                              //
    pintState = (msgCode[c] / B10000) % B10;                  //
    digitalWrite(LED3, pintState);                            //
                                                              //
    pintState = (msgCode[c] / B1000) % B10;                   //
    digitalWrite(LED4, pintState);                            //
                                                              //
    pintState = (msgCode[c] / B100) % B10;                    //
    digitalWrite(LED5, pintState);                            //
                                                              //
    pintState = (msgCode[c] / B10) % B10;                     //
    digitalWrite(LED6, pintState);                            // 
                                                              //
    pintState = msgCode[c] % B10;;                            //
    digitalWrite(LED7, pintState);                            //
                                                              //
    delay(delayInChar);                                       //
    // if the character is finished, take a longer off period //
    if ((c + 1) % 5 == 0 ) {                                  //
      digitalWrite(LED1, LOW);                                //
      digitalWrite(LED2, LOW);                                //
      digitalWrite(LED3, LOW);                                //
      digitalWrite(LED4, LOW);                                //
      digitalWrite(LED5, LOW);                                // 
      digitalWrite(LED6, LOW);                                //
      digitalWrite(LED7, LOW);                                //
      delay(delayBetweenChar);                                //
    }                                                         //
  }                                                           //
                                                              //
////////////////////////////////////////////////////////////////
}     


void addChar(String y) {
  if (y == "1") {
    addColumn(B0010001);
    addColumn(B0100001);
    addColumn(B1111111);
    addColumn(B0000001);
    addColumn(B0000001);
  }
  else if (y == "2") {
    addColumn(B0100001);
    addColumn(B1000011);
    addColumn(B1000101);
    addColumn(B1001001);
    addColumn(B0110001);
  }
  else if (y == "3") {
    addColumn(B0100010);
    addColumn(B1000001);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B0110110);
  }
  else if (y == "4") {
    addColumn(B0001100);
    addColumn(B0010100);
    addColumn(B0100100);
    addColumn(B1111111);
    addColumn(B0000100);
  }
  else if (y == "5") {
    addColumn(B1110010);
    addColumn(B1010001);
    addColumn(B1010001);
    addColumn(B1010001);
    addColumn(B1001110);
  }
  else if (y == "6") {
    addColumn(B0111110);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B0100110);
  }
  else if (y == "7") {
    addColumn(B1000000);
    addColumn(B1000111);
    addColumn(B1001000);
    addColumn(B1010000);
    addColumn(B1100000);
  }
  else if (y == "8") {
    addColumn(B0110110);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B0110110);
  }
  else if (y == "9") {
    addColumn(B0110010);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B0111110);
  }
  else if (y == "0") {
    addColumn(B0111110);
    addColumn(B1000101);
    addColumn(B1001001);
    addColumn(B1010001);
    addColumn(B0111110);
  }
  else if (y == "A") {
    addColumn(B0011111);
    addColumn(B0100100);
    addColumn(B1000100);
    addColumn(B1000100);
    addColumn(B1111111);
  }
  else if (y == "B") {
    addColumn(B1111111);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B0110110);
  }
  else if (y == "C") {
    addColumn(B0111110);
    addColumn(B1000001);
    addColumn(B1000001);
    addColumn(B1000001);
    addColumn(B0100010);
  }
  else if (y == "D") {
    addColumn(B1111111);
    addColumn(B1000001);
    addColumn(B1000001);
    addColumn(B1000001);
    addColumn(B0111110);
  }
  else if (y == "E") {
    addColumn(B1111111);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B1000001);
  }
  else if (y == "F") {
    addColumn(B1111111);
    addColumn(B1001000);
    addColumn(B1001000);
    addColumn(B1001000);
    addColumn(B1000000);
  }
  else if (y == "G") {
    addColumn(B0111110);
    addColumn(B1000001);
    addColumn(B1000001);
    addColumn(B1000101);
    addColumn(B0100110);
  }
  else if (y == "H") {
    addColumn(B1111111);
    addColumn(B0001000);
    addColumn(B0001000);
    addColumn(B0001000);
    addColumn(B1111111);
  }
  else if (y == "I") {
    addColumn(B0000000);
    addColumn(B1000001);
    addColumn(B1111111);
    addColumn(B1000001);
    addColumn(B0000000);
  }
  else if (y == "J") {
    addColumn(B0000000);
    addColumn(B0000010);
    addColumn(B1000001);
    addColumn(B1000001);
    addColumn(B1111110);
  }
  else if (y == "K") {
    addColumn(B1111111);
    addColumn(B0001000);
    addColumn(B0010100);
    addColumn(B0100010);
    addColumn(B1000001);
  }
  else if (y == "L") {
    addColumn(B1111111);
    addColumn(B0000001);
    addColumn(B0000001);
    addColumn(B0000001);
    addColumn(B0000001);
  }
  else if (y == "M") {
    addColumn(B1111111);
    addColumn(B0100000);
    addColumn(B0011000);
    addColumn(B0100000);
    addColumn(B1111111);
  }
  else if (y == "N") {
    addColumn(B1111111);
    addColumn(B0010000);
    addColumn(B0001000);
    addColumn(B0000100);
    addColumn(B1111111);
  }
  else if (y == "O") {
    addColumn(B0111110);
    addColumn(B1000001);
    addColumn(B1000001);
    addColumn(B1000001);
    addColumn(B0111110);
  }
  else if (y == "P") {
    addColumn(B1111111);
    addColumn(B1001000);
    addColumn(B1001000);
    addColumn(B1001000);
    addColumn(B0110000);
  }
  else if (y == "Q") {
    addColumn(B0111100);
    addColumn(B1000010);
    addColumn(B1000010);
    addColumn(B1000010);
    addColumn(B0111101);
  }
  else if (y == "R") {
    addColumn(B1111111);
    addColumn(B1001000);
    addColumn(B1001100);
    addColumn(B1001010);
    addColumn(B0110001);
  }
  else if (y == "S") {
    addColumn(B0110010);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B1001001);
    addColumn(B0100110);
  }
  else if (y == "T") {
    addColumn(B1000000);
    addColumn(B1000000);
    addColumn(B1111111);
    addColumn(B1000000);
    addColumn(B1000000);
  }
  else if (y == "U") {
    addColumn(B1111110);
    addColumn(B0000001);
    addColumn(B0000001);
    addColumn(B0000001);
    addColumn(B1111110);
  }
  else if (y == "V") {
    addColumn(B1111100);
    addColumn(B0000010);
    addColumn(B0000001);
    addColumn(B0000010);
    addColumn(B1111100);
  }
  else if (y == "W") {
    addColumn(B1111110);
    addColumn(B0000001);
    addColumn(B0000110);
    addColumn(B0000001);
    addColumn(B1111110);
  }
  else if (y == "X") {
    addColumn(B1100011);
    addColumn(B0010100);
    addColumn(B0001000);
    addColumn(B0010100);
    addColumn(B1100011);
  }
  else if (y == "Y") {
    addColumn(B1110000);
    addColumn(B0001000);
    addColumn(B0001111);
    addColumn(B0001000);
    addColumn(B1110000);
  }
  else if (y == "Z") {
    addColumn(B1000011);
    addColumn(B1000101);
    addColumn(B1001001);
    addColumn(B1010001);
    addColumn(B1000011);
  }
  else if (y == "Z") {
    addColumn(B1000011);
    addColumn(B1000101);
    addColumn(B1001001);
    addColumn(B1010001);
    addColumn(B1000011);
  }
  else if (y == " ") {
    addColumn(B0000000);
    addColumn(B0000000);
    addColumn(B0000000);
    addColumn(B0000000);
    addColumn(B0000000);
  }
  else if (y == ".") {
    addColumn(B0000000);
    addColumn(B0000011);
    addColumn(B0000011);
    addColumn(B0000000);
    addColumn(B0000000);
  }
  else if (y == "_") {
    addColumn(B0000001);
    addColumn(B0000001);
    addColumn(B0000001);
    addColumn(B0000001);
    addColumn(B0000001);
  }
  else if (y == "-") {
    addColumn(B0000000);
    addColumn(B0001000);
    addColumn(B0001000);
    addColumn(B0001000);
    addColumn(B0000000);
  }
  else if (y == "!") {
    addColumn(B0000000);
    addColumn(B0000000);
    addColumn(B1111101);
    addColumn(B0000000);
    addColumn(B0000000);
  }
  else if (y == "(") {
    addColumn(B0000000);
    addColumn(B0000000);
    addColumn(B0000000);
    addColumn(B0111110);
    addColumn(B1000001);
  }
  else if (y == ")") {
    addColumn(B1000001);
    addColumn(B0111110);
    addColumn(B0000000);
    addColumn(B0000000);
    addColumn(B0000000);
  }
  else if (y == "%") {
    addColumn(B1100010);
    addColumn(B1100100);
    addColumn(B0001000);
    addColumn(B0010011);
    addColumn(B0100011);
  }
  else if (y == ",") {
    addColumn(B0000000);
    addColumn(B0000101);
    addColumn(B0000110);
    addColumn(B0000000);
    addColumn(B0000000);
  }
  else if (y == "?") {
    addColumn(B0100000);
    addColumn(B1000101);
    addColumn(B1001000);
    addColumn(B0110000);
    addColumn(B0000000);
  }
  else if (y == "#") {
    addColumn(B0010100);
    addColumn(B0111110);
    addColumn(B0010100);
    addColumn(B0111110);
    addColumn(B0010100);
  }
  else if (y == "@") {
    addColumn(B0111110);
    addColumn(B1000001);
    addColumn(B1011101);
    addColumn(B1011101);
    addColumn(B0111000);
  }
  else if (y == "$") {
    addColumn(B0110010);
    addColumn(B1001001);
    addColumn(B1111111);
    addColumn(B1001001);
    addColumn(B0100110);
  }
}

void addColumn(byte x) {
  columnNum += 1;
  msgCode[columnNum] = (x);
}



Image captured with my POV set:




Image captured with my son's POV set:


How to capture the image:
I used HTC U11 to shot these photos. First, you have change HTC camera to Pro mode and set the exposure time to greater than 2 seconds to capture this image. Hold the Arduino POV set steadily on one hand and move the POV set slowly towards to left from right.  I believe any camera with Bulb exposure time greater than 2 seconds should be able to capture this image. 

That's all for this tutorial. See you next time!

Article feferences:
  1. Wikipedia for POV
  2. How to Make a POV Display Using LEDs and Arduino 
  3. Simple-Arduino-POV-Wand 


Done.

==== 中 文 版 本 ====

自從我看個幾個 Arduino POV[1] 專案之後,一直想自己試試做一個來玩玩,但一直有點懶惰,遲遲沒有動手。最近看到一篇很簡單的教學 Arduino POV tutorial[2] ,剛好兒子也在家,我們決定一起動手來做一個來玩。只需約一小時,我們就各自做了一組 Arduino POV,而且整個下午都在試著不同的字串及拿著 HTC U11 拍出很一些有趣的照片。這是一個很好的親子活動的安排哩!現在就看著這篇教學一起動手吧!


這篇教學所需材料:

  • Arduino Nano * 1 (Nano, Pro mini, Uno 都可以)
  • LED * 7
  • 220 歐姆電阻 * 7 
  • 杜邦線 ~ 約 10條 (母對母)
  • 洞洞板 * 1 
  • 電池盒 (不用連接USB,可以更方便的玩,但可有可無)

接線方式:
  1. LED1 ~ LED7 負級 to 220 歐姆電阻
  2. 電阻 to Nano(or Uno) GND
  3. LED1 ~ LED7 正級 to Nano(or Uno) D2 ~ D8 腳位
  4. USB 電源接 Nano USB 來提供電源 (這可以用電池盒來取代)

電路圖: (我是用 www.tinkercad.com 來製作這張電路圖)



這真的是一個很簡單又好玩的範例! 
道先, 先把 LED 負級連到220歐姆的電阻再由電阻連接到洞洞板的負極上。


接著,把LED 1 ~ 7 的正極接到 Arduino 上的 D2 ~ D8 腳位上。





我這次是使用了 Arduino Nano,因為它的體積比較小。下圖中可以看到我們做了兩組,我做了紅色的這組,我兒子則做了綠色的這一組。



程式的邏輯如下:
原理是當我們看到一個影像時,這個影像會暫留在視網膜上約 1/16 秒。當影像一個接著一個的顯示後,我們即會看到好像是數個影像的重疊,這些重疊的影像看起來就會形成一幅影像;卡通或動畫即是這樣的原理。Arduino POV 就是利用同樣的原理。

看下例如何顯示 H 字母。首先,Arduino 在 Time 1 顯示了欄位 1 的 7 個 LED,然後 Arduino 在 Time 2 ~ 5 個別的顯示欄位 2 ~ 5。 由於每個欄位都會在視網膜上暫留,我們就可以在到字母 'H'。


你可以參考這幾個字母放大後的影像如下:



Arduino 程式碼在上方,直接拷貝就可以使用:

*如果你要改變顯示的字串,請記得改變 msgBody 字串以及 msgLength 的字串長度*





下方是我用 HTC U11 照出來的 POV 照片:




這張是用我兒子那一組所拍下來的POV照片


如何照下 Arduino POV 的照片:
我是使用 HTC U11 來拍攝這些照片的。首先,你必需把手機設定到 PRO 模式 ,然後選定曝光時間到 2 秒以上才能拍的出來。拍攝時,拿著洞洞板,把 LED 朝相機方向,慢慢的由左到右的移動。不過,任何可以選定手動曝光到 2 秒以上的相機應該都可以拍的。

這就是這次的Arduino 範例,下次見!

文章參考:
  1. Wikipedia for POV
  2. How to Make a POV Display Using LEDs and Arduino 
  3. Simple-Arduino-POV-Wand 

2017/09/03

Test PIR Sensor with Arduino | PIR 感應器

In this tutorial, I would like to show you how to make a PIR sensor to work with Arduino.  PIR stands for Passive Infrared sensor. What it does is to measure infrared (IR) light radiating from objects in its field of view.

A frequently use case is installing a PIR sensor at the hall way and whenever PIR sensor detects people walk towards the hall way, then the PIR sensor turn on the light.   Please refer to Wikipedia for more information about PIR.

Material needed for this tutorial:

  • Arduino Nano * 1 (All other kinds of Arduino board will do)
  • PIR sensor * 1
  • Buzzer * 1
  • LED * 1 (You may just utilize the LED on Arduino Nano)
  • 220 resistor * 1 (No need you use the LED on Arduino Nano)
  • Jump wire ~ up to 10 (female to female)

Wire Connection as follow:

  1. PIR Ground pin to Nano(or Uno) GND pin
  2. PIR Power pin to Nano +5V pin
  3. PIR data pin to Nano D2 pin
  4. LED ground to Nano GND pin
  5. LED power pin to 220K resistor pin
  6. 220K resistor pin to Nano pin 13
  7. Buzzer postive pin to Nano D8 pin
  8. Buzzer ground pin to Nano GND pin

Schematic: (I use www.tinkercad.com to draw this schematic below, just in case you interested.)




Programming logic:
Once the PIR sensor detects objects entered to its detection range, light up LED and sound the Buzzer for one second.

Arduino code here:

#define NOTE_C5  523
const int PIRSensor = 2;
const int ledPin =  13;
int sensorValue = 0;
void setup() {
  pinMode(PIRSensor, INPUT);
  pinMode(ledPin, OUTPUT);
}
void loop() {
sensorValue = digitalRead(PIRSensor);
if (sensorValue == HIGH) { 
    // Object detected, turn on LED, sound the buzzer for 1 second
    tone(8, NOTE_C5);
    digitalWrite(ledPin, HIGH);
    delay(1000);
}else{
    // No object detected, turn off LED, mute the buzzer
    noTone(8);
    digitalWrite(ledPin, LOW);
}



See the demo on Youtube:





Done.
==== 中 文 版 本 ==========================================
這次的教學, 我想試試看 Arduino 的 PIR 感測器.  PIR 是被動式感應器的縮寫. 它可以偵測在它的視線內從物體發射出的紅外線.

最常使用到 PIR 感測器 的地方就是不常有人經過的地方,當有人經過時,PIR 感測器感應到紅外線就會把燈打開。 請參考維基百科的資訊。

這次教學所需的材料:
  • Arduino Nano * 1 (其他 Arduino 板子也可以)
  • PIR 偵測器 * 1
  • 蜂鳴器 * 1
  • LED * 1 (也可以使用 Arduino Nano 上的內建 LED)
  • 220 電阻 * 1 (若使用 Arduino Nano 上的內建 LED就不需要)
  • 杜邦線 大約十個 (母對母)

連線方式:

  1. PIR Ground pin to Nano(or Uno) GND pin
  2. PIR Power pin to Nano +5V pin
  3. PIR data pin to Nano D2 pin
  4. LED ground to Nano GND pin
  5. LED power pin to 220K resistor pin
  6. 220K resistor pin to Nano pin 13
  7. Buzzer postive pin to Nano D8 pin
  8. Buzzer ground pin to Nano GND pin

線路圖: (我是使用 www.tinkercad.com 來會畫這張線路圖, 如果你有興趣可以參考一下)




程式邏輯:
很簡單,當 PIR 感測器在他的視線內感應到紅外線, 將 LED 和蜂鳴器開啟一秒鐘.

Arduino 程式碼在這:

#define NOTE_C5  523
const int PIRSensor = 2;
const int ledPin =  13;
int sensorValue = 0;
void setup() {
  pinMode(PIRSensor, INPUT);
  pinMode(ledPin, OUTPUT);
}
void loop() {
sensorValue = digitalRead(PIRSensor);
if (sensorValue == HIGH) { 
    // Object detected, turn on LED, sound the buzzer for 1 second
    tone(8, NOTE_C5);
    digitalWrite(ledPin, HIGH);
    delay(1000);
}else{
    // No object detected, turn off LED, mute the buzzer
    noTone(8);
    digitalWrite(ledPin, LOW);
}




看看Youtube上的示範:



2017/02/12

APP Privacy Policy

PRIVACY POLICY

This privacy policy governs your use of the software applications (“Application”) for mobile devices that was created by Ryan Chen & Stonez Chen. These Applications are for tutorial purposes to demostrate the capability of App Inventor with educational purposes.

What information does the Applications obtain and how is it used?

User Provided Information 
These applications obtain the information from you merely used for Google and Yandex API to collect voices related information and for translation purposes.
Automatically Collected Information 
Our applications do not collect your personal information at all.

Does the Application collect precise real time location information of the device?

This Application does not collect precise information about the location of your mobile device. 

Do third parties see and/or have access to information obtained by the Application?

Voice data were transmitted to external  Google and Yandex servers for translation purposes.

What are my opt-out rights?

You can stop all collection of information by the Application easily by uninstalling the Application. You may use the standard uninstall processes as may be available as part of your mobile device or via the mobile application marketplace or network.

Data Retention Policy, Managing Your Information

We will NEVER retain any User Provided data at our database.

Children

We do not use the Application to knowingly solicit data from or market to children under the age of 13. If a parent or guardian becomes aware that his or her child has provided us with information without their consent, he or she should contact us at stonez.chen@gmail.com We will delete such information from our files within a reasonable time.

 

Security

There is no concerns of security, since we do not collect personal information.

Changes

This Privacy Policy may be updated from time to time for any reason. We will notify you of any changes to our Privacy Policy by posting the new Privacy Policy here and informing you via email or text message. You are advised to consult this Privacy Policy regularly for any changes, as continued use is deemed approval of all changes. You can check the history of this policy by clicking here.

Your Consent

By using the Application, you are consenting to our processing of your information as set forth in this Privacy Policy now and as amended by us. "Processing,” means using cookies on a computer/hand held device or using or touching information in any way, including, but not limited to, collecting, storing, deleting, using, combining and disclosing information, all of which activities will take place in the United States. If you reside outside the United States your information will be transferred, processed and stored there under United States privacy standards. 

Contact us


-->
If you have any questions regarding privacy while using the Application, or have questions about our practices, please contact us via email at stonez.chen@gmail.com

2017/01/14

MIT App Inventor 2 - Voice Recognition

Hi Guys, I wished you all had a happy holidays!

It's been a while since I published my last tutorial.  This morning, when I checked MIT App Inventor 2 web editor, I found few new interesting new components.

One of them specially caught my eyes is the "SpeechRecognizer" under Media block.
Checked the explanation on the right, I decided to do a quick test on this new component.


What I want to do here is very simple:
  1. Click "Speak" button to talk to the App
  2. The App send the voice to SpeechRecognizer 
  3. The App then show the particular sentence into a Text next to "You've said"

Here is the Screen1 Layout:
Here are all the components I've used in this tutorial, a button, two labels, and SpeechRecognizer1 component as shown below.





Here are the programming blocks. Only few blocks to get the Speech Recognizer to work. I was very surprised!

First, initial varibles and text to blank or "".

Secondly, when "SpeakBTN" clicked, just call "SpeechRecognizer1" to GetText. 




After get your Voice to Text, just set it to label.







Well, that's all need you do do the complete Voice Recognizer App.
See the YouTube Video for the demo below.



I guess you might want to give it a try now!

The End.
==================================================================
哈囉大家好,但願大家都有一個開心的假期!

距離上次我發布新的教學已經有一段時間 了。這個早上,我在查看MIT App Inventor 2時
我發現了幾個有趣的新東西。

第一個吸引我的目光的是音樂裡的「聲音辨識」。看一下解釋後,我決定針對這個新東西做個小測試。

我要做的測試非常簡單:

  1. 按下「說話按鈕」後對他說話
  2. 程式把你說的話丟給聲音辨識系統
  3. 辨識完後再將你說的話顯示出來

Here is the Screen1 Layout:
下圖是這次測試所用到的原件,一個按鈕、兩個文字元件和一個聲音辨識元件。





這些是程式方塊。其實,只要這些方塊就能使聲音辨識起作用讓我還蠻驚訝的呢!

首先,先設定變數和把文字設定成空格。


再來,當「說話按鈕」被按下時,就叫聲音辨識元件辨識並得到字串.








當系統辨識完後,就將它設成文字。








只要有上方這幾行程式就能完成你的聲音辨識App了。
請觀看底下的示範影片。


我想你現在一定迫不及待想去試試看了吧!