日々の記録

ほどよく書いてきます。

ニコン一眼レフリモコン

2014年05月18日 01時32分23秒 | AVR

やりたいこと:微速度撮影の制御。ロータリースイッチでシャッター間隔の時間を決める。
機材:ニコンのデジタル一眼レフカメラ(持ってるのはD40,D90)

以前、ニコンの一眼レフリモコンのプログラムを作ったのだが、ブレッドボード上で回路を作っただけで長時間野外で使うにはお粗末なものであった。
また、カメラの電池の容量が稼働時間を制限するため、夜通しの撮影などは無理だった。

で、ヤフオク。Nikonの一眼レフのACアダプタを落札@3800円。決して安くないカメラなので、純正部品にした。最近めっきり出番のないD40を一晩屋外放置などしようと思ったので、D40用のアダプタも落札@1000円。こちらも純正部品。

回路は簡単なもので、さくっと出来上がる。当初は赤外線LEDだけだったが、途中で動いているのか不安になったので、赤色LEDを追加した。リモコンコード送信のときに赤LEDも光るので電池切れで動かないなどがわかる。暗闇の中で使うのを前提にしたので赤色のあまり明るくないLEDを採用。電源はNiMH×4で最大5.2Vほど。5.5Vまでは使っていいみたいなので、ぎりぎりセーフ。電池の過放電が気になるが、無視しよう。一晩程度なら問題ない。

 

まず赤外線のフォーマットだが、キャリア周波数38kHz程度で、Duty 1/3のパルスである。
ニコンのレリーズ信号はこんな漢字らしい。
    turn_on();  _delay_us( 2000);  //2ms発光
    turn_off();  _delay_us(27850);  //27.85ms消灯
    turn_on();  _delay_us(  390);  //0.39ms発光
    turn_off();  _delay_us( 1580);  //1.58m消灯
    turn_on();  _delay_us(  410);  //0.41ms発光
    turn_off();  _delay_us( 3580); //3.58ms消灯
    turn_on();  _delay_us(  400); //0.4ms発光
    turn_off();  _delay_us(63200); //63.2ms消灯
合計99.4msだが、実際は100msだと思う。誰かが測定した結果上記のようになったんだと思う。

では、マイコンのプログラム要素を考える。
38kHz Duty 1/3を8ビットタイマで実現する。出力をピンに接続するかどうかで上記のturn_on()とturn_off()を作ることにする。

マイコンは内臓9.6MHzのDIV8で1.2MHzで動かす(出荷状態どおり)→38kHzの1サイクルは1200/38≒31.5カウントで到達する。カウンタは31までカウントしたらリセットかかるようにして、0カウントでHigh, 10カウントでLowとなるように設定する。DIV8なしで9.6MHz駆動の場合はこれの8倍の値になって、たぶん普通のPWMモード(255カウントでリセットかかる)が使える。
カウンタのトップ値を設定するPWMモードの場合、OCR0Aレジスタで上限決定、OCR0BでDuty決定といったことをやるため、PWM出力がOC0B(PB1)になってしまいます。なので外付けDIPスイッチはPB0,PB2,PB3,PB4という飛び地になってしまいます。

8ビットカウンタの設定

カウンタでは何をするかというと、こんな設定
TCCR0A=0b00000011; //0b00100011と切り替えることでLEDオンオフをやる。


TCCR0B=0b00001001;

CS02-CS00はカウンタへのクロック供給である。1.2MHzをそのまま入れるのでCS02-CS00は001になる。

WGM02-00はレジスタを跨いでいるので注意が必要だが、111の設定(最終行)にする。TOPが0CR0Aになる高速PWMモード。

最後にCOM0Bxの設定だが、非反転の動作を使う。カウンタ0で出力high、カウンタがOCR0Bと一致でlowの出力になる。

ちなみに、このPWMの設定にたどり着くのに一週間以上かかった。

ここまでくれば後は簡単、LEDのON/OFFは関数作るか、そのまま書くかで出来上がり。
void turn_on(void){
      TCCR0A=0b00100011;
}

void turn_off(void){
      TCCR0A=0b00000011;
}


ポートの設定とピン状態の読み込み

PB1を出力にして、ほかを入力端子かつ内部で抵抗プルアップを施す。外に抵抗つけるの面倒くさいじゃない。そして、ロータリースイッチがコンプリメンタリである必要はここからくる。ツマミがオレンジというか朱色のを使うとよい。
DDRB = 0b00000010;
PORTB = 0b00011101;  //入力なのにPORTレジスタに1を書き込むと内部プルアップ!!なるほど!

さて、PB0,PB2,PB3,PB4という4端子を使うのですが、飛び地なので、そのままでは面倒があります。一番右のビットをひとつ左にシフトして全体を右にビットシフトできればいいなー、いいなー、いいなー・・・こういうときは風呂だな。
で、風呂で思いつく。(PINB++)>>1だ!

(0b00011100++)>>1=(0b00011101)>>1=0b00001110
(0b00011101++)>>1=(0b00011110)>>1=0b00001111

きっと世の中じゃ常識なんだろうけど、思い通り程度の計算量で出来上がって便利。

 

ソースコード

/*ハジマリ*/

#define F_CPU 1200000

#include <avr/io.h>
#include <util/delay.h>
#include
#define SignalTime 99

