Zum Inhalt springen

Empfohlene Beiträge

Geschrieben

Stümmt. Nicht aufgepasst. :)

War im Grunde Einstiegsübung in KiCAD. Eagle hat mich zunehmend genervt. Montag werden Platinen in China bestellt, auf dem Breadboard läuft schon fast alles. :)

 

Kurze Umfrage, was wäre praktischer: eine Logik die mit jeder beliebigen IR-Fernbedienung funktioniert (und dann halt nur Start/Stop kann), oder eine mit dedizierter Mini-FB, die dann auch Einzelbild und Intervalometer kann, aber u.U. eben im passenden Moment zuhause liegt? 

Geschrieben
vor 15 Minuten schrieb F. Wachsmuth:

Kurze Umfrage, was wäre praktischer: eine Logik die mit jeder beliebigen IR-Fernbedienung funktioniert (und dann halt nur Start/Stop kann), oder eine mit dedizierter Mini-FB, die dann auch Einzelbild und Intervalometer kann, aber u.U. eben im passenden Moment zuhause liegt? 

Geht nicht beides? Alle Codes außer die der Spezialfernbedienung führen zu Start/Stop. Bei ihr wird zwischen den verschiedenen Codes unterschieden.

Geschrieben

Genau, eine Fernbedienung für Nikon R10/R8, denen ja leider ein einfacher Taster am Kabel nicht reicht. Neben Spezialstecker brauchen die vier im exakt richtigen Timing schließende Kontakte. Das übernimmt dieses kleine Platinchen, das zusammengebaut quasi zum Stecker wird. Und sich dann eben auch noch fernbedienen lässt. Stromversorgung kommt aus der Kamera. :)

Geschrieben (bearbeitet)

So, langsam bin ich fertig. Die Platinen sind nach zig Änderungen jetzt final und in China bereits bestellt. So sehen sie aus:

 

5a345b3a5ae4f_2017-12-16at00_30.thumb.png.6dd5cec90113e54ffc0df11ee8aa15c0.png

 

Das ganze ist allerdings nur 25x35mm klein. Die goldenen Flügel werden durch die sechs Schlitze gesteckt und ergeben festgelötet dann exakt den proprietären Nikon-Stecker. So sitzt das Platinchen einfach unter der Kamera, stört nicht, braucht keine Kabel und keinen extra Strom.

Ich glaub, das wird ne feine Sache. 

Bearbeitet von F. Wachsmuth (Änderungen anzeigen)
Geschrieben (bearbeitet)
/* ATtiny85 IR Remote Control Receiver

This code simulates the Nikon EA-1 Remote Control Switch and adds extra functions, 
like IR-Remote control support and a nifty intervalometer with 416 different intervals
ranging from 200ms to more than 37 hours.
The power needed for the circuit is harvested from the camera (the camera connector has no actual power output).

Some documentation on the hardware below:

Pin numbering, looking onto the camera side jack (or PCB Front)

    3 Green - - Brown   4  
    2 Red   - - Yellow  5 
      space     space 
    1 Blue  - - White   6

Inside the handpiece of the remote control:
Sliders move from 0 to 1 for lightmeter and from 1 to 2 for exposure.

  |-------|      |---------|       |------|  2 expose 
  |       |                        |      | 
  |-------|------|         |       |------|  1 lightmeter on 

  |       |      |         |       |      |  0 no connect 
Brown    Blue   Red      Green  Yellow   White 
  4       1      2         3       5      6

  \ Hold /\ Load /\ Start /         \Light/                    

The "Load" phase charges a capacitor to ease sudden startup and assure even exposure timing. 
The entire start mechanism of the Nikon R8/R10 is rather sophisticated and barely documented.
We need four relays here to follow the protocol. Not following the protocol can work, but might 
damage the camera... who want's that?

*/
#include <util/delay.h> // built-in delay() runs too fast due to timer0 usage in IR receiver ISR

