打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
佳能 EF 镜头 SPI控制
userphoto

2023.05.30 内蒙古

关注
使用廉价的MCU,搭配SPI协议驱动你的佳能摄像头。

逆向Canon EF卡口镜头,这个是昨天的文章。

ASCOM EF Lens Controller – control unit for Canon EF/EF-S lenses. It allows you to control lens using the ASCOM platform tools.

Features (supported by driver):
 focus control;
 aperture value control;
 temperature measure (additional sensor required, e.g. popular
DS18B20).

This device uses SPI interface. Description of lens commands were taken from published articles about reverse engineered internal Canon protocol.

Connection to lens is easy. It is only necessary to know pinout of itscontacts. This information is available on the Web. Just «google» canon efpinout. I recommend to use a scheme, shown below.

This picture describes electric pins on lens or special macro-adapter which issuitable for soldering wires. You can buy adapters in any photo shop or onweb stores such as EBay. It looks something like this.

Next component – microcontroller, which support SPI interface. It may beATmega, STM32, PIC or board, based on its controllers. Factory PCB has allrequired components and will be easy for beginners while simplemicrocontroller allows you to make own custom device.

I used Arduino Nano based on ATmega328P controller. Its performance isenough for our purpose. Small size and low cost - its advantage.

Pinout diagram above shows the designations of Arduino Nano contacts. Sowe need:

Note: only huge lenses may require external power supply. I tested mylenses (EF-S 18-55, EF 50/1.8, EF200/2.8L) and measured their currentconsumption. It was less than 200 mA. It means that these lenses can bepowered directly from 5V Arduino pin. Entire system will be powered fromUSB, and there is no need for additional wires.

You can experiment on the breadboard but for the final design it is better touse a more respectable solution.

I want to point out one feature associated with Arduino. Now, these boardsuse the Automatic (Software) Reset, which is convenient for firmware uploadbut do not really need us. The fact is that:

One of the hardware flow control lines (DTR) of the FT232RL is connected to thereset line of the ATmega168 or ATmega328 via a 100 nanofarad capacitor. Whenthis line is asserted (taken low), the reset line drops long enough to reset the chip.

This means that each connection («Connect» button in MaximDL orFocusMax) to the device will cause it to reboot. Result is 3-5 sec delay. Ifyou are not satisfied, simplest solution is to unsolder DTR pin to preventtransfer of reboot signal. I used «ChinaDuino», it has CH340G as UART chip.Original Arduino uses FT232RL.

These schemes allow you to easily find the DTR pin. After making thesechanges, device connects immediately.

Software

Software consists of two main parts:

Arduino sketch (firmware) is responsible for interaction with lens;
ASCOM device driver.

Unit relations shown in the figure below:

The red highlighted functionality implemented in addition to the mainfunctions realized in driver pattern. Focuser driver has no iris controlfunctions by default. But aperture value control is important feature.

代码使用我就不写了,后面我会上代码:

Use P# to get current focus position (5000 by default)
Use Mxxxx# to move focus, e.g. M5270#
Use Axx# to change aperture value, where xx – count of steps (1/3
EV). 0 – wide open on your lens.

下载这个控制软件,有一种年老失修的美

ASCOM

Click «Properties», you can see driver setup dialog. Set requiredparameters:

COM Port Number – controller connection port;

Lens Model – choose your lens from drop-down list. In fact youcan use any lens. Just add it to lens.txt which is in driverinstallation folder and insert all aperture values of lens;

Aperture Value – select required aperture value. Changes will besaved in EEPROM of Arduino chip.

After all changes are saved, you can connect to the controller.

Temperature will be displayed only if you connect a sensor. I usedanalog KTS-1 sensor. GET TEMPERATURE section in my sketch work with this sensor. You can use any other. Do not forget to correct your sketch. If you do not need to measure temperature just comment this strings.

