PC and PC troubles

05/27/2017

肩を温める USB電源(5V)を使った自作ヒーター

Img_20170527_071241 50肩になってしまった。就寝中に肩が冷えると痛みが増す。肩部を温めるための何かいい方法は無いものかと探していたが、そのようなものは、意外に見つからない。別の電子工作のアイデアを探していた時、カメラレンズや鏡筒のための「結露対策ヒーターの作り方」というブログに出会った。
USB(5V)から電源をとり、1mほどの長さのニクロム線に500mAの電流を流してレンズなどを温めるというアイデアになっている。この方法を応用できないか・・・とやってみた。


僕は、Amazonから これに必要な部品①,②を購入
①単位長さ当たりの抵抗値が、参考にしたブログに記載のものと同等レベルのニクロム線 (557円、送料込み)
  ワイヤ径0.4mm、  抵抗値 8.674Ω/m、 AWG26、 15m巻き
  使うのは1mほどの長さなのだが、この単位でしか購入できなかった。

注記)抵抗線は、線径が細くなるほど単位長さ当たりの抵抗値が高くなる。
 用途に応じて線径を決めるのが良い。
  (例) 矢印(⇒)の右側は、10Ωになる抵抗線(ニクロム線)の概略長さ
    0.7mm - 2.93Ω/m ⇒ 341cm
    0.6mm - 4.103Ω/m ⇒ 244cm
    0.5mm - 5.755Ω/m ⇒ 173cm 
    0.4mm - 8.674Ω/m ⇒ 115cm
    0.3mm - 15.42Ω/m ⇒ 65cm
    0.25mm - 22.21Ω/m ⇒ 45cm

②耐熱ガラスチューブ内径1.5mm (@156円+配送料560円)
  1mの長さがこの値段。使うのは1.2mほどになるので、1mでは短い・・・
  不足する長さの分については、僕は細目の熱収縮チューブを使った。
  実は、細い熱収縮チューブも購入し、ニクロム線をその中に入れようとしたが、50cmほど挿入したところから、挿入する抵抗が高くなり、1mのニクロム線を貫通させることは無理そうなので、耐熱ガラスチューブを使うことにした。この問題は透水性がありそうなので、電気の絶縁性能がどうかな・・・と不安である。

 その他、アッセンブリに必要な部品として、熱収縮チューブ、圧着スリーブ、自己融着テープ、USBケーブル、モバイルバッテリー等があるが、身の回りにあるものから、かき集めた。

参考にしたブログにも注意事項が細かく書かれていたが、
私がここに書いているのは私のメモであって、これと同じようなものを作ろうとして、いかなる事故が起きたとしても、私は一切の責任を負いません。自作するに際しての責任は、全てあなたの自己責任になります。

《作り方》

Img_20170526_115611 Img_20170526_120530結露対策ヒーターの作り方」を参考に、5V、500mAでほのかに温かいという仕様にすべく、抵抗線(ニクロム線)の値も市販品から 8.674Ω/m のものを選んで、入手後プラスチックスケールの上に抵抗線を貼り付け、20cm当たりの抵抗値を実測してみた。
抵抗値は 1.7Ωであった。

そのため、抵抗値が10Ωになるように、抵抗線の長さをほぼ 118cmと決めた。

Img_20170526_125638 Img_20170526_132144 Img_20170526_124651 Img_20170526_132550 ニクロム線は、絶縁のない裸状態なので、ショートさせたりする危険性を避けるために、
耐熱ガラスチューブを被せ、ガラスチューブ長さが不足する両端部を細目の熱収縮チューブを被せて、写真のようにニクロム線を被覆した。
バッテリーに繋いでみたが、この状態ではずっと手で握って居られるほど低い温度である。
多分、
耐熱ガラスチューブの効果が高すぎるのかもしれない。しかし、ガラスチューブ表面の温度は時間が経過すれば、内部も外部も同じ状態(平衡状態)になるはずである。

耐熱ガラスチューブを使わず、熱収縮チューブを使って絶縁するという(参考にしたブログと同じ)方法もあるが、細い熱収縮チューブを使うと、0.4mmの径のニクロム線を1mの長さ通すのは至難の業が必要になる。ガラスチューブは接触抵抗が低いので、難なく通すことが出来る。

肩用のサポータにこのニクロム線を縫い付けるのだが、ニクロム線の長さはある程度必要なため、温度を上げるためにニクロム線長さを短縮したくはないので、当初計画通り10Ωを保持する長さのままとした。

Img_20170526_133605 Img_20170526_161449 Img_20170526_161513 USBケーブルの端を開き、圧着スリーブを用いてニクロム線と接続した。この上にも太めの熱収縮チューブを被せ、その後、自己融着テープを用いて絶縁保護とその部分の補強を行った。


《使用の状況》

温かさ : 組込む前に、もう少し細かく詰めれば良かった。温度は低めで、もう少し上げられれば・・・と思う。

ニクロム線の配置間隔をもう少し詰めた方が良さそうに思う。そのためには、ニクロム線の単位長さ当たりの抵抗値をもう少し低いものを使って、扱える線の長さを延ばし配置すればと考えられる。

例えば前述の「線径-単位長さ当たりの抵抗値」を参考に、0.6mmの線径の抵抗線を使えば、10Ωとするには244cmとれる為、今回使った線径0.4mmの線配置の空いた場所に線を配置できる。そのため、面当たりに近づき、より「ほんわか」した温かさを実現できそうだ。

05/14/2017

Arduino用mp3シールドを使い TVリモコンで指定したMP3ファイル再生

Mp3tf16p_controlled_by_tv_ir_remote Img_20170514_112430 MP3-TF-16Pを使って、MP3形式で保存したファイルを、TVリモコンを使って再生する方法。
ブレッドボードを使った回路図は左側、実際に組んだ回路は右側のようになる。



Mp3tf16p_controlled_by_tv_ir_remo_2左は、Fritzingで記載した回路図。


MP3-TF-16Pで使うマイクロSDカードに保存するファイルは、ファイルを保存した順番とファイル(番号)名を合わせておく必要がある。すなわち「0001.mp3」「0002.mp3」・・・「0013.mp3」のように、ファイル(トラック)番号を書かなければいけない。

sketchでは、赤外線受信で受け取ったREGZA TVリモコンの信号を、switch-case制御文を使って条件分岐させて、各条件(ここではTVチャンネル番号)に合わせたmp3音源ファイルを1つだけ再生するようにしている。
(注記)僕が使っている東芝のREGZA TV の赤外線コントローラー信号は、ここで受信したものを使っている。

TVリモコンの10チャンネルを赤外線受信で受け取ると、16進数で「0A」、11チャンネルは「0B」、12チャンネルは「0C」となるので、case分ではその16進数を使う必要があるので、間違えないように・・・。

mp3の音源ファイルを1つ、例えば3番目のファイル(0003.mp3)を演奏するには、case文 0x03 のところに、
  myDFPlayer.play(3); と書けばよい。

また、11番目のファイル(0011.mp3)を演奏する場合には、case文 0x0B のところに、
  
myDFPlayer.play(11); と書けばよい。


《sketch》

