ロータリーエンコーダーで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); 
}

 

コメントはありません
コメントをどうぞ

*