SSブログ

Arduinoでモーションセンサを使ってみる [Arduino]

Arduinoでモーションセンサを使ってみる.
使ったのは,Panasonicの焦電型赤外線センサのうち,NaPiOn (ナピオン) シリーズAMN31112だ.

このセンサは,電源とGNDと出力ピンしかないので,接続も簡単だ.
Arduinoとの接続はこんな感じ.
出力ピンをプルダウンしなければいけないというのが唯一の注意点.
pir_sensor_回路図.png

Arduinoのスケッチはこんな感じ.
const int LED = 13;
const int PIR = 2;

void setup() {
  pinMode(LED, OUTPUT);
  pinMode(PIR, INPUT);
}

void loop() {
  if (digitalRead(PIR) == HIGH) {
    digitalWrite(LED, HIGH);
  } 
  else {
    digitalWrite(LED, LOW);
  }

  delay(200);
}

これでモーションセンサが人体検出したら,Arduino上のLEDが点灯する.

モーションセンサ側がいろいろやってくれるので,Arduino側からは単に出力を見るだけでOK.
とても簡単だ.
お試しあれ.

nice!(1)  トラックバック(0) 
共通テーマ:日記・雑感

Edisonでmraaを使ってLチカをやってみる [edison]

以前は,Arduino IDEを使ってLチカをやってみたが,今回はmraaを使ってLチカをやってみる.
回路図は以前と同じ.

なお,Arduino IDEでいう13番ピンは,EdisonモジュールのGP40ピンだが,mraaでは別途ピン番号が管理されていて,mraa numberは37になる.ちなみに,情報は「mraa/edison.md at master · intel-iot-devkit/mraa · GitHub」にある.

今回はEclipseを使ってクロスビルドして試してみた.Eclipseでの開発はこんな感じ.
スクリーンショット 2014-11-29 20.21.49.png

参考にしたのは,公式の,「Getting Started for C/C++ (Eclipse) - Galileo & Edison」だ.

コードは,スクリーンショットをみれば分かるが,一応ここにも記載しておく.
#include "mraa.hpp"

static int iopin = 37;

int main(int argc, char **argv) {
    mraa::Gpio* gpio = new mraa::Gpio(iopin);
    if (gpio == NULL) {
        return MRAA_ERROR_UNSPECIFIED;
    }

    mraa_result_t response = gpio->dir(mraa::DIR_OUT);
    if (response != MRAA_SUCCESS) {
        mraa::printError(response);
        return 1;
    }

    while (true) {
        response = gpio->write(1);
        sleep(1);
        response = gpio->write(0);
        sleep(1);
    }
    delete gpio;
    return response;
}


Eclipseからはリモートデバッグも可能なようだ.

それにしてもArduino IDEからの制御も楽だが,mraaも楽だな...
お試しあれ.

タグ:Eclipse
nice!(1)  トラックバック(0) 
共通テーマ:日記・雑感

Edisonに照度センサをつないでみる [edison]

前回,Arduinoに照度センサをつないでみたが,今回はEdisonにつないでみる.
EdisonはIntel Edison Breakout Boardを使っているので,IOは1.8Vだ.arduinoのときは5Vだったが今回は1.8Vだ.だけど,秋月のI2Cバス用双方向電圧レベル変換モジュール(PCA9306)を経由して接続するってのは変わらない.

接続はこんな感じ.
当初はこんな感じで接続していたが,Kさんからコメントいただいたように,AE-PCA9306ではVref2側を高電圧側にするべきである.
luminance_sensor_ng.png
なので,こちらの回路図のように接続すべきである.
luminance_sensor.png

今回もArduino IDEで動かしてみる.
スケッチは,前回Arduinoで動かしたときと全く一緒でOK.

が,動かしてみたらうまく動かなかった.

調べてみると,こんな記事が見つかった.
Edison のI2Cを試してみる — Edison-Note 1.3 documentation
Edison Breakout BoardでI2C通信テスト[1](C言語,mraaライブラリ,PCA9306,DRV8830を使用) - Qiita

どうやらEdisonのI2Cは内蔵プルアップが有効になっているようで,一方,秋月のレベル変換モジュールもデフォルトではプルアップが有効になっていて,これのせいでうまく通信できない.

最初はEdisonの内蔵プルアップを無効にしようと思ったんだけど,さんざんWeb上の情報を探したけど方法が見つからなかった.というわけで,秋月のレベル変換のプルアップを無効にすることにした.やりかたは,AE-PCA9306モジュール取扱説明書(927KB)に書かれている通り,ジャンパをカットすればいい.
今回は,Edison側だけレベル変換モジュールのプルアップを無効にして,照度センサ側は(センサ側でプルアップしてないので)レベル変換モジュールのプルアップは有効のままにしておく.

上記の回路図のように接続しているので,カットするジャンパは,J2とJ3 J4とJ5だ.