/*************************************************************************************** 
MP3-TF-16P(DFPlayer) - A Mini MP3 Player for Arduino controlled by TV-remote
****************************************************************************************/
#include "Arduino.h"
#include <SoftwareSerial.h>
#include "DFRobotDFPlayerMini.h"
#define IR_PIN      2             // 赤外線受信モジュール接続ピン番号
#define DATA_POINT  3             // 受信したデータから読取る内容のデータ位置 東芝REGZA TV
SoftwareSerial mySerial(10,11); // RX, TX
DFRobotDFPlayerMini myDFPlayer;
#include <Wire.h>                 // ライブラリ内部で使用するので定義必要

void setup()
{
    Serial.begin(115200) ;       // パソコン(ArduinoIDE)とシリアル通信の準備を行う
    mySerial.begin(9600);
    pinMode(IR_PIN,INPUT) ;       // 赤外線受信モジュールに接続ピンをデジタル入力に設定

    if (!myDFPlayer.begin(mySerial)) {  // Use softwareSerial to communicate with mp3.
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    while(true);
  }
  Serial.println(F("MP3-TF-16P(DFPlayer Mini) online."));
  myDFPlayer.volume(25);               //Set volume value. From 0 to 30
  Serial.println("起動しました") ;
}
void loop()
{
    int ans ;
    ans = IRrecive() ;                 // 赤外線リモコンのデータを受信する
        if (ans != 0) {
            Serial.println(ans,HEX) ; // REGZA TV リモコンからデータを受信し番号に準じて発音

            switch(ans) {
            case 0x01: 
                Serial.println("覚悟を決めましょう") ;
                myDFPlayer.play(1);
                break ;
                
            case 0x02:
                Serial.println("神の裁きを") ;
                myDFPlayer.play(2);
                break ;
                
            case 0x03:
                Serial.println("ベートーベンの運命") ;
                myDFPlayer.play(3);
                break ;
                      
            case 0x04:
                Serial.println("運命") ;
                myDFPlayer.play(4);
                break ;
                
            case 0x05:
                Serial.println("スキ有り") ;
                myDFPlayer.play(5);
                break ;
                
            case 0x06:
                Serial.println("悔い改めよ") ;
                myDFPlayer.play(6);
                break ;
                
            case 0x07:
                Serial.println("こいつは厄介そうじゃな") ;
                myDFPlayer.play(7);
                break ;
                
            case 0x08:
                Serial.println("ついに迎えが") ;
                myDFPlayer.play(8);
                break ;
                
            case 0x09:
                Serial.println("大勢で拍手") ;
                myDFPlayer.play(9);
                break ;
                
            case 0x0A:
                Serial.println("学校のチャイム") ;
                myDFPlayer.play(10);
                break ;
                                
            case 0x0B:
                Serial.println("うっそお!") ;
                myDFPlayer.play(11);
                break ;
                                
            case 0x0C:
                Serial.println("ぱんぱかぱ~ん") ;
                myDFPlayer.play(12);
                break ;  
           }
     }
}
// 赤外線リモコンのデータを受信する処理関数
int IRrecive()
{
     unsigned long t ;
     int i , j ;
     int cnt , ans ;
     char IRbit[64] ;

     ans = 0 ;
     t = 0 ;
     if (digitalRead(IR_PIN) == LOW) {
          // リーダ部のチェックを行う
          t = micros() ;                               // 現在の時刻(us)を得る
          while (digitalRead(IR_PIN) == LOW) ;         // HIGH(ON)になるまで待つ
          t = micros() - t ;                           // LOW(OFF)の部分をはかる
     }
     // リーダ部有りなら処理する(3.4ms以上のLOWにて判断する)
     if (t >= 3400) {
          i = 0 ;
          while(digitalRead(IR_PIN) == HIGH) ;          // ここまでがリーダ部(ON部分)読み飛ばす
          // データ部の読み込み
          while (1) {
               while(digitalRead(IR_PIN) == LOW) ;      // OFF部分は読み飛ばす
               t = micros() ;
               cnt = 0 ;
               while(digitalRead(IR_PIN) == HIGH) {     // LOW(OFF)になるまで待つ
                    delayMicroseconds(10) ;
                    cnt++ ;
                    if (cnt >= 1200) break ;            // 12ms以上HIGHのままなら中断
               }
               t = micros() - t ;
               if (t >= 10000) break ;                  // ストップデータ
               if (t >= 1000)  IRbit[i] = (char)0x31 ;  // ON部分が長い
               else            IRbit[i] = (char)0x30 ;  // ON部分が短い
               i++ ;
          }
          // データ有りなら指定位置のデータを取り出す
          if (i != 0) {
               i = (DATA_POINT-1) * 8 ;
               for (j=0 ; j < 8 ; j++) {
                    if (IRbit[i+j] == 0x31) bitSet(ans,j) ;
               }
          }
     }
     return( ans ) ;
}


《参考資料》

①MP3-TF-16Pを使ったArduinoとの結線・mp3ファイルの再生方法
 「Electronic Circuit Projects」の中の「
Mp3 Player Using Arduino and DFPlayer 」より
 ここにあるDFPlayerは、私が使ったMP3-TF-16Pと基本的に同じもののようだ。
 僕は、RX,TXの接続部分を参考にさせてもらった。

②IR TVリモコンの解析
 赤外線通信の実験パート2
 (赤外線リモコンを送信器にして何か動かす)
 ここに書かれている赤外線受信のサンプル回路はシンプルなので、実験もやり易い。
 赤外線受信解析のスケッチも、ここのスケッチを使わせてもらった。


③コントロール方法
 DFPlayer Mini SKU:DFR0299
 ここでは「DFPlayerMini」を使ってArduino用のMP3プレーヤーのコントロール方法について記載されているが、私が使った「MP3-TF-16P」もほぼ同じなので、スケッチなどは大変参考になった。一部のコードを、私のスケッチへコピーして使わせてもらっている。

④MP3音声ファイル(著作権フリー素材)

 効果音ラボ よりdownloadし、使わせて戴きました。

 

05/08/2017

TWE-Lite 半完成品セミキットで通信が出来ないと思ったら・・・

TWE-Liteを使ったおもちゃを作ろうと思い、「TEW-Lite DIP-PCB (半完成品セミキット)」を2個追加購入した。半完成品なので自分でコネクタを半田付けしなくてはいけないが、価格が300円ほど安価であるし、自分の半田付け技術は悪くないと思っているので、安価なセミキットを購入した。
部品到着後、早速半田付けして、ブレッドボード上で回路を組み立て試験してみたが、回路が動かない・・・。
それほど難しい回路構成でもないので、何が悪いのだろうと悩んでしまった。

Img_20170508_093812 Img_20170508_093826 Img_20170508_093844 二日後、Lチカ回路での問題が無いかを確認すると・・・、
①DI1、DI2はプッシュボタンを押していないのに、電源を入れた段階で既に子機側のLEDが点灯している!

②DI3、DI4はプッシュボタンに連動してLEDが点灯する。

プッシュボタンの設置には問題が無い・・・回路図とブレッドボード上の配線を何度も見直してみるが、間違いはない。
TWE-Liteを疑ってみた。電源投入後に親機側の押しボタンがONになっている事から、テスターでDI1、DI2、DI3、DI4 とGND間の抵抗をあたってみた。
DI1、DI2は、導通している!
DI3、DI4
は、高い抵抗値を示している。

