当前位置:[北京同好会]>[自己动手]>[DC实验室]>[控制手柄]

 

COOLPIX控制手柄

最近作了一个独立的COOLPIX数码相机控制手柄,可以操作995,5000和4500。


线路非常简单,三个IC,(如果不要LED显示,2片IC就够了),其余都是电阻,电容和LED,总成本几十元钱。


电路原理图(点击放大):


装配好的控制手柄,与原配的MC-EU1控制器相比当然是又大又沉。不过既然满足了操纵要求,又玩了一把单片机,也算是一举两得吧。


操作方法:

1)将USB电缆的9针插头插上后电源接通,LED2闪烁。
2)打开相机电源,进入串行通信模式,LCD关闭。
3)按“1”键连接相机,LCD打开,LED2变为常亮。
4)“5”键为拍摄。按一下“F2"相当于半按快门,LED1闪烁。再按一下“F2"解除半按快门状态,LED1关。或者按“5”拍摄,完毕后LED1关。
5)“*”,“#”键为变焦按键(5000不支持)
6)“7”,“9”键为翻页按键(4500不支持)
7)按“2”断开相机(好像没什么用)

通信过程中可能会出现超时中断的情况,这时LED2开始闪烁。通常可以继续操作,系统将自动恢复正常。如果发现相机不动作、各种按键无效、相机显示出错的情况,可以试着:再按“1”键......(没反应)乱按键盘......(没反应)断开相机侧USB电缆......(没反应)关断相机电源开关......(没反应)拆卸相机电池......(没反应)把相机扔掉......

程序很小,1K左右,单片机程序存储器还有近3/4的空间,I/O口也剩余很多,可以方便地加入其他功能。


以下为用于AT89C51的单片机C51源程序。以及编译好的HEX文件,可直接编程芯片

//COOLPIX控制器程序,用于AT89C51
//2003-8-15

#include <AT89X51.H>

//常量定义
//========================系统50ms时钟
#define RELOAD_HIGH 0x4C
#define RELOAD_LOW 0x0C

//========================按键地址,根据硬件定义键盘
#define KEY1 0x0008
#define KEY2 0x0004
#define KEY3 0x0002
#define KEY4 0x0080
#define KEY5 0x0040
#define KEY6 0x0020
#define KEY7 0x0800
#define KEY8 0x0400
#define KEY9 0x0200
#define KEYFF 0x8000 //FOCUS FORWARD
#define KEY0 0x4000
#define KEYFB 0x2000 //FOCUS BACKWARD
#define KSET 0x0001 //F1
#define KEY2X 0x0010 //F2
#define KTURBO 0x0100 //F3
#define KCAM 0x1000 //F4
#define KESC KCAM

//========================按键组合
#define KEY_CAMERA KEY5|KEY2X|KEYFF|KEYFB|KEY7|KEY9|KESC|KEY1|KEY2


//代码常量定义
//========================按键
unsigned int code num09[16]={KEY0,KEY1,KEY2,KEY3,KEY4,KEY5,KEY6,KEY7,KEY8,KEY9,KEYFF,KEYFB,KEY2X,KTURBO,KESC,KSET};


//全局变量定义
bit flag_keyscan_en; //enable keyscan
bit flag_uart_busy;
bit flag_halfpress;
bit flag_dc_on;

unsigned int nk; //键盘状态,pressed key set that bit

unsigned char uartread,uartwrite;
unsigned char uartbuf[8];
unsigned char ikey; //last key id
unsigned char urvcmd;//uart接收到的控制指令

signed char rvdata;


//---------------------------------------------------
//键盘处理

/***************************************************
void wait_for_input(unsigned int)
function:wait for input from specified key groups
****************************************************/
void wait_for_input(unsigned int imask){
J1:while (flag_keyscan_en) { //wait for input
;
}
if (!(nk&imask)) { //no allowed key
flag_keyscan_en=1;
goto J1;
}
ikey=0;
while (!(nk&num09[ikey])){
ikey++;
}
}

/**************************************************
void wait_for_release(void)
function:delay and wait for release of specified key
**************************************************/
void wait_for_release(void){
unsigned char delay=5;
flag_keyscan_en=1;
while (--delay){
while (flag_keyscan_en) {
;
}
flag_keyscan_en=1;
}

do {
flag_keyscan_en=1;
}
while (!((~nk)&num09[ikey])); //wait for button release
}