で,これで試したら無事通信できた.Arduinoで試したときと同じように動いたのでOKだ.
お試しあれ.
nice!(1)  トラックバック(0) 
共通テーマ:日記・雑感

Arduinoに照度センサをつないでみる [Arduino]

手元のジャンクにI2C接続の照度センサがあったのでArduinoにつないでみた.
照度センサは,ROHMのBH1751FVI.I2Cで制御するタイプだ.
で,ArduinoとはIOの電圧が違うので直結できない.なので,秋月のI2Cバス用双方向電圧レベル変換モジュール(PCA9306)を経由して接続してやる.

こんな感じ.
Untitled.png

間にI2Cのレベル変換を挟んでいるだけで,基本的には素直に接続なので悩むことはないと思う.

で,Arduino側のスケッチはこんな感じ.
#include <Wire.h>

const int SensorAddress = 0x23;
const int CommandHResolutionSingle = 0x20;
const int ReadDataNum = 2;

void setup()
{
  Wire.begin();
  Serial.begin(9600);
}

void loop()
{
  Wire.beginTransmission(SensorAddress);
  Wire.write(CommandHResolutionSingle);
  Wire.endTransmission();
  
  Wire.requestFrom(SensorAddress, ReadDataNum);

  while (Wire.available() < ReadDataNum);
  
  unsigned int h = Wire.read();
  unsigned int l = Wire.read();
  double lx = convertSensorDataToLx(h, l);
  Serial.println(lx);

  delay(500);  
}

double convertSensorDataToLx(unsigned int high, unsigned int lo)
{
  double result = (high * 256u + lo) / 1.2;
  return result;
}

簡単すぎる.これでシリアルに照度値が出力されるようになる.
Arduinoってなにかちょっと試すのにホント便利だなぁ.
nice!(0)  トラックバック(0) 
共通テーマ:日記・雑感

EdisonでLチカを試してみる [edison]

Edisonで定番のLチカをやってみる.
IntelのGetting Started GuideではIntel Edison Arduino BoardでのLチカが説明されているが,うちはIntel Edison Breakout Boardなのでちょっと違うが,まぁ試してみる.

といっても,Arduino IDEをダウンロードして,SampleのBlinkを書き込んでやるだけだ.

ただ,LEDはArduino Boardの13番ピンにつながってる前提のサンプルなのだが,Breakout BoardにArduinoの13番ピンなんてないので,該当するピンに読み替えてやる必要がある.

で,回路図をみると,Arduino Boardの13番ピンは,EdisonモジュールのGP40ピンで,これはBreakout BoardでいうJ19-10番ピンにつながっているようだ.

というわけで,LEDをつないでテストしてみる.
ただ,Breakout BoardはIOが1.8Vで,かつIO出力も3mAしかないようなので,そのままLEDを点灯させるのはやめて,レベル変換ICを通して点灯させることにする.
レベル変換ICは先日購入しておいた,秋月電子の「8ビット双方向ロジックレベル変換モジュール」を使う.

で,こんな感じに接続.
Untitled.png

DSC_0131 のコピー.jpg

これで試したら,LEDの点滅が無事確認できた.

さて,次は何に手を出そうか...

nice!(2)  トラックバック(0) 
共通テーマ:日記・雑感

intel Edisonを入手してみる [edison]

intel Edisonを買ってみた.

「Edison Kit for Arduino」と,「Edison Breakout Board Kit」のどちらにするか迷ったが,せっかくEdisonが小さいんだからその小ささが生かされる「Edison Breakout Board Kit」にしてみた.

で,購入したのはこれ.
Intel Edison Breakout Board Kit
USBケーブル Aオス-マイクロBオス 1.5m A-microB 2本
スチロールケース SK-2

ケースは秋月のサイトで「びったとり入ります」と書かれていたので買ってみた.

あと,「Edison Breakout Board Kit」のIO電圧は1.8Vなので,
8ビット双方向ロジックレベル変換モジュール
も買った.

それから,Breakout Boardはピンホールがあるだけで,いろいろ試すとするとピンホールに線材を半田付けすることになると思うが,いきなり半田付けってのはやりたくないなぁと思ってたら,スルーホール用テストワイヤというのがあったのでそれも買ってみた.
テストワイヤ TTW-200
TTW-200_02.jpg

「スルーホールに挿し込むだけで信号の入力やチェックができます」とのことで,半田付けせずに試せる.ただ,Breakout Boardに思いっきり挿すとEdison本体のシールドに接触するかもしれないので,何らかの絶縁はした方が良さそうである.とりあえずうちでは紙を挟んである.

で,実は10月末には入手済みだったのだが,最近やっといじり始めている.
とりあえず,最新のFWにアップデートして,WiFi設定なんかまではやってみた.この辺の作業内容は本家含めネット上にたくさん情報があるのでそれを参考に.