Img_20170508_094043 ブレッドボード上で差し替えして、多分問題が無さそうだったTWE-LiteについてDI1、DI2、DI3、DI4とGND間の抵抗値を図ってみると、DI1、DI2、DI3、DI4全てが高い抵抗値を示している。
今回2個のTWE-Liteを購入したが、1個は壊れている! 半完成品なので、納品された当初からの問題なのか、私が半田付けしブレッドボード上で回路を組立していた時に壊してしまったのかは定かではない・・・。
今回TWE-Liteを使って造ろうと思っていた「おもちゃ」へのモチベーションが一気に下がってしまった・・・。

次にTWE-Liteを購入する際には、完成品を買った方が良さそうだ。

05/03/2017

TVリモコンを使ってArduinoに喋らせる

Img_20170503_154904 Img_20170503_083736 家電用リモコンを利用して、Arduinoから音を発する装置を考えた。(左写真:試作完成品)
家電のリモコンは容易に入手できるし、コントローラを新たに製作する時間を短縮することが出来る。ただし、TVリモコンは赤外線式なので、見通し出来る場所でしか使えないが、5mぐらいの距離なら問題なく使う事が出来るだろう。


.
Img_20170503_210742 先ず、コントロールするには、赤外線リモコンの制御信号を入手する必要がある。それで、下記のブログを参考にして、リモコンの制御信号を確認した(上写真右側)。この装置は、下表の状況が分かれば要らなくなるが、各種リモコンのコードを解析するのには簡単に作成でき良いものだなぁと思う。

僕の手元にある東芝REGZAのデジタルTVリモコン(CT-90451)のコードは、次のようになっていた。


.

東芝REGZA デジタルTVリモコンコード

  受信コード                         ボタン名称
00000010111111011000000001111111 ( 40 BF 1 FE )   1
00000010111111010100000010111111 ( 40 BF 2 FD )   2
00000010111111011100000000111111 ( 40 BF 3 FC )   3
00000010111111010010000011011111 ( 40 BF 4 FB )   4
00000010111111011010000001011111 ( 40 BF 5 FA )   5
00000010111111010110000010011111 ( 40 BF 6 F9 )   6
00000010111111011110000000011111 ( 40 BF 7 F8 )   7
00000010111111010001000011101111 ( 40 BF 8 F7 )   8
00000010111111011001000001101111 ( 40 BF 9 F6 )   9
00000010111111010101000010101111 ( 40 BF A F5 )   10
00000010111111011101000000101111 ( 40 BF B F4 )   11
00000010111111010011000011001111 ( 40 BF C F3 )   12
00000010111111010100100010110111 ( 40 BF 12 ED ) 電源

したがって、受信したデータから読取る内容のデータ位置は 「3」 となる。


《Fritzingで描いた回路》

Tv 図中左が Arduino UNO で、
右側は、ブレッドボード上 中央部に配置した ATP3012F6-PU と関連する周辺部品である。

僕が製作した実物は、Arduinoユニバーサル プロトシールド基板の上に小型のブレッドボードを貼り付けたものに
ATP3012F6-PU を挿して配線したが、赤外線受光部はブレッドボード基板に載せきれなかったので、基板の上に半田付けしてある。

発生する音声は、上図にあるようなスピーカー直付けでは聞こえないほど音が小さいので、アクティブスピーカーを繋いで聞くのが良い。


《使い方》
TVリモコンをシステムの受光部に向けて、「1」~「6」及び「電源」のキーを押すと、Arduinoが、スケッチに書いた言葉を「女性の声で・・・」発する。
1:ただいま解析中
2:脈拍が上昇しています
3:ゆっくりしていってね
4:よろしいですか?

5:チャイム音J(ポンという音)
6:チャイム音K(ピンという音)
電源:連続チャイム音(JとKの組み合わせ音)

スケッチプログラムの中で、ローマ字で書いてある部分を
ATP3012F6-PUが読んでくれる。
番号に対応するところを、この使用者が変更すればいろいろな言葉で言い変えることが出来る。話す言葉の書き方は、音声合成LSIのデータシートの所に文法が書かれているので、これを参考にして記載するのが良い。

《使用部品》
①Arduino UNO互換品 : Arduino UNO R3 (keyestudio)互換品 1個
              Amazonで1020円ほどの値段で購入できる。

②赤外線受光器(1個): PL-IRM2121(38kHz)  秋月電子通商より購入
          データーシート Vcc=5V、220Ω抵抗と4.7μF コンデンサが必要

③音声合成LSI(1個): ATP3012F6-PU (女性の音声明瞭版) 秋月電子通商より購入
          データーシート 

 (注意) ATP3012 と ATP3011の主な違いがこのデータシート17ページに記載されている。動作クロックが外付けになり、セラミック振動子などの外付けデバイスが必要。また、AOUT/PMOD1の端子が入れ替わっているなど変更点があるので注意を要する。

④セラミック振動子(1個) : コンデンサ内蔵タイプ 20MHz ㈱村田製作所製 秋月電子通商より購入

⑤その他部品、
 1kΩ、220Ω抵抗(各1個)と 4.7μF コンデンサ(1個)、
Arduino用ユニバーサルプロトシールド基板(1枚)ピンソケット 1x6 (1枚)、1x8 (2枚)、1x10 (1枚)、ミニブレッドボード BB-601(1個)、ジャンパーケーブル用として 耐熱通信機用ビニル電線 導体系0.65mm 単芯


《Sketch》

// TV リモコンからチャネル番号を読み取り他の制御に使う
#define IR_PIN      2    // 赤外線受信モジュール接続ピン番号
#define DATA_POINT  3    // 受信したデータから読取る内容のデータ位置 東芝REGZA TV

#include <AquesTalk.h>
#include <Wire.h>        // ライブラリ内部で使用するので定義必要

AquesTalk atp;         // インスタンス定義

void setup()
{
    Serial.begin(9600) ;    // パソコン(ArduinoIDE)とシリアル通信の準備を行う
    pinMode(IR_PIN,INPUT) ;  // 赤外線受信モジュールに接続ピンをデジタル入力に設定
}