/* Apple Remote (all models) 87 EE */
// see https://en.wikipedia.org/wiki/Apple_Remote


// *** defines and variables ***************************

#define RC_CODE           0x87EE // Apple
#define UP_KEY            0x05  // Up
#define DOWN_KEY          0x06  // Down
#define LEFT_KEY          0x04  // Left
#define RIGHT_KEY         0x03  // Right
#define MENU_KEY          0x01  // Menu
#define ALU_CENTER_KEY    0x2E  // Center (Alu RC)
#define ALU_PLAY_KEY      0x2F  // Play (Alu RC)
#define WHITE_PLAY_KEY    0x02  // Play (old white Apple Remote)

#define LM_MODE_1ST_SINGLESHOT  1   // On the first single exposure shot, we start with lightmetering. 
#define LM_MODE_SUB_SINGLESHOT  2   // Subsequent shots do not meter the light again.

// These are our four relays
int lightmeterPin = 3;  // K4 ye + wh : Lightmeter
int startPin = 4;       // K3 re + gr : Start
int loadPin = 1;        // K2 bl + re : Load
int holdPin = 0;        // K1 br + bl : Hold

int ledPin = 1;         // LED is parallel to load-relay

volatile int irBits;   // This counts the incoming bits from NEC-encoded IR transmitters in the ISR
volatile unsigned long receivedData;  // This contains the received code

// These are used to maintain the different intervals 
byte oldIntervalStep = 31;  // This is the initial OCR1C value (at 1 MHz / Prescaler 16384 = 524ms)
byte newIntervalStep = 31;  // store it here after a change, since we only update OCR1C in the ISR
int postscaler = 2;         // the postscaler doubles the timer1 by POT factors up to 2^16 (39:04:20)
volatile int divider = 0;   // needed in ISR to do some modulo for intervals > 4.3 sec

byte lmMode = LM_MODE_1ST_SINGLESHOT;
bool blinkFlag = true;       // Thisone is used to confirm reception fo valid IR codes
bool aluRemote = false;     // Apple's Alumium Remote has one more key than the white one. Reading
                            // that key is ambigious, so we "lock in" to a safe mode once we know for sure
                            // that our RC is not the white one.


// *** Setup **********************************************
void setup() {
  pinMode(lightmeterPin, OUTPUT);     
  pinMode(holdPin, OUTPUT);     
  pinMode(loadPin, OUTPUT);     
  pinMode(startPin, OUTPUT);     

  noInterrupts();
  
  // Set up timeStampr/Counter0 (assumes 1MHz clock)
  TCCR0A = 0;                 // No compare matches
  TCCR0B = 3<<CS00;           // Prescaler 64
  
  // Set up INT0 interrupt on PB2
  MCUCR = MCUCR | 2<<ISC00;   // Interrupt on falling edge
  GIMSK = GIMSK | 1<<INT0;    // Enable INT0
  irBits = 32;                // Wait for NEC-IR AGC start pulse

  // Set up timeStampr/Counter1 (assumes 1MHz clock speed, saving some power)
  TCNT1 = 0;
  TCCR1 = 0;
  OCR1C = oldIntervalStep;    
  OCR1A = OCR1C;              // interrupt COMPA
  TCCR1 |= (1 << CTC1);       // CTC
  TCCR1 |= (1 << CS13) | (1 << CS12) | (1 << CS11) | (1 << CS10);   // Prescaler 2^14 = 16384
 
  interrupts();
}