それにしても小さい.以前,BeagleBoard-xMを入手したときにも「小さいなぁ」と感じたけど,これはもっと小さい.
Raspberry Piだって十分小さいけど,それよりも小さい.しかもパワフル.

さて,とりあえず次回はLチカやってみよう.
nice!(1)  トラックバック(0) 
共通テーマ:日記・雑感

秋月電子のATmega168/328マイコンボードキットを組み立ててみる [Arduino]

Arduino 互換ボードになるATmega168/328マイコンボードキットを組み立ててみた.AE-ATmegaというやつだ.
DSC_0130 のコピー.jpg

組み立ては難しくなくて,説明書の順番通り半田付けしていけばOK.
ただ,USBシリアル変換モジュール(AE-UM232R)は使い回したいので直接半田付けはしなかった.本当はICソケットを使うのがいいんだろうけど,手元になかったのでやむなくピンソケットをつけてみた.
なので,USBシリアル変換のところだけやたら高さが高くなってしまった.

で,組み立てが終わったらArduino化するためにブートローダーを書き込む.
ネットで調べると,ブートローダーの書き込みはいくつかの方法があるようだが,手元にあるArduino UNOを使って書き込むことができるようなので,それを試してみた.ArduinoISPと呼ぶようである.

方法は,本家「Arduino - ArduinoISP」,もしくはその日本語訳サイト「Arduino を AVR プログラマ(ISP: In-System Programmer)として使う」に情報がある.
で,接続はこんな感じでOK.
arduinoisp.png

あとは書き込み手順通りに進める.
ターゲットボードは,AE-Atmegaはないので,「Arduino Diecimila or Duemilanove w/ ATmega168」を選択する.

で,書き込むのだが,残念ながらこの方法では書き込めない.
こんなエラーが出る.
avrdude: Expected signature for ATMEGA168 is 1E 94 06
Double check chip, or use -F to override this check.


調べてみると,どうやら「Arduino Diecimila or Duemilanove w/ ATmega168」はATmega168なのだが,AE-ATmegaに載っているのはATmega168Pなので,チェックで引っかかるようだ.

というわけで,このままではブートローダーを書き込めないので,なんとかATmega168として認識されるようにごまかしてみた.

以下のやり方はMac環境化での話になるが,ほかの環境でも同様のことができると思う.
では,方法だが,とても簡単.

/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/etc/下にある,avrdude.confを編集する.
で,編集する部分を一部抜粋したのが以下.
#------------------------------------------------------------
# ATmega168
#------------------------------------------------------------

part
    id              = "m168";
    desc            = "ATMEGA168";
     has_debugwire = yes;
     flash_instr   = 0xB6, 0x01, 0x11;
     eeprom_instr  = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00,
	             0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF,
	             0x99, 0xF9, 0xBB, 0xAF;
    stk500_devcode  = 0x86;
    # avr910_devcode = 0x;
    signature       = 0x1e 0x94 0x06;

このうち,
    signature       = 0x1e 0x94 0x06;
を168P用に一時的に変更する.
つまり,
    signature       = 0x1e 0x94 0x0b;
にしてやる.
これで書き込める.

書き込みが終わったら変更を元に戻しておくことを忘れずに.

ここまできたら,もう普通にArduinoとして使える.
サンプルスケッチを書き込んでみて,動作を確認してみたが,問題なく動作した.

お試しあれ.

タグ:AE-ATmega
nice!(1)  トラックバック(0) 
共通テーマ:日記・雑感

ov7670+Arduino+ProcessingでTimelapseをやってみる [Arduino]

長らく放置していたCMOSカメラのov7670だが,とりあえず,秋月電子通商Arduino用ユニバーサル基板に組んでみた.
こんな感じ.
DSC_0128 のコピー.jpgDSC_0129 のコピー.jpg

で,Arduino側は前はQQVGAだったけど,VGAで画像取得できるようにして,あとProcessingで画像表示用にこんなの作ってみた.
スクリーンショット 2014-11-03 9.58.06.png

これで画像を保存できるようにしたので,画像を撮りまくってTimelapseをやってみた.
その動画がこれ.同じような動画ばっかりだけど...






かなり簡単にできた.Processingが画像を動画にしてくれるので楽だ.

ArduinoとProcessingのコードはかなり適当な作りなので,もし要望があったら公開しようと思う.

2015.05.30追記
ArduinoとProcessingのコードはこちら.
久しぶりにov7670+Arduino+Processingを動かしてみる

お試しあれ.

タグ:TIMELAPSE
nice!(1)  トラックバック(0) 
共通テーマ:日記・雑感

RaspbmcにFMトランスミッターをつないでみる [Raspberry Pi]

