ロータリーエンコーダーでLANCリモコンを作る
ビデオカメラのズーム機能のインターフェースって、シーソー式だったり右左に倒すものだったりが主流ですが、昔からあのスイッチに不満があるんですよ。なんというか、狙ったところに止まらないというか直感的じゃないんですよね。業務用のカメラだとレンズを直接回すので、回した分だけズームできるというか、直感的なんです。そんな業務用のカメラを買う金もないので、SONYの家庭用ビデオカメラのLANC端子で、回した分だけズームできるリモコンを作りたいと思います。
ハードウェア
ここで大事になるのが、回した事を感知する入力装置ですが、今回はロータリーエンコーダーを使いました。入力感を決める大事なデバイスになりますので、RSコンポーネンツのロータリーエンコーダーサイトから探しました。
ダイヤルも忘れずに買っておきます。
前回作った基板に接続し、プログラムを改良します。割り込みピンである2・3ピンにロータリーエンコーダーの出力を付けました。
プログラム
ロータリーエンコーダーの入力を、割り込みで受け取りこぼしを防ぎます。ピンの状態が変わった時に割り込みがかかりその時のエンコーダーの値を読み取り、前回の差分を取ります。その差分がどれだけあるかを判断し、多く回転した場合は、ズームのスピードを上げるLANC信号を出します。
#include <MsTimer2.h> #define cmdPin 7 #define lancPin 11 #define recButton 6 #define zoomOutButton 5 #define zoomInButton 4 #define focusNearButton 9 #define focusFarButton 10 #define encoderPinA 2 #define encoderPinB 3 int cmdRepeatCount; int bitDuration = 104; //Duration of one LANC bit in microseconds. //RECコマンド byte REC[] = {0x18 ,0x3A}; byte STOP[] = {0x18 ,0x30}; byte RECSTARTSTOP[] = {0x18 ,0x33}; byte PAUSE[] = {0x18 ,0x32}; byte STILL[] = {0x18 ,0x2B}; //Zoom in from slowest to fastest speed byte ZOOM_IN_0[] = {0x28 ,0x00}; byte ZOOM_IN_1[] = {0x28 ,0x02}; byte ZOOM_IN_2[] = {0x28 ,0x04}; byte ZOOM_IN_3[] = {0x28 ,0x06}; byte ZOOM_IN_4[] = {0x28 ,0x08}; byte ZOOM_IN_5[] = {0x28 ,0x0A}; byte ZOOM_IN_6[] = {0x28 ,0x0C}; byte ZOOM_IN_7[] = {0x28 ,0x0E}; //Zoom out from slowest to fastest speed byte ZOOM_OUT_0[] = {0x28 ,0x10}; byte ZOOM_OUT_1[] = {0x28 ,0x12}; byte ZOOM_OUT_2[] = {0x28 ,0x14}; byte ZOOM_OUT_3[] = {0x28 ,0x16}; byte ZOOM_OUT_4[] = {0x28 ,0x18}; byte ZOOM_OUT_5[] = {0x28 ,0x1A}; byte ZOOM_OUT_6[] = {0x28 ,0x1C}; byte ZOOM_OUT_7[] = {0x28 ,0x1E}; volatile int encoder_value = 0; volatile uint8_t encoder_prev = 0; int encoder_ValueBefore = 0; int encoder_ValueDiff = 0; int encoder_Between = 0; void putOrder(){ encoder_ValueDiff = encoder_ValueBefore - encoder_value; encoder_ValueBefore = encoder_value; } void setup() { pinMode(lancPin, INPUT); //listens to the LANC line pinMode(cmdPin, OUTPUT); //writes to the LANC line pinMode(recButton, INPUT_PULLUP); pinMode(zoomOutButton, INPUT_PULLUP); pinMode(zoomInButton, INPUT_PULLUP); pinMode(focusNearButton, INPUT_PULLUP); pinMode(focusFarButton, INPUT_PULLUP); digitalWrite(cmdPin, LOW); //set LANC line to +5V delay(5000); //Wait for camera to power up completly bitDuration = bitDuration - 8; //ロータリーエンコーダーを割り込みとして処理 pinMode(encoderPinA, INPUT); pinMode(encoderPinB, INPUT); attachInterrupt(0, updateEncoder, CHANGE); attachInterrupt(1, updateEncoder, CHANGE); MsTimer2::set(500, putOrder); // 500msごとにオンオフ MsTimer2::start(); Serial.begin(9600); Serial.println("start"); } void loop() { //ロータリーエンコーダー回転検知部 if(encoder_Between > 3){ putOrder(); encoder_Between = 0; } encoder_Between++; int aaa = ceil(encoder_ValueDiff / 1); if(aaa > 9){ aaa = 8; } if(aaa < -9){ aaa = -8; } switch (aaa) { case -1: lancCommand(ZOOM_IN_0); break; case -2: lancCommand(ZOOM_IN_1); break; case -3: lancCommand(ZOOM_IN_2); break; case -4: lancCommand(ZOOM_IN_3); break; case -5: lancCommand(ZOOM_IN_4); break; case -6: lancCommand(ZOOM_IN_5); break; case -7: lancCommand(ZOOM_IN_6); break; case -8: lancCommand(ZOOM_IN_7); break; case 1: lancCommand(ZOOM_OUT_0); break; case 2: lancCommand(ZOOM_OUT_1); break; case 3: lancCommand(ZOOM_OUT_2); break; case 4: lancCommand(ZOOM_OUT_3); break; case 5: lancCommand(ZOOM_OUT_4); break; case 6: lancCommand(ZOOM_OUT_5); break; case 7: lancCommand(ZOOM_OUT_6); break; case 8: lancCommand(ZOOM_OUT_7); break; } //ボタン if (!digitalRead(recButton)) { lancCommand(REC); } if (!digitalRead(zoomOutButton)) { lancCommand(STOP); } if (!digitalRead(zoomInButton)) { lancCommand(RECSTARTSTOP); } if (!digitalRead(focusNearButton)){ lancCommand( PAUSE ); } if (!digitalRead(focusFarButton)){ lancCommand( STILL ); } } void updateEncoder() { uint8_t a = digitalRead(2); uint8_t b = digitalRead(3); uint8_t ab = (a << 1) | b; uint8_t encoded = (encoder_prev << 2) | ab; if(encoded == 0b1101 || encoded == 0b0100 || encoded == 0b0010 || encoded == 0b1011){ encoder_value ++; } else if(encoded == 0b1110 || encoded == 0b0111 || encoded == 0b0001 || encoded == 0b1000) { encoder_value --; } encoder_prev = ab; } void lancCommand(byte lanc[]){ byte tmp = 0; while (pulseIn(lancPin, HIGH) < 5000){} delayMicroseconds(bitDuration); tmp = lanc[0]; for (int i=0; i<8; i++) { if((tmp & 1) == 1){ digitalWrite(cmdPin, HIGH); }else{ digitalWrite(cmdPin, LOW); } tmp = tmp >> 1; delayMicroseconds(bitDuration); } digitalWrite(cmdPin, LOW); delayMicroseconds(10); while (digitalRead(lancPin)) {} delayMicroseconds(bitDuration); tmp = lanc[1]; for (int i=0; i<8; i++) { if((tmp & 1) == 1){ digitalWrite(cmdPin, HIGH); }else{ digitalWrite(cmdPin, LOW); } tmp = tmp >> 1; delayMicroseconds(bitDuration); } digitalWrite(cmdPin, LOW); }
コメントはありません