void ReceivedCode(boolean Repeat) {
  // Check if Transmitter is not an Apple Remote
  if ((receivedData & 0xFFFF) != RC_CODE) {
    if (!Repeat) blinkLED();
    int key = receivedData>>16 & 0xFF; // extracting the command byte, full 8 bits  
    // We could actually learn some arbitrary codes here and keep them in the EEPROM. Wouldn't
    // be a very interactive experience though, so skipping that part until someone asks for it.
    if ((key != 0xFF) && !Repeat && !digitalRead(lightmeterPin))      startRunWithMetering();
    else if ((key != 0xFF) && !Repeat && digitalRead(lightmeterPin))  stopRun();

  } else { // This is comfort mode with the Apple Remote. :)
    int key = receivedData>>17 & 0x7F; // extracting the command byte, ignoring the 1-bit to match all Apple Remotes

    // If we receive codes unique to an alu RC, let's remember that to fight ambiguity
    if (((key == ALU_CENTER_KEY) && !Repeat) || ((key == ALU_PLAY_KEY) && !Repeat)) aluRemote = true;
    
    // Now let's determine what to do
    if ((key == ALU_PLAY_KEY) && !Repeat && !digitalRead(lightmeterPin))      startRunWithMetering();
    else if ((key == ALU_PLAY_KEY) && !Repeat && digitalRead(lightmeterPin))  stopRun();
    else if ((key == ALU_CENTER_KEY) && !Repeat) {
      if (lmMode == LM_MODE_1ST_SINGLESHOT) meterOnce();
      singleFrame();
    } else if ((key == MENU_KEY) && !Repeat) { //MENU_KEY
      if (TIMSK & ( 1 << OCIE1A )) TIMSK &= ~(1 << OCIE1A);  // enable timer interrupt
      else                         TIMSK |= (1 << OCIE1A);   // disable timer interrupt
    } else if ((key == DOWN_KEY) && !Repeat) {
      oldIntervalStep = newIntervalStep;
      newIntervalStep = constrain(oldIntervalStep + 10, 1, 255);
    } else if ((key == UP_KEY) && !Repeat) {
      oldIntervalStep = newIntervalStep;
      if (postscaler <= 4) {  // This could lead to intervals <200ms, which we do want to avoid
        newIntervalStep = constrain(oldIntervalStep - 10, 11, 255);
      } else {
        newIntervalStep = constrain(oldIntervalStep - 10, 1, 255);
      }
    } else if ((key == RIGHT_KEY) && !Repeat) postscaler = constrain(postscaler * 2, 1, 32768);
    else if ((key == LEFT_KEY) && !Repeat) {
      postscaler = constrain(postscaler / 2, 1, 32768);
      if ((newIntervalStep < 11) && (postscaler <= 4)) newIntervalStep = 11; }
    else if ((key == WHITE_PLAY_KEY) && !Repeat && !aluRemote && !digitalRead(lightmeterPin)) startRunWithMetering();
    else if ((key == WHITE_PLAY_KEY) && !Repeat && !aluRemote && digitalRead(lightmeterPin))    stopRun();
    else blinkFlag = false;   // if we received a partial or garbled IR code, let's not confirm reception
  }
  if (blinkFlag) blinkLED();
  blinkFlag = true;   // Let's assume the next code is a valid one
}


// ISR 1 - called on IR signal coming in (falling edge on PB2)
ISR(INT0_vect) {
  int timeStamp = TCNT0;
  int overFlow = TIFR & 1 << TOV0;
  if (irBits == 32) {
    // Let's check for AGC
    if ((timeStamp >= 194) && (timeStamp <= 228) && (overFlow == 0)) {
      receivedData = 0; irBits = 0;
    } else if ((timeStamp >= 159) && (timeStamp <= 193) && (overFlow == 0)) ReceivedCode(1);
  } else {
    // Here comes the Data in
    if ((timeStamp > 44) || (overFlow != 0)) {
      irBits = 32; // Invalid data, so try again
    }
    else {
      if (timeStamp > 26) {
        receivedData = receivedData | ((unsigned long) 1 << irBits);
      }
      if (irBits == 31) { 
        ReceivedCode(0);
      }
      irBits++;
    }
  }
  TCNT0 = 0;                    // Clear Counter0
  TIFR = TIFR | 1 << TOV0;      // Clear Overflow
  GIFR = GIFR | 1 << INTF0;     // Clear INT0 flag
}