普段,音楽を聴くときはRaspberry PiにインストールしたXBMC(Raspbmc)を使っていて,TVとはHDMIでつないでいる.
普段はそれでいいんだけど,うちではたまにベランダでご飯を食べるときがあって,そのときにも音楽が聞きたい.だけどTVからの音声をベランダで聞くのは難しい.
ということで,Raspbmcの音をFMトランスミッターで飛ばして,ベランダではFMラジオを通して音楽を聴くというのを試してみた.

で,まずはFMトランスミッター.
秋月のFMステレオ・トランスミッタキットを買ってみた.通販コード K-00086のやつで,NJM2035Dが載っている.1000円.秋月には4800円の新潟精密製FM送信モジュールNS73Mが載ったやつもあるのだが,とりあえず安い方を買ってみた.

組み立てはそんなに難しくない.説明書の通りに半田付けしていけばいい.小型コンデンサマイクが付属してくるけど,うちではまず使いそうもないので取り付けなかった.
3.5mmのステレオプラグと電源ON/OFF用のスイッチを取り付けて,無事完成.
こんな感じ.
名称未設定.jpg
アンテナには,先がBNCになってるケーブルをつないだ.そこからアンテナをつなごうと思ったんだけど,つないでもつながなくても電波の飛びがあまり変わらなかったので,BNCケーブルを引き出しただけで終わってる.

ま,そもそもRaspberry Piがある場所からベランダまで電波が飛べば十分なのと,使ってるFMラジオがソニーの手回しラジオICF-B03というやつなので,音質は気にしてない.聴ければいいというレベル.ちゃんと聴く人はアンテナとか気にした方がいいと思うけど,そもそもそういう人はこの1000円のじゃなくて4800円の方を買った方がいいかもしれない.

しかも,ネットで調べると,全然電波が飛ばないという人と,10mぐらい飛ぶって人といろいろ情報があるみたい.旧バージョンはよく飛んだけど今のはそれなりとかいう情報もあるし,よくわからない.
うちでは,確かに設置場所とかちょっとしたケーブルの取り回しで様子が変わったりしたので,かなりデリケートなのかもしれない.

で,Raspbmc側.
通常は,システム -> 設定 -> システム -> オーディオハードウェアでオーディオ出力デバイスをHDMIかAnalogueを選択するようになっているのだが,Raspbmcの設定画面で設定レベルを変更すると「Dual audio output」を選択できるようになる.なので,この「Dual audio output」を選択する.
が,しかし,これを選択してもHDMIとアナログの両方から出力はされない.

で,調べてみると,どうやら,Raspbmcではaudio playerとしてデフォルトはPAPlayerというのが使われているらしいのだが,これは「Dual audio output」に対応しておらず,OMXPlayerを使う必要があるらしい.

というわけでデフォルトのaudio playerをOMXPlayerに変更してみる.
変更するには,raspbmc上の/home/pi/.xbmc/userdata/下にadvancedsettings.xmlファイルを作ってやる.そしてadvancedsettings.xmlファイルに以下のように記述してやる.
<advancedsettings>
  <audio>
    <defaultplayer>omxplayer</defaultplayer>
  </audio>
</advancedsettings>


これでOK.HDMIとアナログの両方から出力されるはずだ.

お試しあれ.

nice!(1)  トラックバック(0) 
共通テーマ:日記・雑感

ArduinoでCMOSカメラの画像を取得してみる [Arduino]

先日,ArduinoとCMOSカメラを接続して動かしてみたので,いよいよ画像を取得してみる.

というわけで,早速だがArduinoのスケッチを示そう.

ファイルは2つあって,ov7670.inoとov7670reg.hだ.
まずはov7670.ino
#include <Wire.h>
#include "ov7670reg.h"

// Pin
const int WEN   = 14; // PC0
const int RRST  = 15; // PC1
const int OE    = 16; // PC2
const int RCLK  = 17; // PC3
const int VSYNC =  2; // PD2 INT0
const int D0    =  8; // PB0
const int D1    =  9; // PB1
const int D2    = 10; // PB2
const int D3    = 11; // PB3
const int D4    =  4; // PD4
const int D5    =  5; // PD5
const int D6    =  6; // PD6
const int D7    =  7; // PD7

boolean isWriteEnable = false;


void setPinMode()
{
  pinMode(WEN,   OUTPUT);
  pinMode(RRST,  OUTPUT);
  pinMode(OE,    OUTPUT);
  pinMode(RCLK,  OUTPUT);
  pinMode(D0,    INPUT );
  pinMode(D1,    INPUT );
  pinMode(D2,    INPUT );
  pinMode(D3,    INPUT );
  pinMode(D4,    INPUT );
  pinMode(D5,    INPUT );
  pinMode(D6,    INPUT );
  pinMode(D7,    INPUT );

  attachInterrupt(0, setWriteEnable, FALLING);

  digitalWrite(WEN,  LOW);
  digitalWrite(RRST, HIGH);
  digitalWrite(OE,   HIGH);
  digitalWrite(RCLK, HIGH);
}

