やりたいこと:微速度撮影の制御。ロータリースイッチでシャッター間隔の時間を決める。
機材:ニコンのデジタル一眼レフカメラ(持ってるのは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,というような時間がいいだろうかと。