#include <SPI.h>#include <EEPROM.h>
#include <Adafruit_GFX.h>#include <Adafruit_SSD1306.h>#include <Wire.h>#define SCREEN_WIDTH 128#define SCREEN_HEIGHT 64#define OLED_RESET -1Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define LED_SW 7#define CS 10 // Emurate CS of SPI for DEBUG#define F1 9 // Function SW#define ENC_A 2#define ENC_B 3#define LED_Red 14#define LED_Green 15
volatile byte pos;volatile int enc_count;boolean sw = false;boolean real_mode = false;
int mode = 0;int mode_counter[2];int focuserPosition, apValue, offset, apAddr, fpAddr, fpValue, x, y;boolean IsFirstConnect;
void InitLens(){ SPI.transfer(0x0A); delay(30); SPI.transfer(0x00); delay(30); SPI.transfer(0x0A); delay(30); SPI.transfer(0x00); delay(30);}
int ENC_COUNT(int incoming){ static int enc_old = enc_count; int val_change = enc_count - enc_old;
if (val_change != 0) { incoming += val_change; enc_old = enc_count; } return incoming;}
void ENC_READ(){ byte cur = (!digitalRead(ENC_B) << 1) + !digitalRead(ENC_A); byte old = pos & B00000011; byte dir = (pos & B00110000) >> 4;
if (cur == 3) cur = 2; else if (cur == 2) cur = 3;
if (cur != old) { if (dir == 0) { if (cur == 1 || cur == 3) dir = cur; } else { if (cur == 0) { if (dir == 1 && old == 3) enc_count++; else if (dir == 3 && old == 1) enc_count--; dir = 0; } } pos = (dir << 4) + (old << 2) + cur; }}
void setup(){ digitalWrite(13, LOW); // SPI Clock PIN pinMode(ENC_A, INPUT_PULLUP); pinMode(ENC_B, INPUT_PULLUP); pinMode(LED_Red, OUTPUT); pinMode(LED_Green, OUTPUT); pinMode(LED_SW, INPUT_PULLUP); pinMode(CS, OUTPUT); pinMode(F1, INPUT_PULLUP);
attachInterrupt(0, ENC_READ, CHANGE); attachInterrupt(1, ENC_READ, CHANGE);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); display.clearDisplay();
// Font size display.setTextSize(3); // Font color display.setTextColor(WHITE); display.setCursor(0, 10); display.println("EF-LensFocuser"); display.display(); delay(1000); mode = 0; // focus control mode apAddr = 0; // 1 byte memory for aperture value fpAddr = 1; // 2 byte memory for focus position focuserPosition = 5000; SPI.begin(); SPI.setBitOrder(MSBFIRST); SPI.setClockDivider(SPI_CLOCK_DIV128); SPI.setDataMode(SPI_MODE3); digitalWrite(12, HIGH); digitalWrite(LED_Red, HIGH); digitalWrite(LED_Green, LOW); InitLens(); SPI.transfer(0x05); // Focus Max delay(1000); apValue = EEPROM.read(apAddr); fpValue = EEPROM.read(fpAddr) * 256 + EEPROM.read(fpAddr + 1); // focus position offset = fpValue - focuserPosition; proc_lens(offset); // Move focus tot last position
Serial.begin(9600); Serial.print("FP:"); Serial.println(fpValue); Serial.print("AP:"); Serial.println(apValue); display.clearDisplay(); display.setCursor(0, 10); display.print("F:"); display.println(fpValue); display.print("A:"); display.println(apValue); display.display(); delay(1000);}
void loop(){ int sw_count; int tmp, last_offset; short counter_now; digitalWrite(CS, HIGH); sw_count = 0; while (digitalRead(LED_SW) == LOW) { sw_count++; if (sw_count > 50) { if (mode == 1) { // forcus control mode digitalWrite(LED_Red, HIGH); digitalWrite(LED_Green, LOW); } else { // aperture control mode digitalWrite(LED_Green, HIGH); digitalWrite(LED_Red, LOW); } } if (sw_count > 200) { digitalWrite(LED_Green, HIGH); digitalWrite(LED_Red, HIGH); } delay(10); } delay(100); if (sw_count > 50 && sw_count < 200) { mode == 0 ? mode = 1 : mode = 0; } if (mode == 1) { digitalWrite(LED_Green, HIGH); digitalWrite(LED_Red, LOW); } else { digitalWrite(LED_Red, HIGH); digitalWrite(LED_Green, LOW); } /* if (sw_count != 0) { Serial.print("mode: "); Serial.print(mode); Serial.print(", real: "); Serial.println(real_mode); } */ if (sw_count > 200) { real_mode = !real_mode; if (real_mode) { Serial.print("mode: "); Serial.println(mode); last_offset = mode_counter[mode]; } else { mode_counter[mode] = last_offset; } } if (sw_count != 0 && (sw_count < 50)) { proc_lens(tmp); }
counter_now = ENC_COUNT(mode_counter[mode]); tmp = counter_now - mode_counter[mode]; // encoder counter state if (mode_counter[mode] != counter_now) { tmp > 0 ? 1 : -1; if (real_mode) { mode_counter[mode] += tmp; proc_lens(tmp); } else { mode_counter[mode] = counter_now; } } if (sw_count != 0 || tmp != 0) disp_update(tmp, last_offset);}
void proc_lens(int tmp){ int ap; digitalWrite(CS, LOW); if (mode == 0) { // Send command to LENS フォーカス if (real_mode) { offset = tmp; } else { offset = mode_counter[mode]; } x = highByte(focuserPosition); y = lowByte(focuserPosition); EEPROM.write(fpAddr, x); // write to EEPROM last focus position EEPROM.write(fpAddr + 1, y); x = highByte(offset); y = lowByte(offset); Serial.print("FP:"); Serial.print(offset); Serial.print(", "); Serial.println(focuserPosition); InitLens(); SPI.transfer(0x44); delay(30); SPI.transfer(x); delay(30); SPI.transfer(y); delay(30); SPI.transfer(0); delay(100); focuserPosition += offset; } else { // 絞り apValue = mode_counter[mode]; ap = (apValue - EEPROM.read(apAddr)) * 3; Serial.print("APvalue:"); Serial.print(apValue); Serial.print(",SET ap:"); Serial.println(ap); if (apValue != EEPROM.read(apAddr)) { InitLens(); SPI.transfer(0x07); delay(10); SPI.transfer(0x13); delay(10); SPI.transfer((apValue - EEPROM.read(apAddr)) * 3); delay(100); SPI.transfer(0x08); delay(10); SPI.transfer(0x00); delay(10); EEPROM.write(apAddr, apValue); } }}
void disp_update(int tmp, int last_offset){ char sep; display.clearDisplay(); display.setCursor(0, 10); if (real_mode) { // Update when encoder rotated sep = '>'; switch (mode) { case 0: (tmp > 0) ? sep = '>' : sep = '<'; display.print("F"); display.print(sep); display.println(last_offset); display.print("P"); display.print(sep); display.println(focuserPosition); break; case 1: display.print("F"); display.print(sep); display.println(focuserPosition); display.print("A"); display.print(sep); display.println(mode_counter[mode]); break; } } else { // Update when switch pushed sep = ':'; switch (mode) { case 0: display.print("F"); display.print(sep); display.println(mode_counter[mode]); display.print("P"); display.print(sep); display.println(focuserPosition); break; case 1: display.print("F"); display.print(sep); display.println(focuserPosition); display.print("A"); display.print(sep); display.println(mode_counter[mode]); break; } } display.display();}
https://astromechanics.org/downloads/ascom_ef/en/manual/User%20Manual%20ASCOM.pdf
以上是代码,颜色好像有问题
https://github.com/crescentvenus/EF-Lens-CONTROL/blob/master/EF-Lens-control.ino
https://ascom-standards.org/Downloads/FocuserDrivers.htm
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
PS2手柄遥控Arduino小车
Arduino 语法
如何仅花20元成本用arduino平台建立自己的物联网应用
Arduino ESP8266自动配网并上传温湿度、光照强度到OneNET
用android控制arduino(wifi版)
Arduino基础
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服