IT井戸端会議

IT井戸端会議

インフラ、ネットワーク、アプリケーション開発、IT界隈の話等々を東京都千代田区界隈から発信します。

初心者が Arduino ボードを触ってみた

電子工作すらまともにやったことのない私ですが、 Arduino ボードを購入して触ってみました。

Arduino ボードは、ATmega をベースに作られたマイコンボードです。 最近、Arduino 互換の製品が増えてきていることもあり、試してみることにしました。

Arduino ボードは種類がいくつもありますが、今回は、一番メジャーなArduino UNOを使用します。

Arduino UNO は、公式サイトに以下のとおり記載されています。

Microcontroller ATmega328P
Operating Voltage 5V
Input Voltage (recommended) 7-12V
Input Voltage (limit) 6-20V
Digital I/O Pins 14 (of which 6 provide PWM output)
PWM Digital I/O Pins 6
Analog Input Pins 6
DC Current per I/O Pin 20 mA
DC Current for 3.3V Pin 50 mA
Flash Memory 32 KB (ATmega328P)of which 0.5 KB used by bootloader
SRAM 2 KB (ATmega328P)
EEPROM 1 KB (ATmega328P)
Clock Speed 16 MHz
Length 68.6 mm
Width 53.4 mm
Weight 25 g

今回はIRレシーバを使用し、リモコンを受信テストをしてみます。

配線

配線は、いろいろネットで調べたり、試したりしながら、以下のようにしました。 f:id:candapc:20160117144134p:plain:w300

コーディング

Arduino 公式アプリを使用して、以下の通りコーディングを行いました。

IR受信には、別途ライブラリが必要とのことで、以下のサイトからダウンロードして、配置してます。

https://github.com/z3t0/Arduino-IRremote

#include <IRremote.h>

int RECV_PIN = 11;
int LED_PIN = 3;

IRrecv irrecv(RECV_PIN);
IRsend irsend;

decode_results results;

void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn();
  pinMode(LED_PIN, OUTPUT);
}

void storeCode(decode_results *results) {
    String rcvCode = String(results->value,HEX);
    Serial.print("0x" + rcvCode + ": ");
    switch(results->value)
    {
      case 0xe730e916:  
        Serial.println("ON!");
        digitalWrite(LED_PIN, HIGH);
        delay(300);
        digitalWrite(LED_PIN, LOW);
        break;
      case 0xe730d12e:
        Serial.println("OFF!");
        digitalWrite(LED_PIN, HIGH);
        delay(300);
        digitalWrite(LED_PIN, LOW);
        break;
      default:
        Serial.println("OTHERS..");
    }
}

void loop() {
  if (irrecv.decode(&results)) {
    storeCode(&results);
    irrecv.resume();
  }
}

アプリから検証とアップロードを行えば、使用可能となります。

テスト

早速試してみると、リモコンを操作したタイミングで、無事にLEDが付きました。

シリアルモニタを開くと、以下の通り、16進数の受信コードと 押したボタンごとの状態表示(ONOFFOTHERSの文字列)が表示されることも確認できました。 f:id:candapc:20160117144223p:plain:w300

所感

若干、電圧とか気になりますが、動作したので、一旦気にしない〜

やっていて感じましたが、ITのシステム構築と似てますね。

H/W(各電子パーツ)を購入して、LAN(銅線)引いて、アプリ開発(コーディング)..w

次回は、乾電池使ったりとか、DCモータの制御とか、やろうかなぁ..

余談

ちなみにライブラリに付属してるサンプルアプリで2進数でコードが見れます。

このあたりの記事を見ましたが...電子工作が嫌いになりそうだったので見るのやめましたw

http://cranberrytree.blogspot.jp/2012/11/arduino2.html

http://elm-chan.org/docs/ir_format.html

最終的にコード解析は、ライブラリ付属のIRrecordを使用しました。

/*
 * IRrecord: record and play back IR signals as a minimal 
 * An IR detector/demodulator must be connected to the input RECV_PIN.
 * An IR LED must be connected to the output PWM pin 3.
 * A button must be connected to the input BUTTON_PIN; this is the
 * send button.
 * A visible LED can be connected to STATUS_PIN to provide status.
 *
 * The logic is:
 * If the button is pressed, send the IR code.
 * If an IR code is received, record it.
 *
 * Version 0.11 September, 2009
 * Copyright 2009 Ken Shirriff
 * http://arcfn.com
 */

#include <IRremote.h>

int RECV_PIN = 11;
int BUTTON_PIN = 12;
int STATUS_PIN = 13;

IRrecv irrecv(RECV_PIN);
IRsend irsend;

