2016年4月7日木曜日

ラッチ型スイッチでLEDをオン・オフ

Multi-function ShieldのLED1とプッシュスイッチSW1を使って簡単なプログラムを作ってみましょう。

1.スイッチSW1とLED1の接続関係
LED D1~D4は、Arduinoボードの13ピンから10ピンに接続されています。ピン10~13にLOWが出力されるとLED D4~D1がオンする接続になっています。
またスイッチS1~S3はArduinoボードのA1ピンからA3ピンに接続されています。スイッチをオンするとLOW(アナログ値:0)を読み、オフのするとHIGH(アナログ値:1023)を読みます。デジタルまたはアナログのどちらでも読み取ることができますが、今回はデジタルで読むことにします。



2.スイッチを押すとLEDがオンし離すとオフするプログラム
スイッチS1を押している時だけLED D1がオンし、スイッチを離すとLEDはオフします。その様子が下記のビデオです。

下記がその制御プログラムです。

#define S1 A1   // スイッチS1 A1ピン     :モード切替SW
#define S2 A2   // スイッチS2 A2ピン     :ラップタイマーリセット
#define S3 A3   // スイッチS3 A3ピン
#define D1 13   // LED D1 1: off, 0: On
#define D2 12   // LED D2
#define D3 11   // LED D3
#define D4 10   // LED D4
#define ON 0    // LED is on
#define OFF 1   // LED is off

void setup ()
{
  pinMode(D1, OUTPUT);          //LED  D1の初期化
  digitalWrite(D1, OFF);
  pinMode(S1, INPUT);          
}

/* Main program */
void loop()
{
  if (digitalRead(S1) == 0)
    digitalWrite(D1, ON);
  else
    digitalWrite(D1, OFF);
}

3. 一度スイッチを押すとLEDがオンし、もう一度押すとオフするプログラム
スイッチS2を押すとLED D2がオンします。スイッチを離してもLEDはオフしません。もう一度スイッチを押すとLEDはオフします。その様子が下記のビデオです。


下記がその制御プログラムです。
#define S1 A1   // スイッチS1 A1ピン
#define S2 A2   // スイッチS2 A2ピン
#define S3 A3   // スイッチS3 A3ピン
#define D1 13   // LED D1 1: off, 0: On
#define D2 12   // LED D2
#define D3 11   // LED D3
#define D4 10   // LED D4
#define ON 0    // LED is on
#define OFF 1   // LED is off

byte S2Latch = 0;   //
boolean D2On = false;
void setup ()
{
  pinMode(D2, OUTPUT);          //LED  D2の初期化
  digitalWrite(D2, OFF);
  pinMode(S2, INPUT);
}

void loop()
{
  if ( digitalRead(S2) == 0) {
    if (S2Latch == 0) {
      S2Latch = 1;
      digitalWrite(D2, D2On);
      D2On = !D2On;
    }
  } else S2Latch = 0;
}




2016年3月30日水曜日

Multi-function Shield と超音波距離センサーを使ったラップタイマー(制作編)

1.Multi-function Shieldの取付け注意事項

Multi-function Shield をArduino UNOに装着する場合、4桁セグメントLEDの裏面ピンがArduino UNOのUSBコネクタに接触します。この表示動作時に誤動作を起こしたり、ボード故障の原因になりますので、セグメントLEDのピンは短くカットして、USBコネクタの上面には絶縁テープを貼ってください。


2.超音波距離センサーの取り付け

超音波距離センサー(HCSR04)をMulti function Shieldにスマートに固定するためにシールド左上の7ピンコネクタ(APC220 Bluetooth)を使用します。簡単なソケットボードを制作してシールドに固定してください。

コネクタのピン3-4は、Arduino UNOのシリアルピン0-1に使用されていますので使えません。なので、コネクタピン6-7を使用します。Arduno UNOのピン5-6がシールド右下のコネクタに引き出されていますので、これを使用します。下記のようにArduno UNOのピン5-6が、HC-SR04のEcho, Trigピンつながるように配線してください。



3.ラップライマーのプログラム