void loop()
{
    int ans ;
     
    ans = IRrecive() ;       // 赤外線リモコンのデータを受信する
        if (ans != 0) {
            Serial.println(ans,HEX) ; // REGZA TV リモコンからデータを受信し番号に準じて発音
            switch(ans) {
            case 0x01: 
                Serial.println("ただいま解析中") ;
                atp.Synthe("tadaima/kaisekichuu.");
                break ;
            case 0x02:
                Serial.println("脈拍が上昇しています") ;
                atp.Synthe("myakuhakuga/jyoushoushiteimasu.");
                break ;
            case 0x03:
                Serial.println("ゆっくりしていってね") ;
                atp.Synthe("/yukkuri_siteittene?");
                break ;         
            case 0x04:
                Serial.println("よろしいですか?") ;
                atp.Synthe("yorosi'ide_suka?"); 
                break ;
            case 0x05:
                Serial.println("チャイム音J") ;
                atp.Synthe("#J");
                break ;
            case 0x06:
                Serial.println("チャイム音K") ;
                atp.Synthe("#K");
                break ;
            case 0x12:
                Serial.println("連続チャイム音") ;
                atp.Synthe("#K");
                atp.Synthe("#K");
                atp.Synthe("#K");
                atp.Synthe("#J");
                break ;
           }
     }
}
// 赤外線リモコンのデータを受信する処理関数
int IRrecive()
{
     unsigned long t ;
     int i , j ;
     int cnt , ans ;
     char IRbit[64] ;

     ans = 0 ;
     t = 0 ;
     if (digitalRead(IR_PIN) == LOW) {
          // リーダ部のチェックを行う
          t = micros() ;                           // 現在の時刻(us)を得る
          while (digitalRead(IR_PIN) == LOW) ;     // HIGH(ON)になるまで待つ
          t = micros() - t ;                       // LOW(OFF)の部分をはかる
     }
     // リーダ部有りなら処理する(3.4ms以上のLOWにて判断する)
     if (t >= 3400) {
          i = 0 ;
          while(digitalRead(IR_PIN) == HIGH) ;     // ここまでがリーダ部(ON部分)読み飛ばす
          // データ部の読み込み
          while (1) {
               while(digitalRead(IR_PIN) == LOW) ; // OFF部分は読み飛ばす
               t = micros() ;
               cnt = 0 ;
               while(digitalRead(IR_PIN) == HIGH) {// LOW(OFF)になるまで待つ
                    delayMicroseconds(10) ;
                    cnt++ ;
                    if (cnt >= 1200) break ;       // 12ms以上HIGHのままなら中断
               }
               t = micros() - t ;
               if (t >= 10000) break ;             // ストップデータ
               if (t >= 1000)  IRbit[i] = (char)0x31 ;  // ON部分が長い
               else            IRbit[i] = (char)0x30 ;  // ON部分が短い
               i++ ;
          }
          // データ有りなら指定位置のデータを取り出す
          if (i != 0) {
               i = (DATA_POINT-1) * 8 ;
               for (j=0 ; j < 8 ; j++) {
                    if (IRbit[i+j] == 0x31) bitSet(ans,j) ;
               }
          }
     }
     return( ans ) ;
}

《参考にしたブログ》
①音声合成LSIの使い方
 「N.Yamazaki's blog」 Arduino用 音声合成LSIライブラリの利用方法記述部分から、「Arduino_AquesTalk_Library」をDownloadし、簡単な使い方を参考にスケッチ作成を行った。

②赤外線通信について
 「赤外線通信の実験パート2」
(赤外線リモコンを送信器にして何か動かす)
 ・赤外線受信のサンプル回路及びスケッチプログラムを参考に、こちらの状況に合わせて修正するための参考にさせて戴いた。


 ・赤外線受信の回路は、使っている素子が違うため、素子のデータシートを参考にして、使う抵抗とコンデンサを配置し、信号の解析を行った。
 そのためのスケッチは、
赤外線受信モジュール接続ピン番号は同じく「2」に設定し、シリアルポートを此方の状況に合わせただけで、エラー無く稼働させることが出来た。

 ・赤外線リモコンからのデータ受信では、ダウンロードさせて戴いたスケッチに対して、
 IRピンの番号は同じ、受信したデータから読取る内容のデータ位置を「3」に変更して使うことが出来た。

 ・switch文の分岐で、caseの後にSerial.print文を追記して分岐が正しく行われたか否かをシリアルモニタで確認できるようにした。


《参考資料》
①赤外線受光器 使用部品の行を参照の事。
②音声合成LSI ATP3012F6-PU 使用部品の行を参照の事。

04/28/2017

Deek-RobotのData logging shield V1.0を使ってArduino Spyカメラ

Ethernet Shield を使った通信がうまく行かないので、Deek-Robot の Data logging shield V1.0 を使ってこのシステムの小型化を図ってみた。写真のようにコンパクトに出来上がっているが、基本的な回路図は、前回のEthernet Shield を使ったものとほぼ同じで、違っているのは Deek-Robot の Data logging shield V1.0 の CSピンが10 なので、この変更を行っている。
4c4dcb61529951a4016055086123b004 Img_20170428_125755 Img_20170428_125816 Img_20170428_125902 コンパクトに納めるために、僕はシールドの中ほどに写真のように棚を設けて部品を配置した。



Img_20170428_205246 Img_20170428_205416Img_20170428_204948_2 一番下の階層は、Arduino UNOで、第二階層が Deek-Robot の Data logging shield V1.0 で、その空いたボード部分に、PIRセンサ(SainSMART製Pyroelectric Infrared PIR Motion Sensor Detector Module for Arduino)(保持時間:約8秒~15分以上、半固定抵抗[Tx]で調整、最大検知距離:7m(気温等の環境条件による)、半固定抵抗[Sx]で調整)、小型TTLシリアルJPEGカメラ(NTSCビデオ出力付 いわゆる VC0706 )[adafruit PRODUCT ID: 1386]、電子ブザー(PB04-SE12HPR)、LEDを配置した。


LEDについて、
写真左側の青いLEDは、PIRが検出中に点滅し、検出した際には点灯する。右側の赤いLEDはSDカードにデータを書き込み中に点灯する。書き込みが終われば消灯する。
半田付けしてから気づいたが、LEDの取付けはカメラの向く方向に足を曲げられるように配置すべきだった。また、電流が多く流れる為明るいが、少し省エネを狙い、10kΩの抵抗を入れた。後で直しておこう。


写真のファイル名称
は、
 PIC_X.JPG という名前で保存される。
 システムが稼働して第1枚目の写真が撮れない。タイミングの問題か?
 

SDカードは、
 手持ちの下記カードで書き込みOK
  microSD
 2GB
  SDHC ⑩ 4GB, 8GB
   
  で撮影出来た。
 写真の1枚当たりの容量は、320x240サイズの場合 約12KBである。



Img_20170519_161530 Img_20170519_162101左の写真のように、100均ショップでお弁当箱を購入してここにシステムとバッテリーを合わせて入れた。
当初、前述の写真にあるようにシステム全てを弁当箱の中に入れたが、このケースの蓋は約3㎜の厚みが有り、PIRセンサーが稼働してくれなかった。そのため、弁当箱の蓋の部分に穴を明けて、センサーの樹脂ドームのみ顔を出すように改造した。電池は18650 3200mA 2本を直列にして自立型で左写真の右側のように設置した。しかし、5~6時間ほど経過した後で設置場所を確認に行くと、検出ランプが停まってしまった。
システムに流れている電流値を測定すると、約135mAあり、約0.7Wの消費電力にあることがわかった。これでは約5時間しか持たなかったことが理解できる。このシステムで続ける場合、電源の容量をアップする必要がある。AC電源からとるようにするか、大容量のバッテリーに繋ぐか・・・検討する必要がありそうだ。


<<Sketch上の注意点>>

①Deek-Robot の Data logging shield V1.0のピン配置
  D10 - Chip Select これに合わせて前回のスケッチを修正した。
  D11 - SPI MOSI
  D12 - SPI MISO
  D13 - SPI SCK

②スケッチで読み込むライブラリーは、下記のみを「library」の中に置く事とする。
 ・JPEGCamera
     このライブラリーは、ここにあるので、zipファイルでダウンロードしてくること。
③シリアルモニターの通信速度(シリアルモニターの画面右下部)は、38400bpsに設定すること。

④Warningメッセージは出るが放置。システムの稼働には問題無いようだ・・・。

⑤僕が使っているPIRは、前述したものだが、SxとTxの調整によっては、このスケッチで旨く動かない可能性もある。
 僕は、Sxを右一杯近くまで回し、抵抗値は凡そ620kΩの辺りに、ただし、検出できる距離がどの程度になっているかは、調べることが出来なかった。
 Txはセンサーの保持時間を決めるもので、Tx ≒ 24567×R10×C6(=0.01μF) の計算式で計算できる。僕は半固定抵抗を左回りにほぼ一杯近くまで回して、約820Ωの値にした。Txは約0.2秒になる。