decode_results results;

void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
  pinMode(BUTTON_PIN, INPUT);
  pinMode(STATUS_PIN, OUTPUT);
}

// Storage for the recorded code
int codeType = -1; // The type of code
unsigned long codeValue; // The code value if not raw
unsigned int rawCodes[RAWBUF]; // The durations if raw
int codeLen; // The length of the code
int toggle = 0; // The RC5/6 toggle state

// Stores the code for later playback
// Most of this code is just logging
void storeCode(decode_results *results) {
  codeType = results->decode_type;
  int count = results->rawlen;
  if (codeType == UNKNOWN) {
    Serial.println("Received unknown code, saving as raw");
    codeLen = results->rawlen - 1;
    // To store raw codes:
    // Drop first value (gap)
    // Convert from ticks to microseconds
    // Tweak marks shorter, and spaces longer to cancel out IR receiver distortion
    for (int i = 1; i <= codeLen; i++) {
      if (i % 2) {
        // Mark
        rawCodes[i - 1] = results->rawbuf[i]*USECPERTICK - MARK_EXCESS;
        Serial.print(" m");
      } 
      else {
        // Space
        rawCodes[i - 1] = results->rawbuf[i]*USECPERTICK + MARK_EXCESS;
        Serial.print(" s");
      }
      Serial.print(rawCodes[i - 1], DEC);
    }
    Serial.println("");
  }
  else {
    if (codeType == NEC) {
      Serial.print("Received NEC: ");
      if (results->value == REPEAT) {
        // Don't record a NEC repeat value as that's useless.
        Serial.println("repeat; ignoring.");
        return;
      }
    } 
    else if (codeType == SONY) {
      Serial.print("Received SONY: ");
    } 
    else if (codeType == RC5) {
      Serial.print("Received RC5: ");
    } 
    else if (codeType == RC6) {
      Serial.print("Received RC6: ");
    } 
    else {
      Serial.print("Unexpected codeType ");
      Serial.print(codeType, DEC);
      Serial.println("");
    }
    Serial.println(results->value, HEX);
    codeValue = results->value;
    codeLen = results->bits;
  }
}

void sendCode(int repeat) {
  if (codeType == NEC) {
    if (repeat) {
      irsend.sendNEC(REPEAT, codeLen);
      Serial.println("Sent NEC repeat");
    } 
    else {
      irsend.sendNEC(codeValue, codeLen);
      Serial.print("Sent NEC ");
      Serial.println(codeValue, HEX);
    }
  } 
  else if (codeType == SONY) {
    irsend.sendSony(codeValue, codeLen);
    Serial.print("Sent Sony ");
    Serial.println(codeValue, HEX);
  } 
  else if (codeType == RC5 || codeType == RC6) {
    if (!repeat) {
      // Flip the toggle bit for a new button press
      toggle = 1 - toggle;
    }
    // Put the toggle bit into the code to send
    codeValue = codeValue & ~(1 << (codeLen - 1));
    codeValue = codeValue | (toggle << (codeLen - 1));
    if (codeType == RC5) {
      Serial.print("Sent RC5 ");
      Serial.println(codeValue, HEX);
      irsend.sendRC5(codeValue, codeLen);
    } 
    else {
      irsend.sendRC6(codeValue, codeLen);
      Serial.print("Sent RC6 ");
      Serial.println(codeValue, HEX);a
    }
  } 
  else if (codeType == UNKNOWN /* i.e. raw */) {
    // Assume 38 KHza
    irsend.sendRaw(rawCodes, codeLen, 38);
    Serial.println("Sent raw");
  }
}

int lastButtonState;

void loop() {
  // If button pressed, send the code.
  int buttonState = digitalRead(BUTTON_PIN);
  if (lastButtonState == HIGH && buttonState == LOW) {
    Serial.println("Released");
    irrecv.enableIRIn(); // Re-enable receiver
  }

  if (buttonState) {
    Serial.println("Pressed, sending");
    digitalWrite(STATUS_PIN, HIGH);
    sendCode(lastButtonState == buttonState);
    digitalWrite(STATUS_PIN, LOW);
    delay(50); // Wait a bit between retransmissions
  } 
  else if (irrecv.decode(&results)) {
    digitalWrite(STATUS_PIN, HIGH);
    storeCode(&results);
    irrecv.resume(); // resume receiver
    digitalWrite(STATUS_PIN, LOW);
  }
  lastButtonState = buttonState;
}

シリアルモニタの出力はこんな感じになりました。 スクリーンショット 2015-08-14 0.32.16

今回、TOSHIBA製のリモコンを使用しましたが、NECフォーマットを使用してるようです。