home

So in a fit of pique I decided to put a TTL lightmeter into my old Leica IIIb, this camera was made in 1938.  To simplify the design the meter assumes the shutter is set to the film speed, the so called 'sunny f16' rule (go Google)

The progress of which I posted in the photo.net leica forum, you can see this by going to photo.net and searching for 'Mad Project'. 

Me and my camera
Here it is, finished (the one on the right!)

There are three main bits to this meter..

1) The photocell
2) The readout
3) The electronics

The photocell.
This is a TI TSL237 light to frequency converter, and sits in the light chamber of the camera pointing at the shutter curtain which has a white spot painted on it using fabric paint.

spot
Spot on the curtain

sensor
The sensor

placed
Shown here pointing at the shutter spot.

2) Readout

Here I have used a SOT23 red/green led, to see it through the viewfinder I stuck it onto the side of the 'bending' prism, this destroys the total internal reflection at this point and hence lets the light through.

led
The LED on 1mm divisions

on
Shown here stuck to the prism

wires
...and wired up leads go through slots and holes I machined.

red
Red LED on

green
Green LED on

3) Electronics
Use a good old PIC16F819 here running off a 3V lithium cell.  This is not finished! the cell lasts but a few minutes at the moment.  There is a switch activated from the shutter button as well.

bottom
Electronics in the baseplate, return circuit via the baseplate

wires
Getting the wire run correct was a bit of a pig, and I had to drill holes in this classic camera!

software
To write and debug the software I used a Microchip ICD2

I think I will make a cradle so I don't have to de-re- solder.

It's not finished yet, I only have a few minutes battery life, I think I will replace the sensor with a linear one, reduce the LED brightness and slow the clock on the PIC.

Now I have made the MKII so without further ado..


The new sensor


New PCB with MAX952 amplifier/reference and PIC16F819

Now the cell last much longer, at least an hour of on time, 12 rolls of film, I got bored after that.


Just for laughs, the assembler...funny how people have differing ideas on what a tab is! it is left like that so it can be pasted into MPLAB.

It is full of stuff that is not needed, if you want it tidier please tidy it up don't forget to mail me the tidy version!

;   This file is a basic code template for assembly code generation   *
;   on the PICmicro PIC16F819. This file contains the basic code      *
;   building blocks to build upon.                                    *
;                                                                     *
;   If interrupts are not used all code presented between the ORG     *
;   0x004 directive and the label main can be removed. In addition    *
;   the variable assignments for 'w_temp' and 'status_temp' can       *
;   be removed.                                                       *
;                                                                     *
;   Refer to the MPASM User's Guide for additional information on     *
;   features of the assembler (Document DS33014).                     *
;                                                                     *
;   Refer to the respective PICmicro data sheet for additional        *
;   information on the instruction set.                               *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Filename:        iib_expose.asm                                    *
;    Date:          6/6/4                                             *
;    File Version:    very draft                                      *
;                                                                     *
;    Author:       Huw Finney                                         *
;    Company:      Self                                               *
;                                                                     *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Files required:                                                  *
;                                                                     *
;                                                                     *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Notes:                                                           *
;                                                                     *
;     analogue measurment of the sensor                               *
;                                                                     *
;                                                                     *
;**********************************************************************

    list      p=16f819           ; list directive to define processor
    #include <p16F819.inc>        ; processor specific variable definitions

    errorlevel  -302              ; suppress message 302 from list file

    __CONFIG   _CP_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _CCP1_RB2 & _DEBUG_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_ON & _WDT_OFF & _PWRTE_ON & _INTRC_IO

; '__CONFIG' directive is used to embed configuration word within .asm file.
; The lables following the directive are located in the respective .inc file.
; See data sheet for additional information on configuration word settings.




;***** VARIABLE DEFINITIONS

    cblock    0x30
    status_temp
    w_temp
    d1
    d2
    th
    tl
    tl_1
    th_1
    tl_2
    th_2
    tl_3
    th_3
    tl_4
    th_4
    tl_5
    th_5
    tl_6
    th_6
    flags
    tim2
    senad
    refad
    X_IntH
    X_IntL         ;16 bit input/ output integer part
    X_FracH
    X_FracL      ;16 bit output fractional part
    Y               ;              divisor / temporary
    Counter          ;             counter
    endc

;*********** CONSTANTS ********************

exp_h            EQU        0x0c
exp_ok            EQU        0x13
exp_l            EQU        0x0e
sensor            EQU        0x04
vref            EQU        0x01
spower            EQU        0x04
green            EQU        0x06
red             EQU        0x07
timeout            EQU        0x00
switch            EQU        0x04
   