それで、下記のスケッチのPIRによる検出部分周辺を一部書き直した。(2017/05/21)


<<Skech>>
/**
 * VC0706 Camera Module Arduino Compatible:
 *  + cvbs: N/A
 *  + 5V: connected to arduino => pin 5V0
 *  + TX (OUT): connected to the RX (IN) of arduino => pin 2
 *  + RX (IN): connected to the TX (OUT) of arduino => pin 3
 *  + GND: connected to the GND
 *  set the serial monitor 38400bps when use it
 *  PIR sensor: connected to arduino => pin 6 
 */

#include <SoftwareSerial.h>
#include <SPI.h>
#include <SD.h>
#include <JPEGCamera.h>

const int chipSelect = 10;  // I changed this CS value
int pirPin     =  6;  // PIR sensor
int pirState =  LOW;  // states of PIR at the initial
int buzzerPin  =  5;
int ledPin1    =  8;  // PIR LED Flashing(ready) ⇒ Lighting(detected)
int ledPin2    =  7;  // SD Light off ⇒ Lighting(busy)

File testFile;
SoftwareSerial s(2, 3);
JPEGCamera cam(s);
char filename[15];
int num = 0;
int numOfBytes;

int photoSize = 1; // 0 -> 160x120 / 1 -> 320x240 / 2-> 640x480
unsigned long mainStartTime, mainEndTime, startTime, endTime;

void setup()
{
//activate 5V for the SD Card shield
  Serial.begin(38400);
  Serial.println("Start of SPY Camera SetUp");
  pinMode(   pirPin,  INPUT); 
  pinMode(  ledPin1, OUTPUT); 
  pinMode(  ledPin2, OUTPUT); 
  pinMode( buzzerPin,OUTPUT);
  digitalWrite(ledPin1, LOW);       // LED:OFF
  digitalWrite(ledPin2, LOW);       // LED:OFF
  
  Serial.begin(38400);
// Wait for the serial port to be opened
   while (!Serial) delay(25);
 
//check SD card
  while (!SD.begin(chipSelect))
    {
      Serial.println("Error: SD initialization failed. Is SD card in the card folder?");
    }
      Serial.println("Info: SD Initialization complete,");

// Serial port connected to the cam
    s.begin(115200); //for VC0706 cam
    delay(50);

    Serial.println("Info: Reseting cam...");
// reset cam and wait.
    cam.reset();
    delay(3000);

    Serial.println("Info: Changing baud rate...");
// change baud rate to work at 3.3v
    cam.chBaudRate(2);// 0 -> 9600 / 1 -> 19200 / 2 ->  38400 / 3 -> 57600 / 4 -> 115200
    delay(50);
  
//change serial to match new camera baud rate
    s.end();
    s.begin(38400);
    delay(50);

  Serial.println("Info: Changing picture size...");
//change picture size
  cam.chPictureSize(photoSize);
  delay(50);

  Serial.println("Info: getting last pic num for the created files...");
  num = getNewSDFileNum();
  Serial.println("Info: Setup is DONE!");
  Serial.println("Start Detecting");
}

void loop()
{
  while(digitalRead(pirPin) == LOW )
  {
    digitalWrite( ledPin1, HIGH);
    delay(100);
    digitalWrite( ledPin1,  LOW);
    delay(100);
  }

  pirState = digitalRead(pirPin);   // read the state of PIR sensor
   digitalWrite(  ledPin1, HIGH);   // LED :ON
   digitalWrite(buzzerPin, HIGH);   // Warnig Buzzer ON                         
   Serial.println("Some movements were detected!");
   takePic();
}

void takePic()
{
  Serial.println("Info: Preparing to take new photo.");

// must call stopPictures before a new photo is taken.
  cam.stopPictures();
  delay(50);

// take photo
  digitalWrite(buzzerPin,  LOW);   // Buzzer OFF
  digitalWrite(  ledPin1,  LOW);   // LED:OFF 
  cam.takePicture();
  delay(50);

  num++;
  sprintf(filename, "PIC_%i.JPG", num);

  if (SD.exists(filename)) {
    SD.remove(filename);
  }

// Create file
  digitalWrite( ledPin2, HIGH);     // LED :ON  
  testFile = SD.open(filename, FILE_WRITE);
  
//save to file
    Serial.print("Info: Saving photo to SD: ");
    Serial.println(filename);
    
    numOfBytes = cam.readData(testFile);

    Serial.print("Info: Bytes for photo: ");
    Serial.println(numOfBytes);

//must close file to finish writing.
  testFile.close();
    digitalWrite( ledPin2,  LOW);     // LED:OFF
    Serial.println("Info: saved picture that detected!");
}

int getNewSDFileNum() {
  File root = SD.open("/");
  int n = getFileLastNumForDirectory(root);

  root.close();
  return n > 0 ? n : 0;
}

int getFileLastNumForDirectory(File dir) {
  int n = 0;
  int fn = 0;

  while (true) {
    File entry =  dir.openNextFile();

    if (!entry) {
// no more files
      break;
    }

    fn = 0;

    if (entry.isDirectory()) {
      //fn = prepareFileLastNumForDirectory(entry);//no need to be recursively
    }
    else {
      String name = String(entry.name());

      if (name.startsWith("PIC_") && name.endsWith(".JPG")) {
        int pos = name.indexOf(".JPG");
        name = name.substring(4, pos);

        if (isValidNumber(name))
          fn = name.toInt();
      }
    }

    if (fn > n) {
      n = fn;
    }

    entry.close();
  }

  return n;
}

boolean isValidNumber(String str) {
  if (str && str.length() > 0) {
    for (byte i = 0; i < str.length(); i++)
    {
      if (!isDigit(str.charAt(i))) return false;
    }
    return true;
  }
  return false;
}

04/22/2017

PIRで検知しVC0706で撮影、Ethernet ShieldのmicroSDに記録

Pirethernet Arduino UNO にEthernet Shield と シールドボードに小型のブレッドボードを貼り付けた。
Fritzingで絵を描いてみると・・・左図のようになる。
一番下の階層は、Arduino UNOで、第二階層がEthernet Shield、その上の第三階層に自作のシールドボードを載せ小型のブレッドボードを装着して、そこに部品を配置した。
前回のようなSDカードシールドでは、ブレッドボードが小さいとそこに部品を置ききれないので、Ethernetシールドを使えないかと調べ、可能だという事が分かったので、トライしてみた。(注記:カメラの所にある2本の抵抗は、絵では220Ωになっているが、僕がFritzingを使いこなせていないために、間違った表記になっている。この抵抗の値は2本とも10kΩである。)


Dsc_0005Dscf9618 Dscf9621 Ethernet Shieldは、サードパーティ製のもので(写真にあるものはKeystudio製だが、他のメーカー製、例えば「HiLetgo W5100 Ethernet Shield
」等でも稼働した)、ただしMACアドレスのラベル添付も無かった。未だ Ethernet の接続は行っていないが、このShield に装備されている microSDカード装置部は、写真やFritzing にあるような Pin接続で問題なく使う事が出来た。

使用したMicroSD Cardは、Amazonで2GB⑩のものを購入し、「
SD Formatter」でフォーマットして使用。

また、ArduinoのSketchは、下記のようになった。