ラップライマーとして動作するプログラムソースを下記に添付します。
/*
 * 第一工業大学東京上野キャンパス
 * 木下研究室 3年生プレゼミ教材
 * 2016年4月㏠
 */

#define EchoPin 5   // 超音波距離センサ HC-SR0 ピン 入力
#define TrigPin 6   // 超音波距離センサ HC-SR0 ピン 出力
#define LATCH_DIO 4 // シフトレジスタ 74HC595 ピン OUTPUT
#define CLK_DIO 7   // シフトレジスタ 74HC595 ピン OUTPUT
#define DATA_DIO 8  // シフトレジスタ 74HC595 ピン OUTPUT
#define SW1 A1      // スイッチSW1 A1ピン     :モード切替SW
#define SW2 A2      // スイッチSW1 A1ピン     :ラップタイマーリセット
#define SW3 A3      // スイッチSW1 A1ピン
#define SW3 A3      // スイッチSW1 A1ピン
#define Mode_0 0    // モード0: トラック位置設定
#define Mode_1 1    // モード1: ラップタイマーモード
#define LED1 13     // LED1 ON:トラック位置設定、
#define LED2 12     // LED2 ON: ラップタイマーモード
#define LED3 11     // LED3
#define LED4 10     // LED4
#define ON 0         // LED is on
#define OFF 1       // LED is off
#define SPEAKER 3        // 
int cm;                 // 超音波距離センサー計測値(センチメートル)
int TrackCenter = 15;   // トラック中央値 (デフォルト)
bool DP_on = false;     //2桁目LEDのDPのOn/Off
byte OperationMode = Mode_0;    // 動作モード
bool Sw2IsOn = false;           // スイッチ2が押された
bool LapTimerStart = false;     // ラップライマー制御
bool LapTimerRunning = false;
unsigned long Last_100ms_Count = 0; //100ms カウント最終値
int Count_100ms = 0; // 100ms カウンタ
bool SpeakerOn = false;     //スピーカーをオン用フラグ(オンは0.1秒に固定
unsigned long SpeakerDuration = 0;
void setup ()
{
  Serial.begin(9600);   //シリアルを使用する

  // シフトレジスタ 74HC595初期化
  pinMode(LATCH_DIO, OUTPUT);
  pinMode(CLK_DIO, OUTPUT);
  pinMode(DATA_DIO, OUTPUT);

  // 超音波距離センサピン初期化
  pinMode(TrigPin, OUTPUT);
  pinMode(EchoPin, INPUT);
  digitalWrite(TrigPin, LOW);

  // Speaker 設定(オンオフは方向レジスタで制御)
  pinMode(SPEAKER, INPUT);

  // LED1-4の初期化
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(LED4, OUTPUT);

  digitalWrite(LED1, ON);  //ON
  digitalWrite(LED2, ON);
  digitalWrite(LED3, ON);
  digitalWrite(LED4, ON);
  delay(1000);
  digitalWrite(LED1, OFF);  //OFF
  delay(100);
  digitalWrite(LED2, OFF);
  delay(100);
  digitalWrite(LED3, OFF);
  pinMode(SPEAKER, OUTPUT);
  delay(100);
  digitalWrite(LED4, OFF);
  pinMode(SPEAKER, INPUT);
}