void setWriteEnable()
{
  if (isWriteEnable) {
    digitalWrite(WEN, HIGH);
    isWriteEnable = false;
  } else {
    digitalWrite(WEN, LOW);
  }
}

void initFifo()
{
  digitalWrite(RCLK, HIGH); digitalWrite(RRST, HIGH); digitalWrite(OE, HIGH);
  digitalWrite(RCLK, HIGH); digitalWrite(RRST, LOW ); digitalWrite(OE, HIGH);
  digitalWrite(RCLK, LOW ); digitalWrite(RRST, LOW ); digitalWrite(OE, HIGH);
  digitalWrite(RCLK, HIGH); digitalWrite(RRST, LOW ); digitalWrite(OE, HIGH);
  digitalWrite(RCLK, LOW ); digitalWrite(RRST, LOW ); digitalWrite(OE, HIGH);
  digitalWrite(RCLK, LOW ); digitalWrite(RRST, HIGH); digitalWrite(OE, HIGH);
  digitalWrite(RCLK, HIGH); digitalWrite(RRST, HIGH); digitalWrite(OE, HIGH);
  digitalWrite(RCLK, HIGH); digitalWrite(RRST, HIGH); digitalWrite(OE, LOW );
  digitalWrite(RCLK, LOW ); digitalWrite(RRST, HIGH); digitalWrite(OE, LOW );
  digitalWrite(RCLK, HIGH); digitalWrite(RRST, HIGH); digitalWrite(OE, LOW );
}

void readFifo()
{
  const int HSIZE = 160;
  const int VSIZE = 120;
  const int DATABYTE = 2;

  int d0, d1, d2, d3, d4, d5, d6, d7;
  byte data;

  for (int v = 0; v < VSIZE; v++) {
    for (int h = 0; h < HSIZE; h++) {
      for (int d = 0; d < DATABYTE; d++) {
        digitalWrite(RCLK, HIGH);
        d0 = digitalRead(D0);
        d1 = digitalRead(D1);
        d2 = digitalRead(D2);
        d3 = digitalRead(D3);
        d4 = digitalRead(D4);
        d5 = digitalRead(D5);
        d6 = digitalRead(D6);
        d7 = digitalRead(D7);
        data = pinLevel2Byte(d0, 0)
          + pinLevel2Byte(d1, 1)
          + pinLevel2Byte(d2, 2)
          + pinLevel2Byte(d3, 3)
          + pinLevel2Byte(d4, 4)
          + pinLevel2Byte(d5, 5)
          + pinLevel2Byte(d6, 6)
          + pinLevel2Byte(d7, 7);
        digitalWrite(RCLK, LOW);

        char temp[3];
        snprintf(temp, sizeof(temp), "%02X", data);
        Serial.print(temp);
      }
    }
    Serial.println("");
  }

  // read end
  digitalWrite(RCLK, LOW ); digitalWrite(OE, HIGH);
  digitalWrite(RCLK, HIGH); digitalWrite(OE, HIGH);
}

byte pinLevel2Byte(int level, int shift)
{
  byte result = (level == HIGH) ? 1 : 0;
  return result << shift;
}

void writeRegister(int address, int data)
{
  const int I2C_WRITE_ADDR = 0x42;

  Wire.beginTransmission(I2C_WRITE_ADDR >> 1);
  Wire.write(address);
  Wire.write(data);
  Wire.endTransmission();
}

int readRegister(int address)
{
  const int I2C_READ_ADDR = 0x43;

  Wire.beginTransmission(I2C_READ_ADDR >> 1);
  Wire.write(address);
  Wire.endTransmission();

  Wire.requestFrom(I2C_READ_ADDR >> 1, 1);
  return Wire.read();
}

void resetCamera()
{
  writeRegister(0x12, 0x80);
  delay(200);
}