int main(void)
{
    DDRB   = 0b00000010;    // 出力方向にする
    PORTB  = 0b00011101;    //抵抗プルアップ
    TCCR0A = 0b00000011;
    TCCR0B = 0b00001001;
    OCR0A = 31;  // (( 1.2MHz / 38kHz ) / 1(分周) ) - 1 = 30.6
    OCR0B = 10;  // duty比を1/3にする ( 1.2MHz / 38kHz ) / 3 = 10.5

    while(1)
    {
        TCCR0A = 0b00100011;        _delay_us( 2000);     //サブルーチン使わず、コピペでやったれ!
        TCCR0A = 0b00000011;         _delay_us(27850);
        TCCR0A = 0b00100011;         _delay_us(  390);
        TCCR0A = 0b00000011;         _delay_us( 1580);
        TCCR0A = 0b00100011;         _delay_us(  410);
        TCCR0A = 0b00000011;         _delay_us( 3580);
        TCCR0A = 0b00100011;         _delay_us(  400);
        TCCR0A = 0b00000011;         _delay_us(63200);

        uint8_t IntervalStatus  = ((PINB & 0b11101) + 1) >> 1;   //ふっ、おいらC育ちじゃないから++演算子わすれてたよ。

        if(IntervalStatus ==   0)  {_delay_ms(  1000-SignalTime);} //1秒ごとのシャッター
        if(IntervalStatus ==   1)  {_delay_ms(  2000-SignalTime);}
        if(IntervalStatus ==   2)  {_delay_ms(  5000-SignalTime);}
        if(IntervalStatus ==   3)  {_delay_ms( 10000-SignalTime);}
        if(IntervalStatus ==   4)  {_delay_ms( 20000-SignalTime);}
        if(IntervalStatus ==   5)  {_delay_ms( 30000-SignalTime);}
        if(IntervalStatus ==   6)  {_delay_ms( 40000-SignalTime);}  //星の撮影だと露光30sほどやるのでたぶんこの辺をよく使う
        if(IntervalStatus ==   7)  {_delay_ms( 60000-SignalTime);}
        if(IntervalStatus ==   8)  {_delay_ms(120000-SignalTime);}
        if(IntervalStatus ==   9)  {_delay_ms(240000-SignalTime);}
    }
}

/*オワリ*/

待機時間はカウンタが止まっていても問題ないが、一連の信号を送信する間、2ms発光から最後の0.4ms発光まではコヒーレントな38kHzがいいかとおもってタイマはとめていない。もっとも面倒くさくなったので、上記のプログラムではずっとタイマは動いている。タイマとめても大して節電にならない気がするから。

スリープに入って、など節電できる工夫はまだできるが、充電電池使うし、いつ飽きるかわからないので、今回はこれでよし。

そんなブログを書いている間に月は昇った。送電線が邪魔なので、引っ越したいくらい。ACアダプタがないと長時間の露光ができないので事実上部屋のまどから外を撮影、というのが今の限界である。


 

組みあがった回路はこちら。配線がほとんどない。赤外線LEDはデジカメのところまで引っ張っていってる。

撮影の様子

送電線が邪魔だ!これさえなければ!これさえなければ!

 

備忘録

シャッター速度、長いほうから
Bulb, 30s, 25s, 20s, 15s, 10s, 8sというような感じなので、後で比較明コンポジットなどを行いたい場合はこれらの時間よりやや長い程度のものにしておくとよいかも。
35s, 30s, 25s, 20s,というような時間がいいだろうかと。

コメント (3)    この記事についてブログを書く
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする
« ハイサイドP-MOSのゲート充放電 | トップ | 微速度撮影 »

3 コメント

コメント日が  古い順  |   新しい順
おおっ、 (いち)
2014-05-22 15:00:43
完成品に近づきましたね。
すっきりとしたハードでいい感じ。(^^)

タイマーIOを使いましたか。
たかが100円程度のマイコン、されどコンピューター!
ペリフェラルIOを使い込むには結構悩むこともありますね。
趣味のおもちゃとしては、コソトパフォーマンスMAXな遊びじゃないでしょうか。(笑)

月の重ね撮り、面白い画像ですね。
まるで巨大な火球が落ちたようです。

植物の成長をタイムラプスしたら、植物も生物なんだと実感できて面白そうですね。(^^)
返信する
ふふふ (まこち)
2014-05-22 22:38:34
ハードは相当簡単なものになりました。チップ内部で抵抗プルアップしてくれるのでありがたいです。
タイマーIOはほうっておいてもON/OFFしてくれるのでとても便利です。前の太陽電池MPPT回路もタイマーで制御していますよ!

マイコンの趣味はコスパ相当高いです。このチップは秋月で50円なのですが、2日でも3日でも時間がどんどんなくなります^^;
暇なときはいいけど、仕事で忙しいときに、こっちも楽しくなると大変w

星の重ね取りは次に長野に帰ったときに一晩撮影して星がグルっとまわった写真を撮影したいと思ってます。

植物もいいですね。朝顔とか動画にしたら面白そうです。以前朝顔にチャレンジしたときは、屋外の植物は風に吹かれてブレブレのロクなものにならなかったので、屋内の植物限定な感じがしました。

カメラのコントローラを箱に収めたら次は通信に手を出そうかと思ってます。
やっぱり周辺機器との連動大事ですし、いっちーからもらった測定デバイスがこちらをじっと眺めているので・・・(笑
返信する
時間 (いち)
2014-05-30 13:48:30
たいしたことじゃないんですけど、
シャッター時間のスイッチ設定は、
対数間隔のほうが現実的かも?
5、7、10、14、20、28、40
みたいな・・・
返信する

コメントを投稿

AVR」カテゴリの最新記事