/* Main program */
void loop()
{
  ReadSwitch();     //SW1, SW2 の読み取り

  // キャリブレーションモード
  if (OperationMode == Mode_0) {
    digitalWrite(LED1, ON);
    digitalWrite(LED2, OFF);
    Display(cm);
    DP_on = false;
    Count_100ms = 0;
    TrackCenter = 2 * cm / 3;
    LapTimerStart = false;
    LapTimerRunning = false;
  }

  // ラップタイマーモード
  if (OperationMode == Mode_1) {
    digitalWrite(LED1, OFF);
    digitalWrite(LED2, ON);
    DP_on = true;
    Display(Count_100ms);

    // ラップタイマーストップ状態でマイコンカーが横切ったらカウントスタート
    if (LapTimerStart == false && cm  < TrackCenter ) {
      LapTimerStart = true;
      TurnSpeakerOn();
    }

    // ラップタイマーラン状態でマイコンカーが横切ったらカウントストップ
    if (LapTimerRunning == true && cm  < TrackCenter ) {
      LapTimerStart = false;
      TurnSpeakerOn();
    }

    // ラップタイマーストップ状態で、SW2を押した場合
    if (Sw2IsOn == true &&  LapTimerStart == false) {
      Count_100ms = 0;              // カウントを0.0秒にリセット
      LapTimerRunning = false;      // ラップタイマー停止
      Sw2IsOn = false;              // SW2 ONクリア
    }
  }
  // 100ms インターバル処理
  if (millis() - Last_100ms_Count > 100) {
    Last_100ms_Count = millis();
    cm = readDistance();        // 距離計測は100msごと

    if (LapTimerStart == true) {
      if (Count_100ms < 9999) {
        Count_100ms++;
        if (Count_100ms > 10 ) LapTimerRunning = true;  // ラップライマーがスタートして1秒間はラン状態にしない。
        else LapTimerRunning = false;
      } else  Count_100ms = 0;
    }
  }

  if (SpeakerOn == true) {     // スピーカーを0.5秒オンする
    if (millis() - SpeakerDuration > 50) {
    SpeakerOn = false;
    pinMode(SPEAKER, INPUT);
    }
  }

}
// SW1, SW2の読み取り, スイッチはアナログ読み
void ReadSwitch(void) {
  static byte Sw1Latch;
  static byte Sw2Latch;
  if ( analogRead(SW1) < 100) {
    if (Sw1Latch == 0) {
      Sw1Latch = 1;
      TurnSpeakerOn();
      if (OperationMode == Mode_0) {
        OperationMode = Mode_1;

      } else {
        OperationMode = Mode_0;
        Sw2IsOn = false;
        LapTimerStart = false;
      }
    }
  } else Sw1Latch = 0;

  if ( analogRead(SW2) < 100) {
    if (Sw2Latch == 0) {
      Sw2Latch = 1;
      Sw2IsOn = true;
      TurnSpeakerOn();
    }
  } else Sw2Latch = 0;

}

void TurnSpeakerOn(void) {
  SpeakerOn = true;
  pinMode(SPEAKER, OUTPUT);
  SpeakerDuration = millis();
}


/*4SEG LEDにNumberを表示する
  loop()関数内に配置すれば、3ms毎にスキャン表示を行いう
  Number: 0-9999 の4桁の整数
  表示間隔: 5ms
*/
void Display(int Number)
{
  static unsigned long Last_ms_Count;
  static byte ScanSeg = 0;
  if (millis() - Last_ms_Count > 3) {
    Last_ms_Count = millis();
    switch (ScanSeg++) {
      case 0:
        WriteNumberToSegment(0 , Number / 1000);
        break;
      case 1:
        WriteNumberToSegment(1 , (Number / 100) % 10);
        break;
      case 2:
        WriteNumberToSegment(2 , (Number / 10) % 10);
        break;
      case 3:
        WriteNumberToSegment(3 , Number % 10);
        break;
      default:
        ScanSeg = 0;
    }
  }
}
/* セグメント表示
    Segment: セグメント位置:0 - 3
     Value:表示する値 : 0 - 9
*/
void WriteNumberToSegment(byte Segment, byte Value)
{
  // セグメント表示パターン:  0 - 9
  const byte SEGMENT_MAP[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0X80, 0X90};  
  const byte SEGMENT_SELECT[] = {0xF1, 0xF2, 0xF4, 0xF8}; // 4-seg LED 選択パターン: 1 to 4
  byte SegPattern;

  if (DP_on == 1 && Segment == 2)           // LED2のDP On/Off判定
    SegPattern = SEGMENT_MAP[Value] & 0x7F;     // DPパターンのマスク
  else
    SegPattern = SEGMENT_MAP[Value];
  digitalWrite(LATCH_DIO, LOW);
  shiftOut(DATA_DIO, CLK_DIO, MSBFIRST, SegPattern);
  shiftOut(DATA_DIO, CLK_DIO, MSBFIRST, SEGMENT_SELECT[Segment] );
  digitalWrite(LATCH_DIO, HIGH);
}

