Adafruit Trinketで距離センサを利用

WS2822Sのアニメーションについては下記記事を参照下さい
Adafruit TrinketでWS2822Sをアニメーション点灯

目的

  1. Adafruit Trinketで対象物との距離を測定する
  2. 距離センサはSHARP GP2Y0E03赤外線距離センサを利用する
    秋月電子で800円弱で購入、参考にしたデータシートは下記
    http://sharp-world.com/products/device/lineup/data/pdf/datasheet/gp2y0e03_e.pdf

出来上がった物

回路図

  • Trinket 0Pin
    WS2822SのADDRI (Address Input) に接続 → 他のWS2822Sへチェーン接続
  • Trinket 1Pin
    各WS2822SのDAI (Data Input)に接続
  • Trinket 2Pin
    SHARP GP2Y0E03のアナログ出力 Vout(A)を接続
    GP2Y0E03のピンアサイン/出力電圧詳細は上記データシートを参照
  • SHARP GP2Y0E03
    上記のブレッドボード図の左から下記となります
    1 | VDD → 3.3V
    2 | Vout(A) → Trinketのアナログ入力へ
    3 | GND → GNDへ
    4 | VIN(IO) → 3.3V
    5 | GPIO1 → 3.3V
    6 | SCL → I2C用のため利用しない
    7 | SDA → I2C用のため利用しない

  • 3.3V生成
    手持ちのLM317を利用3.3VをSHARP GP2Y0E03の
    VDD/VIN(IO)/GPIO1 に入力

  • その他
    TrinketのGNDはGP2Y0E03と共有

注意点 前回記事に色々記載をしておりますので参考にして下さい

ソースコード

#include <Ws2822s.h>
#include <avr/interrupt.h>

// WS2822Sセットアップ
#define NUM_PIXELS 3   // 使用するWS2822Sの数
#define LED_PIN 1      // WS2822SのDAIピンにつなげるTrinketのピン番号 #1
#define ADR_PIN 0      // WS2822SのADRIピンにつなげるTrinketのピン番号 #0

// センサーセットアップ
#define DISTANCE_SENSOR 1 // 距離センサーのアナログ出力値を取得 Trinketのピン番号#2
                           // TrinketでanalogRead利用時は AnalogPinNumberで記載する 1 = #2 となる
#define MAX_VOLTAGE 3.0

Ws2822s LED(LED_PIN , NUM_PIXELS);

// アニメーションパターンの定義
#define RGB 3
#define FRAME_MAX 2
PROGMEM const uint8_t displayAnim[][RGB*NUM_PIXELS*FRAME_MAX] = {  
  // R    G    B
  // LED1
  // LED2

  // 近い
  {
    0x0F,0x00,0x00,
    0x0F,0x00,0x00,
    0x0F,0x00,0x00,

    0x00,0x00,0x00,
    0x00,0x00,0x00,
    0x00,0x00,0x00,
  },

  // 中位
  {
    0x00,0x0F,0x00,
    0x00,0x0F,0x00,
    0x00,0x0F,0x00,

    0x00,0x00,0x00,
    0x00,0x00,0x00,
    0x00,0x00,0x00,
  },

  // 遠い
  {
    0x00,0x00,0x0F,
    0x00,0x00,0x0F,
    0x00,0x00,0x0F,

    0x00,0x00,0x00,
    0x00,0x00,0x00,
    0x00,0x00,0x00,
  },
};

// interrupt関数で使いまわす変数
volatile uint8_t  animPattern;  // 実行するアニメーションのパターン  
volatile uint8_t  animFrameNum; // タイマー割り込みが toggleCount 回実行されたらアニメーションフレームが1進む  
volatile uint16_t animWaitTime; // タイマー割り込みが toggleCount 回実行されたらアニメーションフレームが1進む  
volatile uint16_t toggleCount;  // タイマー割り込み時にカウントアップされるカウンタ