//相机控制
//控制指令协议
unsigned char code camcmd[24][4]={
{0x1B, 0x53, 0x06,0x00},
{0x00, 0x11, 0x02,0x00},
{0x00, 0x00, 0x13,0x00}, //Standard SetSpeed to 19200 command packet
{0x1B, 0x53, 0x06,0x00},
{0x00, 0x11, 0x02,0x00},
{0x00, 0x10, 0x23,0x00}, //Go to MC-EU1 protocol packet, switch LCD ON
{0x9B, 0x85, 0x1C,0x1C}, //6 Initialisations
{0x9B, 0x13, 0x1C,0x1C}, //response
{0x9B, 0x08, 0x1C,0x1C}, //8 Has camera power down ?
{0x9B, 0x01, 0x1C,0x1C}, //9 Half press the shutter button.
{0x9B, 0x01, 0x7F,0x1C}, //10 Full press the shutter button,
{0x9B, 0x01, 0x7F,0x7F}, //11 Release the shutter button,
{0x9B, 0x01, 0x1C,0x7F}, //12 Half press release (unlock shutter button).
{0x9B, 0x02, 0x1C,0x1C}, //13 "Press" the zoom in button
{0x9B, 0x02, 0x1C,0x7F}, //"Release" the zoom in button
{0x9B, 0x02, 0x7F,0x1C}, //15 "Press" the zoom out button
{0x9B, 0x02, 0x7F,0x7F}, //"Release" the zoom out button
{0x9B, 0x04, 0x1C,0x1C}, //17 "Press" right,next
{0x9B, 0x04, 0x1C,0x7F}, //"Release" right
{0x9B, 0x04, 0x7F,0x1C}, //19 "Press" left ,previous
{0x9B, 0x04, 0x7F,0x7F}, //"Release" left
{0x9B, 0x07, 0x1C,0x1C}, //21 Number of picture left
{0x9B, 0x89, 0x1C,0x1C}, //22 A/M/P mode
{0x9B, 0x8A, 0x1C,0x1C}}; //23Go back to standard protocol LCD OFF},

/***************************************************
void wait_for_camera(unsigned char)
function: camera operation

****************************************************/
void wait_for_camera(unsigned char cc){
unsigned char delay=125;

flag_keyscan_en=1;
while (--delay){
while (flag_keyscan_en) {
if(uartread!=uartwrite){//有新数据
if(++uartread>7) uartread=0;
if(cc==uartbuf[uartread]){
flag_dc_on=1;
return;
}
}
}
flag_keyscan_en=1;
}
flag_dc_on=0;
return;
}


/***************************************************
void sendcmd_to_camera(unsigned char)
function: camera operation
****************************************************/
sendcmd_to_camera(unsigned char cc){ //发送4字节命令
unsigned char i;

for(i=0;i<4;i++) {
while(flag_uart_busy){
;
}
flag_uart_busy=1;
SBUF=camcmd[cc][i];
}
}


/***************************************************
void camera(void)
function: camera operation
input: none
return: none
****************************************************/
void camera(void){


while(1){
wait_for_input(KEY_CAMERA);
switch (ikey){
case 1:{ //连接
while(flag_uart_busy){
;
}
SBUF=0x00;
wait_for_camera(0xFF);
while(flag_uart_busy){
;
}
SBUF=0x00;
wait_for_camera(0x15);
sendcmd_to_camera(0);
sendcmd_to_camera(1);
sendcmd_to_camera(2);
wait_for_camera(0x06);
sendcmd_to_camera(3);
sendcmd_to_camera(4);
sendcmd_to_camera(5);
wait_for_camera(0x06);
flag_halfpress=0;

break;
}
case 2:{//断开
while(flag_uart_busy){
;
}
sendcmd_to_camera(23);
return;
}
case 5:{ //快门
if(!flag_halfpress){
sendcmd_to_camera(9);
wait_for_camera(0x86);
}

sendcmd_to_camera(10);
wait_for_camera(0x86);

ikey=5; //KEY5
wait_for_release();

sendcmd_to_camera(11);
wait_for_camera(0x8F);

sendcmd_to_camera(12);
wait_for_camera(0x86);
flag_halfpress=0;
break;
}
case 12:{//半按
if(flag_halfpress){ //半按下状态,释放
sendcmd_to_camera(12);
wait_for_camera(0x86);
}
else{//未按下状态,半按
sendcmd_to_camera(9);
wait_for_camera(0x86);
}
flag_halfpress=!flag_halfpress;
ikey=12; //KEY2X
wait_for_release();
break;
}
case 10:{ //广角
sendcmd_to_camera(15);
wait_for_camera(0x86);

sendcmd_to_camera(16);
wait_for_camera(0x86);
break;
}
case 11:{ //长焦
sendcmd_to_camera(13);
wait_for_camera(0x86);

sendcmd_to_camera(14);
wait_for_camera(0x86);
break;
}
case 7:{ //left, previous
sendcmd_to_camera(19);
wait_for_camera(0x86);

sendcmd_to_camera(20);
wait_for_camera(0x86);
break;
}
case 9:{ //right, next
sendcmd_to_camera(17);
wait_for_camera(0x86);

sendcmd_to_camera(18);
wait_for_camera(0x86);
break;
}
case 14://default: //退出
//return;
return;
break;
};//end of switch
}//end of while(1)


}