void initRegister()
{
  // QQVGA, RGB444
  writeRegister(REG_CLKRC,  0x80);
  writeRegister(REG_COM11,  0x0A);
  writeRegister(REG_TSLB,   0x04);
  writeRegister(REG_COM7,   0x04);
  writeRegister(REG_RGB444, 0x02);
  writeRegister(REG_COM15,  0xD0);
  writeRegister(REG_HSTART, 0x16);
  writeRegister(REG_HSTOP,  0x04);
  writeRegister(REG_HREF,   0x24);
  writeRegister(REG_VSTART, 0x02);
  writeRegister(REG_VSTOP,  0x7A);
  writeRegister(REG_VREF,   0x0A);
  writeRegister(REG_COM10,  0x02);
  writeRegister(REG_COM3,   0x04);
  writeRegister(REG_COM14,  0x1A);
  writeRegister(0x72,       0x22);
  writeRegister(0x73,       0xF2);

  // COLOR SETTING
  writeRegister(0x4F, 0x80);
  writeRegister(0x50, 0x80);
  writeRegister(0x51, 0x00);
  writeRegister(0x52, 0x22);
  writeRegister(0x53, 0x5E);
  writeRegister(0x54, 0x80);
  writeRegister(0x56, 0x40);
  writeRegister(0x58, 0x9E);
  writeRegister(0x59, 0x88);
  writeRegister(0x5A, 0x88);
  writeRegister(0x5B, 0x44);
  writeRegister(0x5C, 0x67);
  writeRegister(0x5D, 0x49);
  writeRegister(0x5E, 0x0E);
  writeRegister(0x69, 0x00);
  writeRegister(0x6A, 0x40);
  writeRegister(0x6B, 0x0A);
  writeRegister(0x6C, 0x0A);
  writeRegister(0x6D, 0x55);
  writeRegister(0x6E, 0x11);
  writeRegister(0x6F, 0x9F);

  writeRegister(0xB0, 0x84);
}

void printData(int address, int data)
{
  char temp[16];
  snprintf(temp, sizeof(temp), "addr=%02X data=%02X", address, data);
  Serial.println(temp);
}

void receiveCommand(char *buff)
{
  char c = '\0';
  while (c != '\r' ) {
    if (Serial.available() > 0) {
      c = Serial.read();
      Serial.print(c);
      *buff++ = c;
    }
  }
  *buff = '\0';
  Serial.println("");
}

void setup()
{
  Serial.begin(115200);
  Wire.begin(); 

  printMenu();

  setPinMode();
  resetCamera();
  initRegister();
}

void loop()
{
  int address  = 0;
  int data = 0;

  char buff[256];
  char *buff_ptr;
  char *cmd_ptr;
  char *arg1_ptr;
  char *arg2_ptr;
  const char DELIMITTER[] = " \t";

  Serial.print("> ");
  receiveCommand(buff);

  //  trim white space
  buff_ptr = buff;
  while ( (*buff_ptr == ' ') || (*buff_ptr == '\t') || (*buff_ptr == '\n') ) {
    buff_ptr++;
  }

  cmd_ptr = strtok(buff_ptr, DELIMITTER);

  switch (tolower(*cmd_ptr)) {
    case 'w':
      arg1_ptr = strtok(NULL, DELIMITTER);
      arg2_ptr = strtok(NULL, DELIMITTER);

      if ( (arg1_ptr != NULL) && (arg2_ptr != NULL) ) {
        address = hex2dec(arg1_ptr);
        data    = hex2dec(arg2_ptr);

        printData(address, data);
        writeRegister(address, data);

        delay(10);

      } else {
        Serial.println("Syntax Error");
      }

      break;
    case 'r':
      arg1_ptr = strtok(NULL, DELIMITTER);

      if (arg1_ptr != NULL) {
        address = hex2dec(arg1_ptr);
        data = readRegister(address);

        printData(address, data);

        delay(50);

      } else {
        Serial.println("Syntax Error");
      }
      break;

    case 'd':
      Serial.println("Dump");
      initFifo();
      readFifo();
      break;

    case 's':
      Serial.println("Start");
      isWriteEnable = true;
      break;

    case 'h':
      printHelp();
      break;

    default:
      Serial.println("Syntax Error");
      break;
  }

  Serial.println("");
}

void printMenu()
{
  Serial.println("------------------------------");
  Serial.println(" OV7670 Camera Debugger");
  Serial.println("------------------------------");
  Serial.println("");
}

void printHelp()
{
  Serial.println("WRITE :w [address] [data]");
  Serial.println("READ  :r [address]");
  Serial.println("START :s");
  Serial.println("DUMP  :d");
  Serial.println("HELP  :h");
}

int hex2dec(char *str)
{
  return strtol(str, NULL, 16);
}