尚、マイコンボードに書き込み時、幾つかのWarningメッセージは出るが、稼働している。

システムが稼働し、セットアップが終了した後
・PIRが検知するまでの間、LEDランプ1を0.3秒間隔で点滅させて、システムが稼働している事が分かるようにした。
・PIRがものの動きを検知すると、LEDランプ1が点灯し、ブザーを1.5秒間鳴らし、その後写真を撮影する。
・撮影した写真をmicroSDカードに記録中は、別のLEDランプ2を点灯させる。
・SDカードへの記録が終われば
  LEDランプ2は消灯し、
  PIR検知中を示すLEDランプ1は点滅状態になる。

詳細は、後ほどここに記載するが、記載している時間が今は無いので、今日はここまで・・・

/**
 * VC0706 Camera Module Arduino Compatible:
 *  + cvbs: N/A
 *  + 5V: connected to arduino => pin 5V0
 *  + TX (OUT): connected to the RX (IN) of arduino => pin 2
 *  + RX (IN): connected to the TX (OUT) of arduino => pin 3
 *  + GND: connected to the GND
 *  set the serial monitor 38400bps when use it
 *  PIR sensor: connected to arduino => pin 6 
 */

#include <SoftwareSerial.h>
#include <SPI.h>
#include <SD.h>
#include <JPEGCamera.h>

const int chipSelect = 4;
int pirPin     =  6;  // PIR sensor
int pirState =  LOW;  // states of PIR at the initial
int buzzerPin  =  5;
int ledPin1    =  8;  // LED shows Ready(flashing) or Detected(lighting)
int ledPin2    =  7;  // LED shows SD card writing(lighting) or not

File testFile;
SoftwareSerial s(2, 3);
JPEGCamera cam(s);
char filename[15];
int num = 0;
int numOfBytes;

int photoSize = 1; // 0 -> 160x120 / 1 -> 320x240 / 2-> 640x480
unsigned long mainStartTime, mainEndTime, startTime, endTime;

void setup()
{
//activate 5V for the SD Card shield
  Serial.begin(38400);
  Serial.println("Start of SPY Camera SetUp");
  pinMode(  pirPin,  INPUT); 
  pinMode( ledPin1, OUTPUT); 
  pinMode( ledPin2, OUTPUT); 
  pinMode(buzzerPin,OUTPUT);  
  digitalWrite( ledPin1, LOW);       // LED:OFF
  digitalWrite( ledPin2, LOW);       // LED:OFF
  
  Serial.begin(38400);
// Wait for the serial port to be opened
   while (!Serial) delay(25);
 
//check SD card
  while (!SD.begin(chipSelect))
    {
      Serial.println("Error: SD initialization failed. Is SD card in the card folder?");
    }
      Serial.println("Info: SD Initialization complete,");

// Serial port connected to the cam
    s.begin(115200); //for VC0706 cam
    delay(50);

    Serial.println("Info: Reseting cam...");
// reset cam and wait.
    cam.reset();
    delay(3000);

    Serial.println("Info: Changing baud rate...");
// change baud rate to work at 3.3v
    cam.chBaudRate(2);// 0 -> 9600 / 1 -> 19200 / 2 ->  38400 / 3 -> 57600 / 4 -> 115200
    delay(50);
  
//change serial to match new camera baud rate
    s.end();
    s.begin(38400);
    delay(50);

  Serial.println("Info: Changing picture size...");
//change picture size
  cam.chPictureSize(photoSize);
  delay(50);

  Serial.println("Info: getting last pic num for the created files...");
  num = getNewSDFileNum();
  Serial.println("Info: Setup is DONE!");
}

void loop()
{
  while(digitalRead(pirPin) == LOW )
  {
    digitalWrite(  ledPin1, HIGH);
    delay(300);
    digitalWrite(  ledPin1, LOW);
    delay(300);
  }

  pirState = digitalRead(pirPin);   // read the state of PIR sensor
  if (pirState == HIGH) {           // detected => "HIGH", if not-detected => "LOW"
                                    // Detected!
   digitalWrite(  ledPin1, HIGH);   // LED :ON
   digitalWrite(buzzerPin, HIGH);   // Warnig Buzzer ON   
   Serial.println("Some movements were detected!");
   delay(1500);
   digitalWrite(  ledPin1, LOW);    // LED:OFF 
   digitalWrite(buzzerPin, LOW);    // Buzzer OFF  
   takePic();
  }
}

void takePic()
{
  Serial.println("Info: Preparing to take new photo.");

// must call stopPictures before a new photo is taken.
  cam.stopPictures();
  delay(50);

// take photo
  cam.takePicture();
  delay(50);

  num++;
  sprintf(filename, "PIC_%i.JPG", num);

  if (SD.exists(filename)) {
    SD.remove(filename);
  }

// Create file
  digitalWrite( ledPin2, HIGH);     // LED :ON 
  testFile = SD.open(filename, FILE_WRITE);

//save to file
    Serial.print("Info: Saving photo to SD: ");
    Serial.println(filename);
    numOfBytes = cam.readData(testFile);
    Serial.print("Info: Bytes for photo: ");
    Serial.println(numOfBytes);

//must close file to finish writing.
    testFile.close();
    digitalWrite( ledPin2,  LOW);     // LED:OFF
    Serial.println("Info: saved picture that detected!");
}

int getNewSDFileNum() {
  File root = SD.open("/");
  int n = getFileLastNumForDirectory(root);
  root.close();

  return n > 0 ? n : 0;
}

int getFileLastNumForDirectory(File dir) {
  int n = 0;
  int fn = 0;

  while (true) {
    File entry =  dir.openNextFile();

    if (!entry) {

// no more files
      break;
    }

    fn = 0;

    if (entry.isDirectory()) {
      //fn = prepareFileLastNumForDirectory(entry);//no need to be recursively
    }
    else {
      String name = String(entry.name());

      if (name.startsWith("PIC_") && name.endsWith(".JPG")) {
        int pos = name.indexOf(".JPG");
        name = name.substring(4, pos);

        if (isValidNumber(name))
          fn = name.toInt();
      }
    }

    if (fn > n) {
      n = fn;
    }

    entry.close();
  }

  return n;
}

boolean isValidNumber(String str) {
  if (str && str.length() > 0) {
    for (byte i = 0; i < str.length(); i++)
    {
      if (!isDigit(str.charAt(i))) return false;
    }
    return true;
  }
  return false;
}

Arduino EthernetシールドとSDライブラリーの利用に関してのメモ書き

SdFatライブラリー (2016/6/19にアップデートされている)
 ・
Arduino 1.6x以上で使う

 ・このライブラリーは、SD/SDHCフラッシュカード上のFAT16/FAT32ファイルシステムへの読み取り/書き込みアクセスを提供する。
 ・新規クラス「File」は SD.hライブラリーとの互換性を提供するために付け加えられた。
 ・SD.hで書かれたプログラムに対してSdFatを使えるようにするには、#include <SD.h>をその下の2行のように置き換えて記載すればよい。

  #include <SD.h> 
 

⇒ #include "SdFat.h"
  SdFat SD;

uint8_tのデータ・タイプ
 Byte、uint8_t、unsigned charは、Arduinoでは基本的に同じもの
。組み込みソフトウェアの作者は、システムが8ビット、16ビット、または32ビットの長さを定義することがあるため、これらのタイプを定義することがよくある。uint16_tやint32_tなどの他のtypedefも使用している場合は、uint8_tを使用する。型定義の数値には、変数が何ビットを占めるかが明示されています。
uint16_t 
 16ビットの非負整数を格納する。