// 距離測定:センチメートル
int readDistance(void) {
  long t ;
  int ans ;
  digitalWrite(TrigPin, HIGH) ;         // 超音波センサーに5usのパルスを出力する
  delayMicroseconds(5) ;
  digitalWrite(TrigPin, LOW) ;
  t = pulseIn(EchoPin, HIGH, 5000) ;    // パルス幅の時間を測る
  ans = (t / 29) / 2 ;                  // 往復なので2で割る
  return ans ;                          //cm単位戻す
}

Multi-function Shield と超音波距離センサーを使ったラップタイマー(操作編)

Multi-function Shieldは、Amazon.com などで1000円程度で購入できる Arduino UNO用のプログラミング学習用シールドです。Arduino UNOに、このボートと超音波距離センサー(HC-SR04)を取り付けて、マイコンカー用のラップライマーを制作したので紹介します。

1. 動作
  • ラップタイマーと反射ブロックの間をマイコンカーが走り抜けると、ラップタイマーがスタートします。そして再度、マイコンカーがラップタイマーの前を通過したときにタイマーがストップします。
  • Arduino Unoは超音波距離センサーと反射ブロックまでの距離を計測していますが、マイコンカーが超音波を遮ると計測距離が短くなります。この原理を利用してラップライマーを起動・停止させます。

2. 設置方法
  • ラップタイマー(このボード)を、マイコンカーのコーストラックの右サイドにを設置してください。
  • 反射ブロックをコーストラックの左サイドに配置してください。このとき、反射ブロックと超音波距離センサーの距離は30cm以下にしてください。
  • そして、ラップタイマーに電源を投入してください。
3. 操作方法
  • キャリブレーションモード: 電源がオンすると、LED1から4がオンしブザー音がして、このモードになります。このときLED1(D1)がオンします。 そして、4桁セグメントLEDには反射ブロックまでの距離が表示(単位:センチメートル)されます。反射ブロックを動かすと表示距離が変化します。マイコンカーのガイド用センターラインが反射ブロックと超音波距離センサーのちょうど中間に来るように反射ブロックを配置してください。このモードでSW1を押すと計測モードに移行します。
  • 計測モード: このモードでは、LED2(D2)がオンします。 4桁セグメントLEDにはラップタイマーのカウント値が秒で表示(0.1秒まで)されます。表示は"000.0"でストップしています。この状態で、マイコンカーがセンサーの前を横切るとカウントがスタートします。そして再度マイコンカーがセンサーの前に来たときカウントがストップします。この表示値がラップタイム(秒)です。SW2スイッチを押すと、ラップタイムが"000.0"にリセットされカウントスタート状態になります。 "000.0" 以外のカウント停止状態では、マイコンカーがセンサーを通過してもカウントはスタートしませんので注意してください。このモードでSW1を押すとキャリブレーションモードに移行します。


2016年2月3日水曜日

JavaScriptによるハノイの塔