次にov7670reg.h
#define REG_GAIN        0x00    /* Gain lower 8 bits (rest in vref) */
#define REG_BLUE        0x01    /* blue gain */
#define REG_RED         0x02    /* red gain */
#define REG_VREF        0x03    /* Pieces of GAIN, VSTART, VSTOP */
#define REG_COM1        0x04    /* Control 1 */
#define COM1_CCIR656    0x40    /* CCIR656 enable */
#define REG_BAVE        0x05    /* U/B Average level */
#define REG_GbAVE       0x06    /* Y/Gb Average level */
#define REG_AECHH       0x07    /* AEC MS 5 bits */
#define REG_RAVE        0x08    /* V/R Average level */
#define REG_COM2        0x09    /* Control 2 */
#define COM2_SSLEEP     0x10    /* Soft sleep mode */
#define REG_PID         0x0a    /* Product ID MSB */
#define REG_VER         0x0b    /* Product ID LSB */
#define REG_COM3        0x0c    /* Control 3 */
#define COM3_SWAP       0x40    /* Byte swap */
#define COM3_SCALEEN    0x08    /* Enable scaling */
#define COM3_DCWEN      0x04    /* Enable downsamp/crop/window */
#define REG_COM4        0x0d    /* Control 4 */
#define REG_COM5        0x0e    /* All "reserved" */
#define REG_COM6        0x0f    /* Control 6 */
#define REG_AECH        0x10    /* More bits of AEC value */
#define REG_CLKRC       0x11    /* Clocl control */
#define CLK_EXT         0x40    /* Use external clock directly */
#define CLK_SCALE       0x3f    /* Mask for internal clock scale */
#define REG_COM7        0x12    /* Control 7 */
#define COM7_RESET      0x80    /* Register reset */
#define COM7_FMT_MASK   0x38
#define COM7_FMT_VGA    0x00
#define COM7_FMT_CIF    0x20    /* CIF format */
#define COM7_FMT_QVGA   0x10    /* QVGA format */
#define COM7_FMT_QCIF   0x08    /* QCIF format */
#define COM7_RGB        0x04    /* bits 0 and 2 - RGB format */
#define COM7_YUV        0x00    /* YUV */
#define COM7_BAYER      0x01    /* Bayer format */
#define COM7_PBAYER     0x05    /* "Processed bayer" */
#define REG_COM8        0x13    /* Control 8 */
#define COM8_FASTAEC    0x80    /* Enable fast AGC/AEC */
#define COM8_AECSTEP    0x40    /* Unlimited AEC step size */
#define COM8_BFILT      0x20    /* Band filter enable */
#define COM8_AGC        0x04    /* Auto gain enable */
#define COM8_AWB        0x02    /* White balance enable */
#define COM8_AEC        0x01    /* Auto exposure enable */
#define REG_COM9        0x14    /* Control 9  - gain ceiling */
#define REG_COM10       0x15    /* Control 10 */
#define COM10_HSYNC     0x40    /* HSYNC instead of HREF */
#define COM10_PCLK_HB   0x20    /* Suppress PCLK on horiz blank */
#define COM10_HREF_REV  0x08    /* Reverse HREF */
#define COM10_VS_LEAD   0x04    /* VSYNC on clock leading edge */
#define COM10_VS_NEG    0x02    /* VSYNC negative */
#define COM10_HS_NEG    0x01    /* HSYNC negative */
#define REG_HSTART      0x17    /* Horiz start high bits */
#define REG_HSTOP       0x18    /* Horiz stop high bits */
#define REG_VSTART      0x19    /* Vert start high bits */
#define REG_VSTOP       0x1a    /* Vert stop high bits */
#define REG_PSHFT       0x1b    /* Pixel delay after HREF */
#define REG_MIDH        0x1c    /* Manuf. ID high */
#define REG_MIDL        0x1d    /* Manuf. ID low */
#define REG_MVFP        0x1e    /* Mirror / vflip */
#define MVFP_MIRROR     0x20    /* Mirror image */
#define MVFP_FLIP       0x10    /* Vertical flip */
#define REG_AEW         0x24    /* AGC upper limit */
#define REG_AEB         0x25    /* AGC lower limit */
#define REG_VPT         0x26    /* AGC/AEC fast mode op region */
#define REG_HSYST       0x30    /* HSYNC rising edge delay */
#define REG_HSYEN       0x31    /* HSYNC falling edge delay */
#define REG_HREF        0x32    /* HREF pieces */
#define REG_TSLB        0x3a    /* lots of stuff */
#define TSLB_YLAST      0x04    /* UYVY or VYUY - see com13 */
#define REG_COM11       0x3b    /* Control 11 */
#define COM11_NIGHT     0x80    /* NIght mode enable */
#define COM11_NMFR      0x60    /* Two bit NM frame rate */
#define COM11_HZAUTO    0x10    /* Auto detect 50/60 Hz */
#define COM11_50HZ      0x08    /* Manual 50Hz select */
#define COM11_EXP       0x02
#define REG_COM12       0x3c    /* Control 12 */
#define COM12_HREF      0x80    /* HREF always */
#define REG_COM13       0x3d    /* Control 13 */
#define COM13_GAMMA     0x80    /* Gamma enable */
#define COM13_UVSAT     0x40    /* UV saturation auto adjustment */
#define COM13_UVSWAP    0x01    /* V before U - w/TSLB */
#define REG_COM14       0x3e    /* Control 14 */
#define COM14_DCWEN     0x10    /* DCW/PCLK-scale enable */
#define REG_EDGE        0x3f    /* Edge enhancement factor */
#define REG_COM15       0x40    /* Control 15 */
#define COM15_R10F0     0x00    /* Data range 10 to F0 */
#define COM15_R01FE     0x80    /*            01 to FE */
#define COM15_R00FF     0xc0    /*            00 to FF */
#define COM15_RGB565    0x10    /* RGB565 output */
#define COM15_RGB555    0x30    /* RGB555 output */
#define REG_COM16       0x41    /* Control 16 */
#define COM16_AWBGAIN   0x08    /* AWB gain enable */
#define REG_COM17       0x42    /* Control 17 */
#define COM17_AECWIN    0xc0    /* AEC window - must match COM4 */
#define COM17_CBAR      0x08    /* DSP Color bar */
#define REG_CMATRIX_BASE 0x4f
#define CMATRIX_LEN 6
#define REG_CMATRIX_SIGN 0x58
#define REG_BRIGHT      0x55    /* Brightness */
#define REG_CONTRAS     0x56    /* Contrast control */
#define REG_GFIX        0x69    /* Fix gain control */
#define REG_REG76       0x76    /* OV's name */
#define R76_BLKPCOR     0x80    /* Black pixel correction enable */
#define R76_WHTPCOR     0x40    /* White pixel correction enable */
#define REG_RGB444      0x8c    /* RGB 444 control */
#define R444_ENABLE     0x02    /* Turn on RGB444, overrides 5x5 */
#define R444_RGBX       0x01    /* Empty nibble at end */
#define REG_HAECC1      0x9f    /* Hist AEC/AGC control 1 */
#define REG_HAECC2      0xa0    /* Hist AEC/AGC control 2 */
#define REG_BD50MAX     0xa5    /* 50hz banding step limit */
#define REG_HAECC3      0xa6    /* Hist AEC/AGC control 3 */
#define REG_HAECC4      0xa7    /* Hist AEC/AGC control 4 */
#define REG_HAECC5      0xa8    /* Hist AEC/AGC control 5 */
#define REG_HAECC6      0xa9    /* Hist AEC/AGC control 6 */
#define REG_HAECC7      0xaa    /* Hist AEC/AGC control 7 */
#define REG_BD60MAX     0xab    /* 60hz banding step limit */