;**********************************************************************
    ORG     0x000                 ; processor reset vector
    nop                            ; for debugger
    goto    main                  ; go to beginning of program
   
    ORG     0x004                 ; interrupt vector location
    movwf   w_temp                ; save off current W register contents
    movf    STATUS,w              ; move status register into W register
    movwf    status_temp           ; save off contents of STATUS register
    bcf        STATUS, RP0            ; bank
    bcf        STATUS, RP1            ; zero
    bcf        INTCON, GIE            ; inhibit interrupts, set on retfie
    btfsc    INTCON, TMR0IF        ; is it timer 0 ??
    call    timer0routine
    movf    status_temp,w         ; retrieve copy of STATUS register
    movwf    STATUS                ; restore pre-isr STATUS register contents
    swapf   w_temp,f
    swapf   w_temp,w              ; restore pre-isr W register contents
    retfie                        ; return from interrupt

timer0routine
    bcf        INTCON, TMR0IF        ; has to be done
    incf    tim2, F                ; increment overflow reg
    btfsc    STATUS, Z            ; this overflowed too?
; this happens in 8 seconds, timeout???
    bsf        flags, timeout        ; say timed out
    return


main
    bcf        flags, timeout        ; un-timeout
    bcf        STATUS, RP1
    bcf        STATUS, RP0            ; bank 0
    clrf    PORTA
    clrf    PORTB
    bcf        STATUS, RP1
    bsf        STATUS, RP0            ; bank 1
    movlw    0xff                ; max freq
    movwf    OSCCON                ; set 8MHz
    MOVLW     b'00000100'            ; Configure pins
    MOVWF     ADCON1                 ; as a mixture of a & d
    MOVLW     b'000001010'        ;
    MOVWF     TRISA                 ; Set RA<7:0> as above
    MOVLW     b'11010000'            ;
    MOVWF     TRISB                 ; Set RB<7:0> as above
    movlw    b'00000111'            ; timer at 30Hz overflow rate
    movwf    OPTION_REG            ; set up
    movlw    b'10100000'            ; gie set tmr0 set
    movwf    INTCON                ; now all going
    bcf        STATUS, RP1
    bcf        STATUS, RP0            ; bank 0

; just for info, sunny 16 = 35 adresh

;timeout setup
    clrf    tim2                ; timeout ready
    bcf        flags, timeout

main_loop
    btfsc    flags, timeout        ; check for timeout
    goto    endall

; get sensor
    bsf        PORTA, sensor        ; power up sensor
    movlw    b'11011001'            ; ana on, ra3, int osc
    movwf    ADCON0
    call    sensor_pu_del        ; wait for power up and acq
    movlw    b'11011101'            ; ana on, ra3, int osc, GO!
    movwf    ADCON0
    nop
wfc    btfsc    ADCON0, 2            ; wait til done
    goto    wfc
;    bcf        ADCON0, 0            ; turn off a/d
    movfw    ADRESH                ; the result
   
    movwf    X_IntH
    clrf    X_IntL

; get reference
    movlw    b'11001001'            ; ana on, ra1, int osc
    movwf    ADCON0
    call    sensor_pu_del        ; wait for power up and acq
    movlw    b'11001101'            ; ana on, ra1, int osc, GO!
    movwf    ADCON0
    nop
wfr    btfsc    ADCON0, 2            ; wait til done
    goto    wfr
;    bcf        ADCON0, 0            ; turn off a/d
    movfw    ADRESH                ; the result
    movfw    Y


    call    Div16by8to16_16

    movfw    X_IntH
    movwf    th
   
    call    leds
   
    goto    main_loop



endall
    bcf        PORTA, green
    bcf        PORTA, red
    bcf        PORTA, spower
    bcf        ADCON0, 0            ; turn off a/d   
    movlw    0x00
    movwf    INTCON                ; clear all interrupts
    bsf        INTCON, RBIE        ; enable RB for wake up
    nop
    nop
; real sleep, test for switch open first, so int on change works
su    btfss    PORTB, switch
    goto su
    sleep
    nop
; pretend sleep for debugger
;ps    btfsc    PORTB, switch
;    goto    ps
    goto     main


sensor_pu_del
    call del1ms
    return


;Division of 16bit by 8 bit with a result in Q16.16 form
;
; X_Int.X_Frac = X_Int / Y
;
; RAM - 6 bytes (1 temp):
; X_Int = X_IntH:X_IntL         16 bit input/ output integer part
; X_Frac = X_FracH:X_FracL      16 bit output fractional part
; Y                             divisor / temporary
; Counter                       counter
;
; Size = 39 instructions
; Execution time = 6+16*14-1+3+16*14-1+3+2(return)
; = 460 instruction cycles
;
; 8-July-2000 by Nikolai Golovchenko
; 16-February-2001 fixed, reduced execution time and temporaries

Div16by8to16_16

        clrf X_FracL
        clrf X_FracH
        movlw 16
        movwf Counter
        movf Y, w       ;keep Y value in accumulator
        clrf Y          ;and use Y register as temporary