ハノイの塔の実行は赤い部分だけで済んでしまうのには驚きます。
(参照: ゼロからわかるJavaScript超入門 河西朝雄 著(技術評論社)

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8" />
    <title>ハノイの塔(テキスト版)</title>
    <script type="text/javascript">
        var result;
        function hanoi(n, a, b, c) {
            if (n > 0) {
                hanoi(n - 1, a, c, b);
                result.value += "板" + n + ": " + a + " --> " + b + "\n";
                hanoi(n - 1, c, b, a);
            }
        }
        function start() {
            var N = document.getElementById("level").value;
            result = document.getElementById("result");
            result.value = "";
            hanoi(N, "a", "b", "c");          
        }
    </script>
</head>
<body>
    <div>ハノイの塔</div>
    <input id="level" type="text" size="2" value="4"/>
    <input type="button" value="START" onclick="start()" />
    <br />
    <textarea id="result" rows="20" cols="20"></textarea>
</body>
</html>

2015年9月10日木曜日

GR-SAKURA HTTPサーバー GETメソッドでLED制御 (ハードウェア)

1.概要
HTTPサーバーとして動作しているGR-SAKURAボードに各種センサーやLEDを接続し、Webブラウザー経由でGR-SAKURAのセンサー情報を表示したりLEDのON/OFF制御を行う方法を紹介します。

2.GR-SAKURAとPC/LANの接続関係


3.GR-SAKURAと周辺部品との接続関係

4.ブラウザー表示とGR-SAKURA周辺部品の関係

2015年9月2日水曜日

GR-SAKURAのRTCを使う

GR-SAKURAボード上のRX63Nマイコンには、RTC(リアル・タイム・クロック)が搭載されています。
RX63Nには、腕時計にも使われている水晶発信子(32.768KHz)が接続されており、この発振パスルをカウントして正確な時刻を作ります。年・月・曜日とかの計算もハードウェアで行いますので、初期値をセットすれば、日付・時間を簡単に読み出すことができます。

下記に、GR-SAKURAボードとWebコンパイラ用のサンプルプログラムを添付します。

//GR-SAKURA用 プロジェクトテンプレート(Ver V2.02)
/* GR-SAKURA Sketch Template V2.02 */
/* RX63N RTC Test Program */
#include <Arduino.h>
#include <RTC.h>   //GR-SAKURAボードのRTCを使用する
#define INTERVAL 100

// myRTCに日付・時刻の初期値をセットする。詳細は gr_common\core\RTC.h

RTC_TIMETYPE myRTC = {15, 12, 31, 2, 23, 59, 30};
const char *WeekDay[7] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};

void setup()
{ 
    Serial.begin( 115200 ); // シリアルモニタの通信速度
    pinMode(PIN_LED0,OUTPUT);
    pinMode(PIN_LED1,OUTPUT);
    pinMode(PIN_LED2,OUTPUT);
    pinMode(PIN_LED3,OUTPUT);
    rtc_set_time(&myRTC);  // RTCに初期値をセットしてRTCをスタート
}

void loop()
{
    digitalWrite(PIN_LED0, 1);
    delay(INTERVAL);
    digitalWrite(PIN_LED1, 1);
    delay(INTERVAL);
    digitalWrite(PIN_LED2, 1);
    delay(INTERVAL);
    digitalWrite(PIN_LED3, 1);
    delay(INTERVAL);
    digitalWrite(PIN_LED0, 0);
    delay(INTERVAL);
    digitalWrite(PIN_LED1, 0);
    delay(INTERVAL);
    digitalWrite(PIN_LED2, 0);
    delay(INTERVAL);
    digitalWrite(PIN_LED3, 0);
    delay(INTERVAL);

    rtc_get_time(&myRTC); // RTCレジスタ内容をmyRTCに読み出す

    Serial.print(myRTC.year);
    Serial.print("/"); 
    Serial.print(myRTC.mon);
    Serial.print("/"); 
    Serial.print(myRTC.day);
    Serial.print(" ("); 
    Serial.print(WeekDay[myRTC.weekday]); 
    Serial.print(")  "); 
    Serial.print(myRTC.hour);
    Serial.print(":"); 
    Serial.print(myRTC.min);
    Serial.print(":"); 
    Serial.println(myRTC.second);
}

2015年8月29日土曜日

S4AをGR-SAKURA HTTPサーバーにつなげる

1. S4A とは
S4Aは、「Scratch for Arduino」の略称で、MITがリリースしている Scratch Ver 1.4 を、Arduino ボードに接続しScrtachからArduinoボードに接続されているセンサーを読み取ったりモーターを駆動できるよに拡張されたアプリケーションソフトです。

Arduinoボードを使った組込みシステムの開発は、ボードや搭載されているワンチップマイクロコントローラーの細かい技術的知識がなくてもセンサーを読んだりモータを駆動したりと簡単にソフトウエア開発が可能です。しかしそのソフト開発にはC++言語を使うので、ある程度のC/C++言語の知識がないと開発ができない。

その点、Scratchは命令ブロックを積木のように組み合わせて制御プログラムの開発ができるので、小中学生のようなプログラミングに何の知識がない方々でも簡単なプログラム開発できます。

S4AはScratch機能をすべて継承し、Arduinoボードの制御機能を拡張し多くのセンサーを読んだりやモータを駆動できるように拡張されています。