これをArduinoに書き込めばOK.

いろいろwebで調べて,とりあえずQQVGAのRGB444で画像取得する例がいくつか見つかったので,それで試してる.

使い方は,シリアルモニタを開いて,
sを入力すると撮影,dで画像データのダンプが行われる.hで簡単なヘルプ(というほどのものでもないが)が表示される.なので,まぁスケッチを見ながらいろいろ試してみてくださいな.

画像データは,QQVGAのRGB444で動かしているので,ダンプすると160x120=19200画素のデータが,1画素あたり2バイト出力される.なので,トータルとしては38400バイトになる.
データの並びは,xBGRで出力される.なお,160画素ごとに改行を入れて出力される.改行を除去すると,1バイトあたり2文字でダンプされるので,結果として,76800文字のデータが得られることになる.

さて,データだけあってもつまらないので,Processingで画像を表示してみる.
Processingのコードは,こんな感じ.
int width = 160;
int height = 120;
String[] pixeldata;

void setup() {
  frameRate(1);
  size(width, height);
  noStroke();
  pixeldata = loadStrings("captureData.txt");
}

void draw() {
  for (int i = 0; i < width * height; i++) {
    int x = i % width;
    int y = i / width;

    fill(
    unhex(String.valueOf(pixeldata[0].charAt(4*i+3))) *16, 
    unhex(String.valueOf(pixeldata[0].charAt(4*i+2))) *16, 
    unhex(String.valueOf(pixeldata[0].charAt(4*i+1))) *16
      );    

    rect(x, y, 1, 1);
  }
}


ダンプしたデータは,captureData.txtとしてProcessingのコードと同じディレクトリに保存してくださいな.

で,表示されるサンプル画像はこんな感じ.スクリーンショット 2014-07-20 9.58.05.png
ま,QQVGなのと,RGB各色4ビットしかないので,画質はそれなりですな.
あと,水平方向の位相がちょっとずれてるようなのと,電源投入一発目の画像がおかしいことがあるんだけど...

ま,お試しあれ.

参考サイト
いっぱいあって,いっぱい参考にした.特に以下の2つを参考にしたけど,ほかにもGoogleでov7670で検索してヒットするサイトは軒並みチェックした.先人に感謝.
トラ技 頒布カメラB(OV7670 FIFO AL422B)の動作確認 | mbed
HR2_blog: mbedでトラ技3月号の頒布カメラBを使う


2014.12.15追記
サンプル画像の元データ(captureData.txt)はこんな感じ.captureData.txt.zip.jpg
So-netのブログはテキストファイルのアップロードができないので,ZIP圧縮して,拡張子に.jpgをつけて無理矢理アップロードしてる.なので,ダウンロードしたら.jpgを消してZIPファイルとして展開してくださいな.

nice!(1)  トラックバック(0) 
共通テーマ:日記・雑感

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。