Arduinoのマイクロコントローラ(ATmega168)のメモリ
・Flashメモリ(16kバイト):Arduinoのスケッチが格納される
・SRAM(static random access memory)(1024バイト):スケッチの実行中に変数の作成と操作がおこなれる領域
 スケッチの中の文字列はSRAMを使うので、できるだけコメントは記入しない方が良さそうだ。
・EEPROM(512バイト):長期的に情報を記録するためのスペース


W5100 Ethernet Shield & SD Card Slot
Ethernet ボードが適切に機能することができるように、SS用に Pin10 を使わず開放しておく必要がある。
 使わなくても 
  pinMode(10, OUTPUT);
 としてスケッチの中に記載しておかなければならない。

またSDカード用のSSはPin4 が使われる。
  const int chipSelect = 4;
 としておかなければならない。

また、Pin10,11,12,13は、Ethernetシールドで利用されるので、それ以外のPinを利用しなければならない。
 10:Ethernetコントローラー用のSS
 11:MOSI
 12:MISO
 13:SCK


MACアドレスの目的
  物理ネットワーク上のデバイスを区別するため
時々やってしまう失敗
・スペースを入れる時には必ず半角で入れる事。間違えて全角で入れるとエラーになり、なかなか原因が分からなかったりする。


Ethernet Shield のスケッチ新旧バージョンでの違い
  旧 current_line_is_blank
  新 currentLineIsBlank

 Ethernet library (Ethernet.h) manages the W5100 chip,
 while Ethernet2 library (Ethernet2.h) manages the W5500 chip;
 all the functions remain the same.

04/20/2017

Fritzing で使うBread board はインスペクターでサイズ変更できる

Breadboard_halfsize Fritzingで使うBread boardは自分にはサイズが大きいなぁと思って小さなサイズのものを探していたが、次の手順でサイズの違うものを選んで使う事ができると分かった。

①Fritzingを起動してブレッドボードのタグを選択する。

②ブレッドボードが表示されたら、そのブレッドボードをマウスでクリックして選択した状態にする。

③ツールバーにあるボタン「ウインドウ」をクリックして、「インスペクター」をチェックする。

④Fritzingの画面右側にインスペクターの設定画面が表示される。
 ・プロパティの中に「サイズ」という項目があるので、その枠の右側にある「▼」部分をクリックする。
 ・現設定は「full」になっていると思うが・・・、
 ・「half+」などを選べば、長さが半分のブレッドボードに変更できる。

04/09/2017

VC0706 で撮影し SDカード に記録する Arduino camera

VC0706シリアルカメラで撮影し、マイクロSDカードに記録するArduino Cameraが出来た。
Img_20170409_205846 Arduino_camera_with_vc0706_and_sdca
Arduinoのシールド基板に小さなブレッドボードを貼り付けて、その上に部品を配置してテストした(左の写真)が、Fritzingのブレッドボードで描いてみると右側の絵のようになる。
(注記:カメラの所にある2本の抵抗は、絵では220Ωになっているが、僕がFritzingを使いこなせないために、間違った表記になっている。この抵抗の値は2本とも10kΩである。)

これで撮影した写真は、上下逆転している!


Sketchは、Photo Spy Cam using Arduinoのものが大変参考になった。
各パーツとArduinoとの接続は下記のようになっている。
Arduino 
部品数が少ないので、Arduinoのシールドボードの上にミニブレッドボードを貼り付けて、部品を配置し左表のように結線した。

ここでVC0706は、秋月電子で購入した部品
micro-SDカードは、Amazonで購入


ここでは写真サイズを 640x480 としたが、このサイズにするとSDカードへの記録時間が極端に長くなるので注意を要する。テストの際は、320x240 ぐらいで始めるのが良いのではないだろうか。

.

/**
 * VC0706 Camera Module Arduino Compatible:
 *  + cvbs: N/A
 *  + 5V: connected to arduino => pin 5V0
 *  + TX (OUT): connected to the RX (IN) of arduino => pin 2
 *  + RX (IN): connected to the TX (OUT) of arduino => pin 3
 *  + GND: connected to the GND
 */

#include <SoftwareSerial.h>
#include <SPI.h>
#include <SD.h>
#include <JPEGCamera.h>

File testFile;
SoftwareSerial s(2, 3);
JPEGCamera cam(s);
char filename[15];
int num = 0;
int numOfBytes;

const int chipSelect = 9; // CS : connected to pin 9 of arduino
int photoSize = 2; // 0 -> 160x120 / 1 -> 320x240 / 2-> 640x480
unsigned long mainStartTime, mainEndTime, startTime, endTime;

void setup()
{
//activate 5V for the SD Card shield
  pinMode(8, OUTPUT);    // VCC : connected to pin 8 of arduino
  digitalWrite(8, HIGH); // SD Card power ON

  Serial.begin(38400);

// Wait for the serial port to be opened
   while (!Serial) delay(25);
 
//check SD card
  while (!SD.begin(chipSelect))
    {
      Serial.println("Error: SD initialization failed. Is SD card in the card folder?");
    }
    Serial.println("Info: SD Initialization complete,");

// Serial port connected to the cam
    s.begin(115200); //for VC0706 cam
    delay(50);

    Serial.println("Info: Reseting cam...");
// reset cam and wait.
    cam.reset();
    delay(3000);

    Serial.println("Info: Changing baud rate...");
// change baud rate to work at 3.3v
    cam.chBaudRate(2);// 0 -> 9600 / 1 -> 19200 / 2 ->  38400 / 3 -> 57600 / 4 -> 115200
    delay(50);
  
//change serial to match new camera baud rate
    s.end();
    s.begin(38400);
    delay(50);

  Serial.println("Info: Changing picture size...");
//change picture size
  cam.chPictureSize(photoSize);
  delay(2500);

  Serial.println("Info: getting last pic num for the created files...");
  num = getNewSDFileNum();

  Serial.println("Info: Setup is DONE!");
}

void loop()
{
  mainStartTime = millis();
  takePic();
  mainEndTime = millis();
  Serial.print("Info: Main elapsed time (in secs): ");
  Serial.println((mainEndTime - mainStartTime) / 1000);
}

void takePic()
{
  Serial.println("Info: Preparing to take new photo.");

// must call stopPictures before a new photo is taken.
  cam.stopPictures();
  delay(50);

// take photo
  cam.takePicture();
  delay(50);

  num++;
  sprintf(filename, "PIC_%i.JPG", num);

  if (SD.exists(filename)) {
    SD.remove(filename);
  }

// Create file
  testFile = SD.open(filename, FILE_WRITE);
//if it opens ok
  if (testFile)
  {
//save to file
    Serial.print("Info: Saving photo to SD: ");
    Serial.println(filename);
    
    startTime = millis();
    numOfBytes = cam.readData(testFile);
    endTime = millis();

    Serial.print("Info: Elapsed time (in secs): ");
    Serial.println((endTime - startTime) / 1000);

    Serial.print("Info: Bytes for photo: ");
    Serial.println(numOfBytes);
  }
  else  //else it didn't open ok
    Serial.println("Error: Error opening file on SD,");

//must close file to finish writing.
  testFile.close();
}