;Find integer part
Div16by8to16_16a

        rlf X_IntL, f   ;shift next msb into temporary
        rlf X_IntH, f
        rlf Y, f
        rlf Counter, f  ;carry has 9th bit of temporary
                        ;copy carry to counter

        subwf Y, f      ;substract Y (in w) from temporary

        skpnc           ;if no borrow, set Counter.0
         bsf Counter, 0

        btfss Counter, 0 ;if Counter.0 clear (borrow) restore temporary
         addwf Y, f

        clrc            ;restore counter
        rrf Counter, f

;at this point carry is the next bit of result
        decfsz Counter, f ;repeat 16 times to find integer part
         goto Div16by8to16_16a

                        ;shift last integer bit
        rlf X_IntL, f
        rlf X_IntH, f

;Find fractional part
        bsf Counter, 4  ;Counter = 16
Div16by8to16_16b
                        ;Shift zero bit into temporary
        rlf X_FracL, f
        rlf X_FracH, f
        rlf Y, f
        rlf Counter, f  ;carry has 9th bit of temporary
                        ;copy carry to counter

        subwf Y, f      ;substract Y(in w) from temporary

        skpnc           ;if no borrow, set Counter.0
         bsf Counter, 0

        btfss Counter, 0 ;if Counter.0 clear (borrow) restore temporary
         addwf Y, f

        clrc            ;restore counter
        rrf Counter, f

        decfsz Counter, f ;repeat 16 times
         goto Div16by8to16_16b
                        ;shift last fractional bit
        rlf X_FracL, f
        rlf X_FracH, f

        movwf Y         ;restore divisor
        return

wfu    btfss    PORTB, switch
    goto    wfu                    ; ensure wake is the right way round
    nop
    nop
    sleep
    nop
    nop
    goto main

loop
    call    wfh
    bcf        T1CON, 0            ; stop timer
    movfw    TMR1H
    movwf    th
    clrf    TMR1L
    clrf    TMR1H
    bsf        T1CON, 0            ; start timer
    call    leds
    call    wfl
    bcf        T1CON, 0            ; stop timer
    movfw    TMR1H
    movwf    th
    clrf    TMR1L
    clrf    TMR1H
    bsf        T1CON, 0            ; start timer
    call    leds
    goto    loop

leds
; compare th with exp_h, exp_l  h=amber, l=red, ok=green
; exp_h is smaller than exp_l
    bcf        PORTA, green
    bcf        PORTA, red
    movfw    th
    sublw    exp_ok
    btfss    STATUS, C
    bsf        PORTA, green
    btfsc    STATUS, C
    bsf        PORTA, red
;    movfw    th
;    sublw    exp_h
;    btfsc    STATUS, C
;    bsf        PORTA, red
    return

del1ms
    ;1998 cycles
    movlw    0x8F
    movwf    d1
    movlw    0x20
    movwf    d2
Delay_0
    decfsz    d1, f
    goto    $+2
    decfsz    d2, f
    goto    Delay_0
    return

; for getting the right value in calibration
;loop
    call    wfl
    bcf        T1CON, 0            ; stop timer
    movfw    TMR1L
    movwf    tl_1
    movfw    TMR1H
    movwf    th_1
    clrf    TMR1L
    clrf    TMR1H
    bsf        T1CON, 0            ; start timer
    call    wfh
    bcf        T1CON, 0            ; stop timer
    movfw    TMR1L
    movwf    tl_2
    movfw    TMR1H
    movwf    th_2
    clrf    TMR1L
    clrf    TMR1H
    bsf        T1CON, 0            ; start timer

    call    wfl
    bcf        T1CON, 0            ; stop timer
    movfw    TMR1L
    movwf    tl_3
    movfw    TMR1H
    movwf    th_3
    clrf    TMR1L
    clrf    TMR1H
    bsf        T1CON, 0            ; start timer
    call    wfh
    bcf        T1CON, 0            ; stop timer
    movfw    TMR1L
    movwf    tl_4
    movfw    TMR1H
    movwf    th_4
    clrf    TMR1L
    clrf    TMR1H
    bsf        T1CON, 0            ; start timer

    call    wfl
    bcf        T1CON, 0            ; stop timer
    movfw    TMR1L
    movwf    tl_5
    movfw    TMR1H
    movwf    th_5
    clrf    TMR1L
    clrf    TMR1H
    bsf        T1CON, 0            ; start timer
    call    wfh
    bcf        T1CON, 0            ; stop timer
    movfw    TMR1L
    movwf    tl_6
    movfw    TMR1H
    movwf    th_6
    clrf    TMR1L
    clrf    TMR1H
    bsf        T1CON, 0            ; start timer

    goto loop   


wfl    btfsc    PORTA, sensor
    goto    wfl
    return

wfh    btfss    PORTA, sensor
    goto    wfh
    return



; initialize eeprom locations

    ORG    0x2100
    DE    0x00, 0x01, 0x02, 0x03


    END                       ; directive 'end of program'