// ISR 2 - called by timer1 (for intervalometer)
ISR(TIMER1_COMPA_vect) {
  if (newIntervalStep != oldIntervalStep) {
    OCR1C = newIntervalStep;
    OCR1A = OCR1C;
  }
  if (divider == 0) {
    singleFrame();
  }
  divider++;
  divider %= postscaler;  // modulo trick to allow intervals > 4.3 Sec
}

void loop() {
// Our loop() is empty, since everthing happens through Attiny timeStamprs/Counters and Interrupts :)
}

// Here come the various relay plays, simulating what a finger on the camera trigger would do to the built-in switches.
void blinkLED() {
  digitalWrite(ledPin, HIGH);
  _delay_ms(20);
  digitalWrite(ledPin, LOW);
}
void startRunWithMetering() {
// Normaler Startzyklus wie mit EA-1
  digitalWrite(lightmeterPin, HIGH);
  digitalWrite(holdPin, HIGH);  
  digitalWrite(loadPin, HIGH);
  _delay_ms(250);      
  digitalWrite(loadPin, LOW);
  _delay_ms(70);      
  digitalWrite(startPin, HIGH);
}
void stopRun() {
  digitalWrite(startPin, LOW);
  _delay_ms(70);      
  digitalWrite(holdPin, LOW);  

  digitalWrite(lightmeterPin, LOW);
  digitalWrite(ledPin, HIGH);  
  _delay_ms(250);
  digitalWrite(ledPin, LOW);  
  lmMode = LM_MODE_1ST_SINGLESHOT;
}
void meterOnce() {
  digitalWrite(lightmeterPin, HIGH);
  digitalWrite(ledPin, HIGH);  
  _delay_ms(350);
  digitalWrite(ledPin, LOW);  
  digitalWrite(lightmeterPin, LOW);
  lmMode = LM_MODE_SUB_SINGLESHOT;
 }
void singleFrame() {
  digitalWrite(loadPin, HIGH);
  _delay_ms(10);                // 10ms is short but subsequent exposures will have a pre-loaded cap.
  digitalWrite(loadPin, LOW);
  digitalWrite(startPin, HIGH);
  _delay_ms(20);
  digitalWrite(startPin, LOW);
  digitalWrite(loadPin, HIGH);  // Pre-load the start capacitor since for the next exposure. Reduces latency. :)
  _delay_ms(50);        
  digitalWrite(loadPin, LOW);
}

 

Und falls es jemanden interessiert, hier der derzeitige Code.  Funktioniert fantastisch. Besonders stolz bin ich auf den main() loop :-)

 

 

Bearbeitet von F. Wachsmuth (Änderungen anzeigen)
  • Like 1
Geschrieben
vor 9 Stunden schrieb F. Wachsmuth:

Besonders stolz bin ich auf den main() loop :-)

Lol. :)

 

Schaut toll aus, gratuliere! Nachdem ich das noch nicht selbst ausprobieren kann hab ich den Code zumindest mal durch gelesen.

Drei Typos hätte ich gefunden, wenn ich sonst schon nichts beitragen kann, dann wenigsten das :) Hier bitte:

  1. but might damage the camera... who want's that?
  2. bool blinkFlag = true;       // Thisone is used to confirm reception fo valid IR codes
  3. void startRunWithMetering() { // Normaler Startzyklus wie mit EA-1 (plötzlich Kommentar in Deutsch)

Wie üblich wieder mal ein super Projekt, weiter so!

  • Like 1
  • 2 Wochen später...
Geschrieben

Sie funktionieren :)

Eine Kleinigkeit muss ich am Timing noch ändern und auf Teile warten... der erste Schwung chinesischer µC war offenbar gefälscht, zumindest aber nicht funktionsfähig. Das hat mich heute ein paar Stunden Fehlersuche gekostet.

Tja, wer billig kauft, kauft zweimal...

Geschrieben

"Was möchtet du aufgedruckt haben? Kein Problem, wir machen das so." So in etwa war die Antwort meines Batterielieferanten auf die Frage, wie den die Chinableiakkus für das Notlich so sind.