int getNewSDFileNum() {
  File root = SD.open("/");

  int n = getFileLastNumForDirectory(root);

  root.close();

  return n > 0 ? n : 0;
}

int getFileLastNumForDirectory(File dir) {
  int n = 0;
  int fn = 0;

  while (true) {
    File entry =  dir.openNextFile();

    if (!entry) {
// no more files
      break;
    }

    fn = 0;

    if (entry.isDirectory()) {
      //fn = prepareFileLastNumForDirectory(entry); //no need to be recursively
    }
    else {
      String name = String(entry.name());

      if (name.startsWith("PIC_") && name.endsWith(".JPG")) {
        int pos = name.indexOf(".JPG");
        name = name.substring(4, pos);

        if (isValidNumber(name))
          fn = name.toInt();
      }
    }

    if (fn > n) {
      n = fn;
    }

    entry.close();
  }

  return n;
}

boolean isValidNumber(String str) {
  if (str && str.length() > 0) {
    for (byte i = 0; i < str.length(); i++)
    {
      if (!isDigit(str.charAt(i))) return false;
    }
    return true;
  }
  return false;
}


《撮影した写真》
Pic_392逆さまに撮影されていた・・・








《参考にしたブログ》

1)Photo Spy Cam using Arduino
  このブログは同じVC0706カメラと、同じmicro-SDカードを使った事例だったので、大変勉強になった。
 この事例と私の場合のPin接続は違っているのでもし参考にされる場合には、その点を注意してください。

2)オッサンとバイエル、ピアノ等 「カメラで遊んでみる

 このブログも大変参考にさせて戴いた。



《使用部品》

1)小型TTLシリアルJPEGカメラ VC0706 
  [adafruit PRODUCT ID: 1386] 秋月電子で購入
2)

ココログで arduino sketchソースコード を少し見やすくするには・・・

ブログのソースコードに行番号を付けた見やすい表示にするには、google-code-prettify の公式サイトから一番新しいzipファイル (今はこれかな:prettify-21-Jul-2010.zip)をdownloadして、適当な場所に解凍する。

解凍すると google-code-prettify フォルダが作られ、その中に srcフォルダ がある。

その srcフォルダの中から、 prettify.css, prettify.js, lang-css.js をココログのフォルダに格納する。

フォルダの格納先は、 ココログを開いて⇒コントロールパネル⇒「ファイルのタグ」をクリック
僕は、jsファイルを scriptsフォルダに、cssファイルを stylesフォルダにアップロードしたが、これらのフォルダが有れば、その場所を先ほどdownloadした内の3つのファイルのアップロード先とする。
フォルダが無ければ、先ず「新しいフォルダの作成」に scripts と記載し、「フォルダを作成」のボタンをクリックする。
stylesフォルダも同様に作成する。

次に、download し解凍した3つのファイルを其々 scripts,styles のフォルダにアップロードする。
 ・現在のフォルダで srcを選択し、
 ・新規ファイルのアップロードの「ファイルを選択」ボタンをクリックして、
 開いたエクスプローラーからファイルを選択した後、「アップロード」ボタンをクリックする。
  アップロードが完了したら、「ブログ」のタブをクリックして、左下画面の下方にある「設定」をクリックする。
 ブログの基本情報画面になる。

ブログのサブタイトルの中に、下記のように script の記載をする。
この窓画面は小さくて編集しにくいので、Windowsのテキストを開いておいて、そこで作業する事をお勧めする。
僕は、Windowsのテキストを開いてから下記を打ち込み、

<script src="../scripts/lang-css.js" type="text/javascript"></script>
<script src="../scripts/prettify.js" type="text/javascript"></script>
<link href="../styles/prettify.css" rel="stylesheet" type="text/css" />
<script type="text/javascript"> SyntaxHighlighter.all(); </script>

上記のテキストを書いた後、これらをコピーして、サブタイトルの中に貼り付けた。

「変更を保存」ボタンをクリックして、設定変更の内容をサイトに反映させるために「サイトに反映」ボタンをクリックした。

次の画面で、「すべてのファイル」そのまま・・・「反映」ボタンをクリックで全てのブログ記事に反映された。

ここまでの作業は、準備段階である。

各ブログページで行う作業は、

ブログの本文を記載する場所で、HTMLの編集タブをクリックして、
ソースリスト記載部の直前に、
 <pre class="prettyprint linenums"> 

と記載し ソースリスト終了部分に </pre> と書いて締めくくる。
この通り行ったが、デフォルトでは 5行単位での行番号表示となってしまう。

一行ごとに行番号を付けるには、prettify.cssの内の記述を変更する必要があるようだ・・・

下記のようにやってみたが、棒のブログでは上手く行かなかった。


《prettify.cssの編集作業》
 prettify.cssの後半部分に記載されている  
   li.L0, li.L1, … li.L8 { list-style-type: none } 

 を全てコメント行にしてしまうか、{}内を消去する。

 すなわち、下記のように書き換えて保存。

li.L0, li.L1, … li.L8 {  }

そこで、 ブログ本文の<pre ・・・ >の記述の直前に下記を追記した。

<style>
 li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:decimal}
 </style> 

 これで、Sketchソースコード部分の表示はこのようになった。
しかし、「<」「>」「"」「'」「&」は、HTML編集作業の中で下記のように文字を置き直して記載する必要がある。
 「<」 ⇒ 「&lt;」
 「>」 ⇒ 「&gt;」
 「"」 ⇒ 「&quot;」
 「'」 ⇒ 「&apos;」
 「&」 ⇒ 「&amp;

// Sketch : It detects a human and an animal by the PIR sensor.
//          Then, it makes warning by voice using WTV020-SD.
 
#include <Wtv020sd16p.h>

int resetPin   =  2;  // Reset
int clockPin   =  3;  // Clock
int dataPin    =  4;  // Data
int busyPin    =  5;  // Busy
int pirPin     =  6;  // PIR sensor
int p07Pin     =  7;  // P07
int ledPin     = 13;  // LED
int pirState =  LOW;   // states of PIR at the initial

  Wtv020sd16p wtv020sd16p(resetPin,clockPin,dataPin,busyPin);
 
void setup()
{
  Serial.begin(115200);
  pinMode(   pirPin,  INPUT); 
  pinMode(   p07Pin, OUTPUT); 
  pinMode(   ledPin, OUTPUT);    
  wtv020sd16p.reset();

  digitalWrite( p07Pin,HIGH);       // Button(P07) is open(=Off)
  digitalWrite( ledPin, LOW);       // LED:OFF
}
 
void loop()
{
  pirState = digitalRead(pirPin);   // read the state of PIR sensor
  if (pirState == HIGH) {           // detected =>"HIGH", if not-detected =>"LOW"
                                    // Detected!

   digitalWrite( p07Pin,  LOW);     // Button(P07) is close(=On) :PREV  
   digitalWrite( ledPin, HIGH);     // LED :ON  
   
//Plays asynchronously an audio file.
   wtv020sd16p.asyncPlayVoice(1);   // Play audio file number 1
   delay(20000);                    // it sounds for 20 seconds

   digitalWrite( p07Pin, HIGH);     // Button(P07) is close(=On) :PREV 
   digitalWrite( ledPin,  LOW);     // LED:OFF
   delay(3000);  
  }
   wtv020sd16p.reset();
}

より以前の記事一覧

May 2017
Sun Mon Tue Wed Thu Fri Sat
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      

Recent Trackbacks

無料ブログはココログ