2. GR-SAKURAボード
メード・イン・ジャパンの高機能版Arduinoボードです。Arduinoの基本機能をすべて継承し、Web上でソフト開発ができる開発環境を備えています。

GR-SAKURAのWeb開発環境は、開発テンプレートが「GR-SAKURA_Stetch_V2.02.zip]にアップデートされました。スケッチリファレンスもアップデートされ、「Ethernet サーバー」にはHTTPサーバーとして動作するサンプルプログラムが添付されています。

3.GR-SAKURA IoTセンサーサーバー
S4A 1.6 の【調べる】 (http://) 機能(下記の赤点線)は、おもしろい命令だ。インターネット上にあるIoTサーバーの情報を取り込む命令が備わっています。

GR-SAKURAの「Ethernet サーバー」サンプルコードを修正して、S4AからGR-SAKURAにつながったセンサー情報をS4Aで使用できるようなデモを紹介します。

3.GR-SAKURA センサー端子(A0 - A6)をS4Aで読む
GR-SAKURAボードをサンプルコード ”Ethernet サーバー” を使ってHTTPサーバーとして動作させる。この時、S4Aでデータを取得しやすくするために下記の用に変更する。

サンプルコードの43~59行目の変更:
client.print(":"); // this is for S4A client.print(analogRead(0)); // this is for S4A client.print(":"); // this is for S4A client.print(analogRead(1)); // this is for S4A client.print(":"); // this is for S4A client.print(analogRead(2)); // this is for S4A client.print(":"); // this is for S4A client.print(analogRead(3)); // this is for S4A client.print(":"); // this is for S4A client.print(analogRead(4)); // this is for S4A client.print(":"); // this is for S4A client.print(analogRead(5)); // this is for S4A client.print(":"); // this is for S4A 
/*
client.println("<!DOCTYPE HTML>"); client.println("<html>"); // output the value of each analog input pin for (int analogChannel = 0; analogChannel < 6; analogChannel++) { int sensorReading = analogRead(analogChannel); client.print("analog input "); client.print(analogChannel); client.print(" is ");
client.print(sensorReading); client.println("<br/ >"); } client.println("</html>"); */

4. GR-SAKURA HTTPサーバーの起動
修正したサンプルコードをビルドし、GR-SAKURAに書き込みます。そしてUSBシリアルポートを立ち上げます。
そして任意のキーボーをたたくと、GR-SAKURAのIPアドレスが表示されます。このときLANケーブルを接続する場合は、DHCP環境でないとうまくIPアドレスが取得することができません。


今使ってるLAN環境ではルーターはGR-SAKURAに上記のようなIPアドレスを付与しました。

5.S4Aサンプルプログラム
GR-SAKURAのIPアドレスが分かったので、これを使って下記のようなS4Aのスクリプトを作成します。

このとき、Arduino1は、下記のようなスクリプトを準備ください。もし、GR-SAKURAとS4Aを同一PCで実行している場合、USB COMポートが衝突する場合があります。


S4Aのスクリプトブロック が取得するデータは、

 のような形式で受信します。 : によってデータ区切られており、先頭データがA0ピンのアナログ入力値になります。

 http_data[1] = A0ピンのアナログ値
 http_data[2] = A1ピンのアナログ値
 http_data[3] = A2ピンのアナログ値
 http_data[4] = A3ピンのアナログ値
 http_data[5] = A4ピンのアナログ値
 http_data[6] = A5ピンのアナログ値


6.GR-SAKURAのUSBシリアルポート(HTTPモニタ)
このとき、GR-SAKURAボードが接続されたUSBシリアルポートからは、S4AがGR-SAKURA を読むたびに下記のような情報が出力されます。



7. センサーを接続
GR-SAKURAボードのA0~A5ピンにセンサーを接続すれば、S4Aのサンプルスクリプトが4秒おきにGR-SAKURAを読みに行きます。 センサーは、0V~3,3Vの電圧を出力するタイプにしてください。サンプルスクリプトを応用すれば楽しいIoTセンサーネットワークを制作することができます。