//主程序

void main (void){

//延时
{unsigned int i;
for(i=0;i<20000;i++){ //delay
;
}
for(i=0;i<60000;i++){ //delay
;
}
}
//初始化设置
//timer0 configuration
TMOD|=0x01; //Timer0: 16-bit timer;
TH0=RELOAD_HIGH; //设定重装值
TL0=RELOAD_LOW;

//UART configuration
SCON = 0x50; // SCON: mode 1, 8-bit UART, enable rcvr
TMOD |= 0x20; // TMOD: timer 1, mode 2, 8-bit reload
PCON|=0x80;// SMOD=1; ??2?
TL1=0xFD; //19200 baud rate
TH1=0xFD; //19200 baud rate reload
TXD=1;
RXD=1;

//interrupt configuration
EA=1;
ET0=1; //TIMER 0 enabled
ET1=0; //TIMER 1 disabled
ES=1; //UART enabled

//interrupt priority
PT0=1; //T0 high

//开始定时
TR0=1;
TR1=1;

//启动键盘扫描
flag_keyscan_en=1;

uartread=0;
uartwrite=0;

flag_dc_on=0;
flag_halfpress=0;

while (1) {

camera();

} //end of while(1)

}


//中断处理程序

//-----keyscan
sbit SCAN1=P2^4;
sbit SCAN2=P2^5;
sbit SCAN3=P2^6;
sbit SCAN4=P2^7;

sbit LED1=P3^2;
sbit LED2=P3^3;


/***************************************************
timer0
function:timer 0 interrupt;system tick;if flag_keyscan_en,keyboard scan
****************************************************/
void timer0(void) interrupt 1 using 1{
static unsigned char second_cnt=10; //second count
static bit status_led1=1,status_led2=1;
//Timer Reload
TR0=0; // stop T0
TH0=RELOAD_HIGH; //设定重装值
TL0=RELOAD_LOW;
TR0=1; //开始定时

//Clock Maintenance
if(!(--second_cnt)){ //如果经过1/2秒
second_cnt=10; //设置计数值

if(flag_halfpress){
status_led1=!status_led1;
LED1=status_led1;
}
else{
LED1=1;
}

if(flag_dc_on){
LED2=0;
}
else{
status_led2=!status_led2;
LED2=status_led2;
}

}

//keyboard scan
if (flag_keyscan_en) {
unsigned char temp;
nk=0;
P2|=0x0F; // all high
SCAN1=0;
temp=P2&0x0F;
nk=temp;

SCAN1=1;
SCAN2=0;
temp=P2&0x0F;
nk=nk*16+temp;

SCAN2=1;
SCAN3=0;
temp=P2&0x0F;
nk=nk*16+temp;

SCAN3=1;
SCAN4=0;
temp=P2&0x0F;
nk=nk*16+temp;
SCAN4=1;

nk=~nk; //key pressed=bit set to 1
flag_keyscan_en=0;
};

}


/***************************************************
uart interrupt
****************************************************/

void uart(void) interrupt 4 using 2{

if( TI){
TI=0;
}
if (RI){
if(++uartwrite>7) uartwrite=0;
uartbuf[uartwrite]=SBUF;
RI=0;
}
flag_uart_busy=0;
}