void setup()  
{
  // put your setup code here, to run once:

  // tnx for information
  // http://w8bh.net/avr/TrinketTimers.pdf
  // http://tetunori.hatenablog.com
  // http://www.geocities.jp/zattouka/GarageHouse/micon/Arduino/DMSU/DMSU2.htm

  // Disable interrupts
  cli();

  // Clear Timer on Compare
  TCCR1 = (1<<CTC1);
  // all of the prescaler bits are set to 1. The prescaler divides the 8 MHz clock by 16384
  // resulting in a counter frequency of 488 Hz
  TCCR1 |= (1<<CS13) | (1<<CS12) | (1<<CS11) | (1<<CS10);
  // The output frequency for CTC mode is: freq(Hz) = 8 MHz/2/prescaler/(OCR1C+1)
  // resulting a calling TIM1_COMPA_vect frequency is 4.8 Hz
  OCR1C = 50;
  // Enable Timer1 interrupt (compare mode)
  TIMSK = (1 << OCIE1A);

  // init WS2822S Address (EEPROMの寿命を考えていません)
  LED.setAddress(0, NUM_PIXELS-1);

  //色配列の初期化
  setAnimationPatternToBlank();
  setAnimationPattern(2, 5);

  // Enable interrupts
  sei();
}

void loop()  
{
  // put your main code here, to run repeatedly:

  // 着陸するヘリとの距離に応じてアニメーションを変化させる

  int sensorValue = analogRead(DISTANCE_SENSOR);
  float voltage = (float)sensorValue * (MAX_VOLTAGE / 1024.0);

  if (voltage > 1.2) {
    // 距離が約5cm以内 赤色点滅 早くアニメーション
    setAnimationPattern(0, 1);
  } else if (voltage > 0.6) {
    // 距離が約15cm以内 緑色点滅 少しゆっくりとでアニメーション
    setAnimationPattern(1, 3);
  } else if (voltage < 0.6) {
    // 距離が約15cm以上 青色点滅 ゆっくりとアニメーション
    setAnimationPattern(2, 5);
  }
}

void setAnimationPatternToBlank()  
{
  // 全てのWS2822Sピクセルの色情報をR,G,B=0,0,0とする
  for (int ledAddr=0; ledAddr<NUM_PIXELS; ledAddr++) {
    LED.setColor(ledAddr, 0, 0, 0);
  }
  LED.send();
}

void setAnimationPattern(uint8_t _animPattern, uint16_t _animWaitTime)  
{
  // アニメーションのパターンが現在の物と異なったら初期化
  if (animPattern != _animPattern) {
    animWaitTime = _animWaitTime;
    animPattern  = _animPattern;
    animFrameNum = 0;
  }
}

// LEDの色情報を1秒以内に再送信
ISR(TIM1_COMPA_vect)  
{
  // 設定されたアニメーションのパターンとフレームをLEDに設定 & 送信
  for (int ledAddr=0; ledAddr<NUM_PIXELS; ledAddr++) {
    LED.setColor(ledAddr, pgm_read_byte_near(&displayAnim[animPattern][(animFrameNum*NUM_PIXELS*RGB)+(ledAddr*RGB)]),
                          pgm_read_byte_near(&displayAnim[animPattern][(animFrameNum*NUM_PIXELS*RGB)+(ledAddr*RGB)+1]),
                          pgm_read_byte_near(&displayAnim[animPattern][(animFrameNum*NUM_PIXELS*RGB)+(ledAddr*RGB)+2]));
  }
  LED.send();

  // タイマー割り込みのタイミング * animWaitTimeの値で アニメーションのフレームを進める
  if (toggleCount < animWaitTime) {
    toggleCount++;
  } else {
    if (animFrameNum < (FRAME_MAX-1)) {
      animFrameNum++;
    } else {
      animFrameNum = 0;
    }
    toggleCount = 0;
  }
}

利用した物

  • Adafruit Trinket 5V Logic

https://www.switch-science.com/catalog/1501/

  • 抵抗
    LM317の出力電圧調整に数種類試してよさそうな抵抗値を選択しました。
  • ブレッドボード
    多少余裕のある大きさをおすすめします
    自分は秋月電子で600円の物を利用しています。

http://akizukidenshi.com/catalog/g/gP-00319/

  • ジャンパキット 使い捨てでも良ければ安いものでも全然いけます

お高いですがヘタリが少なく繰り返し使え、ブレッドボードに刺さらない部品もクリップで接続できたり便利です

参考情報

http://www.geocities.jp/zattouka/GarageHouse/micon/Arduino/DMSU/DMSU2.htm
とても参考になりました、ありがとうございました。

takashi