Jens

  • Like 1
Geschrieben (bearbeitet)

So, heut kam noch ein Feature hinzu: Das Anlernen beliebiger Fernbedienungen. Das war zum Glück allein durch Code machbar. 

 

Die Platine 

- reagiert auf beliebige Fernbedienungen mit Start/Stop (egal welche Taste) 

 

- erkennt von Haus aus jede Apple Remote (schön klein, ergonomisch, stabil, kräftig und preiswert) und liefert damit vollen Funktionsumfang

 

- kann jede neue FB lernen und bietet dann die gleichen Funktionen wir mit der Apple Remote. (Start/Stop, Einzelbild, Intervalometer)

 

Am 3.1. kriege ich noch eine Teilelieferung, dann wird im Akkord gelötet. :)

Bearbeitet von F. Wachsmuth (Änderungen anzeigen)
Geschrieben

Hier, hab gerade den ersten Schwung fertig gelötet. Funktioniert fantastisch. :)

 

31355FDF-0779-4CBB-8C07-BE11EF0FB980.thumb.jpeg.1b816cea1ab59d7b9c2c40bb340c556f.jpegCE27FB19-38DE-4E28-97FC-109C9F08DB66.thumb.jpeg.2e5692e8b725ab967f3038d72cde11b4.jpeg029CEBA4-6B3C-488A-A2E0-1D510F18DF2C.thumb.jpeg.af0e720497a8241dbfd1b26d772f132d.jpeg

 

Das Ding ist so klein und so wenig störend, dass man es wohl einfach immer drin steckennlassen kann. Sitzt auch so fest, dass es niemals rausfallen wird. 

Vielleicht mach ich morgen mal ein kleines Video zum Demonstrieren. :)

Erstelle ein Benutzerkonto oder melde Dich an, um zu kommentieren

Du musst ein Benutzerkonto haben, um einen Kommentar verfassen zu können

Benutzerkonto erstellen

Neues Benutzerkonto für unsere Community erstellen. Es ist einfach!

Neues Benutzerkonto erstellen

Anmelden

Du hast bereits ein Benutzerkonto? Melde Dich hier an.

Jetzt anmelden
×
×
  • Neu erstellen...

Filmvorführer.de mit Werbung, externen Inhalten und Cookies nutzen

  I accept

Filmvorfuehrer.de, die Forenmitglieder und Partner nutzen eingebettete Skripte und Cookies, um die Seite optimal zu gestalten und fortlaufend zu verbessern, sowie zur Ausspielung von externen Inhalten (z.B. youtube, Vimeo, Twitter,..) und Anzeigen.

Die Verarbeitungszwecke im Einzelnen sind:

  • Informationen auf einem Gerät speichern und/oder abrufen
  • Datenübermittlung an Partner, auch n Länder ausserhalb der EU (Drittstaatentransfer)
  • Personalisierte Anzeigen und Inhalte, Anzeigen- und Inhaltsmessungen, Erkenntnisse über Zielgruppen und Produktentwicklungen
Durch das Klicken des „Zustimmen“-Buttons stimmen Sie der Verarbeitung der auf Ihrem Gerät bzw. Ihrer Endeinrichtung gespeicherten Daten wie z.B. persönlichen Identifikatoren oder IP-Adressen für diese Verarbeitungszwecke gem. § 25 Abs. 1 TTDSG sowie Art. 6 Abs. 1 lit. a DSGVO zu. Darüber hinaus willigen Sie gem. Art. 49 Abs. 1 DSGVO ein, dass auch Anbieter in den USA Ihre Daten verarbeiten. In diesem Fall ist es möglich, dass die übermittelten Daten durch lokale Behörden verarbeitet werden. Weiterführende Details finden Sie in unserer  Datenschutzerklärung, die am Ende jeder Seite verlinkt sind. Die Zustimmung kann jederzeit durch Löschen des entsprechenden Cookies widerrufen werden.