A/D conversion

I’ve gotten the A/D converter on the Microchip PIC P12F675 to work. The pulse width modulation technique is allowing me to simulate different intensities of light. What you do is send extremely fast pulses of light on and off. Your eye “averages” these out to appear as a middle intensity brightness.

Here is a movie:

Here is the source code:

  1  ;Software License Agreement                                         
  2  ;                                                                    
  3  ;The software supplied herewith by Microchip Technology             
  4  ;Incorporated (the "Company") is intended and supplied to you, the  
  5  ;Company~Rs customer, for use solely and exclusively on Microchip    
  6  ;products. The software is owned by the Company and/or its supplier,
  7  ;and is protected under applicable copyright laws. All rights are   
  8  ;reserved. Any use in violation of the foregoing restrictions may   
  9  ;subject the user to criminal sanctions under applicable laws, as   
 10  ;well as to civil liability for the breach of the terms and         
 11  ;conditions of this license.                                        
 12  ;                                                                    
 19  ;****************************************************************************
 20  ;Filename:      atod.asm
 21  ;Author:        Ruan Lourens
 22  ;Date:          1.03.03 
 23  ;Version:       1.0 (A/D Version)
 24  ;Description:   This is an ASSEMBLY written program designed to show the user  
 25  ;               a timer driven analog-to-digital conversion.It is based on the 
 26  ;               interrupt driven conversionLED State Machine used in 
 27  ;               tutorial #3.     
 28  ;****************************************************************************
 29  ;Revision History
 30  ;****************************************************************************
 33      list      p=12F675              ; list directive to define processor
 34      #include <>          ; processor specific variable definitions
 35      ;#include "atod.h"
 36      errorlevel  -302               ; suppress message 302 from list file
 40  ; '__CONFIG' directive is used to embed configuration word within .asm file.
 41  ; The lables following the directive are located in the respective .inc file.
 42  ; See data sheet for additional information on configuration word settings.
 44  ;****************************************************************************
 45  ;Defines
 46  ;****************************************************************************
 47  #define BANK1       bsf     STATUS,RP0  ; Bank1
 48  #define BANK0       bcf     STATUS,RP0  ; Bank0
 49  #define LED1TRIS    b'11001111'
 50  #define LED2TRIS    b'11001111'
 51  #define LED3TRIS    b'11101011'
 52  #define LED4TRIS    b'11101011'
 53  #define LED5TRIS    b'11011011'
 54  #define LED6TRIS    b'11011011'
 55  #define LED7TRIS    b'11111001'
 56  #define LED8TRIS    b'11111001'
 57  #define LED1ON      b'00010000'
 58  #define LED2ON      b'00100000'
 59  #define LED3ON      b'00010000'
 60  #define LED4ON      b'00000100'
 61  #define LED5ON      b'00100000'
 62  #define LED6ON      b'00000100'
 63  #define LED7ON      b'00000100'
 64  #define LED8ON      b'00000010'
 65  #define NUMBEROFBITS    .8
 66  #define ANSelect    b'00010001'     ;Used to configure AD
 67  #define ADControl   b'00000001'     ;Used to configure AD
 71  mcount        EQU     22h
 72  ncount        EQU     23h
 73  new_tris        EQU     24h
 74  new_gpio        EQU     25h
 75  brightness_num  EQU  26h
 76  brightness_den  EQU 27h
 77  brightness_dat  EQU 28h
 78  IS_ON_BIT       EQU 0
 79  brightness_count EQU 29h
 80  temp EQU 30h
 81  ALL_OFF_TRIS EQU b'11111111'
 83  ;****************************************************************************
 84  ;General Purpose Registers (GPR's) 
 85  ;****************************************************************************
 86      ; UDATA_SHR
 87  WTEMP       res 1           ; register used in Interrupt Routine
 88  STATUSTEMP  res 1           ; register used in Interrupt Routine
 89  PCLATHTEMP  res 1           ; register used in Interrupt Routine
 90  FSRTEMP     res 1           ; register used in Interrupt Routine
 91  FLAGS       res 1           ; register used to set flags
 93  ;****************************************************************************
 94  ;Reset Vector
 95  ;****************************************************************************
 96      ORG     0x000             ; processor reset vector
 97      nop                       ; Inserted For ICD2 Use
 98      goto    Init              ; go to beginning of program
100  ;****************************************************************************
101  ;Interrupt Vector - Interrupts only active during animation sequence
102  ;                 - Interrupt Sources:  1.  TIMER0 Overflow
103  ;
104  ;FLAGS register - bit0:  1 = A/D will be serviced, 0 = Display will be serviced
105  ;
106  ;****************************************************************************
107      ORG     0x004             ; interrupt vector location
108  Isr
109      movwf   WTEMP           ;Save off current W register contents
110      movf    STATUS,w
111      clrf    STATUS          ;Force to page0
112      movwf   STATUSTEMP
113      ;movf   PCLATH,w
114      ;movwf  PCLATHTEMP      ;Save PCLATH
115      ;movf   FSR,w
116      ;movwf  FSRTEMP         ;Save FSR
119  ;****************************************************************************
120  ;Interrupt Source Checks
121  ;****************************************************************************
122  Timer0InterruptCheck
123      BANK1                   ; BANK1   
124      movf    INTCON,w
125      andlw   0x20
126      btfsc   STATUS,Z        ;Is T0IE Set?
127      goto    Next1           ;No
128      movf    INTCON,w        ;Yes
129      andlw   0x04
130      btfss   STATUS,Z        ;Is TOIF Set?
131      goto    Timer0Interrupt ;Yes
133  Next1
134  GPIFInterruptCheck
135      movf    INTCON,w
136      andlw   0x08
137      btfsc   STATUS,Z        ;Is GPIE Set?
138      goto    Next2           ;No
139      movf    INTCON,w        ;Yes
140      andlw   0x01
141      btfss   STATUS,Z        ;Is GPIF Set?
142      goto    GPIFInterrupt   ;Yes
144  Next2
145  GP2_INT_ExternalInterruptCheck
146      movf    INTCON,w
147      andlw   0x10
148      btfsc   STATUS,Z        ;Is INTE Set?
149      goto    Next3           ;No
150      movf    INTCON,w        ;Yes
151      andlw   0x02
152      btfss   STATUS,Z        ;Is INTF Set?
153      goto    GP2_INTExternalInterrupt;Yes
155  Next3
156  PeripheralInterruptCheck
157      movf    INTCON,w
158      andlw   0x40
159      btfsc   STATUS,Z        ;Is PEIE Set?
160      goto    EndIsr          ;No
162  Next4
163  EEIFInterruptCheck
164      movf    PIE1,w
165      andlw   0x80
166      btfsc   STATUS,Z        ;Is EEIE Set?
167      goto    Next5           ;No
168      BANK0                   ;Yes
169      movf    PIR1,w
170      BANK1
171      andlw   0x80
172      btfss   STATUS,Z        ;Is EEIF Set?
173      goto    EEPROMInterrupt;Yes
175  Next5
176  ADIFInterruptCheck
177      movf    PIE1,w
178      andlw   0x40
179      btfsc   STATUS,Z        ;Is ADIE Set?
180      goto    Next6           ;No
181      BANK0
182      movf    PIR1,w
183      BANK1
184      andlw   0x40
185      btfss   STATUS,Z        ;Is ADIF Set?
186      goto    A_DConverterInterrupt;Yes   
188  Next6
189  CMIFInterruptCheck
190      movf    PIE1,w
191      andlw   0x08
192      btfsc   STATUS,Z        ;Is CMIE Set?
193      goto    Next7           ;No
194      BANK0                   ;Yes
195      movf    PIR1,w
196      BANK1
197      andlw   0x08
198      btfss   STATUS,Z        ;Is CMIF Set?
199      goto    ComparatorInterrupt;Yes
201  Next7
202  TMR1IFInterruptCheck
203      movf    PIE1,w
204      andlw   0x01
205      btfsc   STATUS,Z        ;Is TMR1IE Set?
206      goto    EndIsr          ;No
207      BANK0                   ;Yes
208      movf    PIR1,w
209      BANK1
210      andlw   0x01
211      btfss   STATUS,Z        ;Is TMR1IF Set?
212      goto    Timer1Interrupt ;Yes
213      goto    EndIsr          ;No
215  Timer0Interrupt             ;Interrupt every 1024 uS
216      BANK0               ;BANK0
217      btfsc   FLAGS,0         ;Check if A/D functions will be serviced or the display routine                 
218      call    AD_Functions        ;Yes, service A/D
219      BANK0               ;BANK0
220      btfss   FLAGS,0         ;Check if Display functions will be serviced
221      call    Display         ;Yes, goto Display
222      BANK0               ;BANK0
223      movlw   b'00000001'
224      xorwf   FLAGS,F         ;Toggle FLAGS,1
225      BANK1               ;BANK1
226      bcf     INTCON,T0IF ;Clear TMR0 Interrupt Flag  
227      goto    EndIsr
229  Display
230      decfsz brightness_count,f
231      goto activate_leds
232      goto toggle_on_off
233  toggle_on_off:
234      movlw   b'11111111'
235      xorwf   brightness_dat,f
236      btfsc   brightness_dat,IS_ON_BIT
237      goto store_off_time
238      goto store_on_time
239  store_on_time:
240      movfw   brightness_num
241      movwf   brightness_count
242      goto activate_leds
243  store_off_time:
244      movfw   brightness_den
245      movwf   brightness_count
246  activate_leds:
247      btfsc   brightness_dat,IS_ON_BIT
248      goto show_black
249      goto show_lights
250  show_black:
251          movlw   b'11111111'
252          bsf     STATUS,RP0  ;Bank 1
253          movwf   TRISIO      ;and set GP<5:4,1:0>
254          bcf     STATUS,RP0  ;Bank 0
255          movlw   b'00000000'
256          movwf   GPIO
257      goto end_of_intr
258  show_lights:
259          movfw   new_tris;
260          bsf     STATUS,RP0  ;Bank 1
261      ;movlw b'11001111'
262          movwf   TRISIO      ;and set GP<5:4,1:0>
263          bcf     STATUS,RP0  ;Bank 0
264          movfw   new_gpio
265      ;movlw  b'00010000'
266          movwf   GPIO
267  end_of_intr:
268      return
273  GPIFInterrupt
274      goto    EndIsr
276  GP2_INTExternalInterrupt
277      goto    EndIsr
279  EEPROMInterrupt
280      goto    EndIsr
282  A_DConverterInterrupt
283      goto    EndIsr
285  ComparatorInterrupt
286      goto    EndIsr
288  Timer1Interrupt
290  EndIsr
291      clrf    STATUS            ;Select Bank0
292      ;movf   FSRTEMP,w
293      ;movwf  FSR               ;Restore FSR
294      ;movf   PCLATHTEMP,w
295      ;movwf  PCLATH            ;Restore PCLATH
296      movf    STATUSTEMP,w
297      movwf   STATUS            ;Restore STATUS
298      swapf   WTEMP,f
299      swapf   WTEMP,w           ;Restore W without corrupting STATUS bits
300      retfie                    ;Return from interrupt    
303  ;****************************************************************************
304  ;AD_Functions
305  ;****************************************************************************
306  AD_Functions
307      BANK0               ;BANK0
308      movf    ADRESH,W        ;Move the most significant byte of A/D Result to W
309      movwf   LEDREGISTER     ;The A/D result is moved to LEDREGISTER and will be displayed
310      bsf ADCON0,GO       ;Start A/D
311      return
313  ;****************************************************************************
314  ;Initialization
315  ;****************************************************************************
316  Init
317      ;call    0x3FF      ; retrieve factory calibration value
318                          ; comment instruction if using simulator, ICD2, or ICE2000
319      BANK1
320      movwf   OSCCAL      ; update register with factory cal value 
321      ;call   InitLED     ;Initialize LED Routine Variables
322      movlw   b'00000001'
323      movwf   TRISIO          ;Tri-State All Inputs
324      BANK0               ;BANK 0
325      clrf    GPIO            ;Clear Port
326      movlw   b'00100000'
327      movwf   GPIO
329      BANK1               ;BANK 1
330      clrf    VRCON           ;Vref Off
331      BANK0               ;BANK 0
332      clrf    TMR0
333      movlw   0x07
334      movwf   CMCON           ;Comparator Off
336      BANK1                   ;BANK 1 
337      movlw   b'10000001'
338      movwf   OPTION_REG      ;TIMER0 Prescaler = 4 and pull-ups disabled
339      bsf     INTCON,T0IE     ;Interrupt on TIMER0 Overflow Enabled
340      bcf     INTCON,T0IF     ;Clear TIMER0 Overflow Interrupt Flag
341      bsf     INTCON,GIE      ;Turn on Global Interrupts
342      movlw   ANSelect
343      movwf   ANSEL           ;Configure AN0 & prescale to A/D    
345      BANK0                   ;BANK 0
346      movlw   ADControl
347      movwf   ADCON0          ;Select AN0, Left justified & enables A/D
348      NOP
349      NOP
350      NOP
351      NOP                     ; Give 4 uS delay before starting A/D
352      bsf ADCON0,GO           ; Start A/D
354  ;****************************************************************************
355  ;MAIN - Main Routine
356  ;****************************************************************************
357  Main
358          movlw   0x02
359          movwf   brightness_num
360          movlw   0x1F
361          movwf   brightness_den
362          movlw   0xFF
363          movwf   brightness_count
364  go
365          ; D0
366          movlw   b'11001111'
367          movwf   new_tris
368          movlw   b'00010000'
369          movwf   new_gpio
370          call    delay
371          ; D0
372          movlw   b'11001111'
373          movwf   new_tris        ;and set GP<5:4,1:0>
374          movlw   b'00100000'
375          movwf   new_gpio
376          call    delay
377          ; D0
378          movlw   b'11101011'
379          movwf   new_tris        ;and set GP<5:4,1:0>
380          movlw   b'00010000'
381          movwf   new_gpio
382          call    delay
383          ; D0
384          movlw   b'11101011'
385          movwf   new_tris        ;and set GP<5:4,1:0>
386          movlw   b'00000100'
387          movwf   new_gpio
388          call    delay
389          ; D7
390          movlw   b'11111001'
391          movwf   new_tris        ;and set GP<5:4,1:0>
392          movlw   b'00000010'
393          movwf   new_gpio
394          call    delay
395          ; D6
396          movlw   b'11111001'
397          movwf   new_tris        ;and set GP<5:4,1:0>
398          movlw   b'00000100'
399          movwf   new_gpio
400          call    delay
401          ; D5
402          movlw   b'11011011'
403          movwf   new_tris        ;and set GP<5:4,1:0>
404          movlw   b'00000100'
405          movwf   new_gpio
406          call    delay
407          ; D0
408          movlw   b'11011011'
409          movwf   new_tris        ;and set GP<5:4,1:0>
410          movlw   b'00100000'
411          movwf   new_gpio
412          call    delay
413         goto go
416  ;delay loop
417  delay   movlw   0x01
418          movwf   temp
419          movwf   brightness_num
420  loadm2   movlw   0x2f
421          movwf   mcount
422  loadn2  movfw   LEDREGISTER
423          addlw   1
424          movwf   ncount
425  repeat2
426          decfsz  ncount,f
427          goto    repeat2
428          decfsz  mcount,f
429          goto    loadn2
430          incf    brightness_num,f
431          movlw   0x13
432          movwf   brightness_den
433          movfw   brightness_num
434          subwf   brightness_den,f
435          incf    brightness_den,f
436          movlw   0x13
437          xorwf   brightness_num,w
438          movwf   temp
439          incf    temp,f
440          decfsz  temp,f
441          goto    loadm2
442          goto delay2
443  delay2   movlw   0x13
444          movwf   brightness_num
445  loadm   movlw   0x2f
446          movwf   mcount
447          movlw   0x13
448          movwf   brightness_den
449          movfw   brightness_num,f
450          subwf   brightness_den,f
451          incf    brightness_den,f
452  loadn   movfw   LEDREGISTER
453          addlw   1
454          movwf   ncount
455  repeat
456          decfsz  ncount,f
457          goto    repeat
458          decfsz  mcount,f
459          goto    loadn
460          decfsz  brightness_num,f
461          goto    loadm
462          return
465  ; initialize eeprom locations
467          ORG 0x2100
468          DE  0x00, 0x01, 0x02, 0x03
471          END                       ; directive 'end of program'

Is that what you would call “geeky”?

I have to share my solution for this problem I was having. My PIC controller programmer only works on Windows (for the time being) because of various technical difficulties (I’ll spare you the details). I only have a Mac at home.
So I plugged the pic controller programmer into my Windows machine at work and turned on Remote Desktop. With Remote Dekstop, I can control my Windows machine from home.
Then I pointed the iSight camera attached to my work Mac at the programmer.
Finally, if I remote desktop into both machines at work, I can dial myself up on iChatAV and get a view of the programmer (and the important 10 LEDs). I can also run the programmer software on the Windows machine to upload new software into the PIC.


Chlorophyll Fluorescence

In a discussion today I was reminded of one of my favorite experiments from college plant physiology class. We were discussing the light harvesting apparatus (LHA) of a plant cell. The molecular organization of this system relies on the primary light collecting molecule chlorophyll. Chlorophyll acts to trap light radiation and convert that into what is called an “excited electron”. This is sort of like electricity. A field of chlorophyll molecules are attached to the chloroplast internal membrane. They pass the excited electrons around until the reach some molecular machines that use that electron to create sugar. The process of making sugar is amazingly complicated, involving a proton gradient, electron carrying molecule (NADPH) and the biological “currency” of the cell, ATP. I’ll spare you the details (for now, moo hoo hah aha ahhaa!).
Anyhow, the interesting thing about chlorophyll in this case is that when it is not attached to the rest of the LHA, the excited electron doesn’t have anywhere to go. So eventually in that case, the electron will become unexcited and in so doing emit some light. However, since there is energy loss in this system, the emitted light is of a lower energy — so it is redder than the light it absorbed.
Plants look green because of the light absorbing characteristics of chlorophyll. Chlorophyll absorbs red and blue light. The water in the plant leaf is shiny and reflects the rest of the light — green.
Okay, with that background info we can go back to the interesting experiment. You can try this at home, but be very careful because acetone is flamable, and blenders can create sparks. Be sure to have fire extinguisher at the ready and also take note that I take no responsibility for death, blindness or dismemberment that results. On the other hand, I was able to do this experiment successfully with a four year old sister and my mother-in-law.
Take some spinach — or any green leafy plant, grass clippings work too. Put it in the blender with some acetone (nail polish remover works). Blend for a little while until it makes a rich green juice. Now strain out the plant matter and reserve the precious green liquid. If you look through the liquid at a bright light source, you will see the light that is not absorbed by the chlorophyll — green is not absorbed so the liquid looks green.
Now for the really cool part. Look at the liquid when it is lit by a strong light from the side. Sunlight works the best, but light from an overhead projector is okay, too. The chlorophyll absorbs the light and then emits light back out. But it emits a different color! The solution will be a deep ruby red. It is really wild to watch the color change depending on your point of view.


Das Blinken Lights

Well, I’ve given up (for the time being) on how to use my Macintosh to program the PIC controller. I took my lunch hour today at work to program my PIC p12F675 on the PICKit 1 Flash Starter Kit to blink its lights in a circular fashion. Since there is a lack of good info about this on the web, per my new initiative to inform the world (lol) I’m going to say exactly how I did it.
First, I installed the gnu pic utilities — of which I’m using gpasm to “assemble” my code into pic bytecode. (See below for the code.)
Next I compiled the code like this:

gpasm –dos -pp12F675 –hex-format inhx32 gp2.asm

It is necessary to add the –dos option since the upload program I use is a Windows program. Oh and by the way everything so far is Mac friendly. Now copy the resulting .hex file onto your windows box and upload it using the PICkit(tm) 1 FLASH Starter Kit application. I think I used the “Baseline Flash” instead of the “Classic” version. Control – I Imports, and Control – W writes.
Be sure you have the right kind of PIC — for my program I used a p12f675.

Double click to replay if there is no controller.
Can’t see the video above? Click
here to download our video file, then launch it from your desktop.

Still can’t
see the video? Install Apple’s free QuickTime player.

Here is the code, for those at home who wish to duplicate my experiment.

  1  ;   This file is a basic code template for assembly code generation   *
  2  ;   on the PICmicro PIC12F675. This file contains the basic code      *
  3  ;   building blocks to build upon.                                    *
  4  ;                                                                     *
  5  ;   If interrupts are not used all code presented between the ORG     *
  6  ;   0x004 directive and the label main can be removed. In addition    *
  7  ;   the variable assignments for 'w_temp' and 'status_temp' can       *
  8  ;   be removed. If the internal RC oscillator is not implemented      *
  9  ;   then the first four instructions following the label 'main' can   *
 10  ;   be removed.                                                       *
 11  ;                                                                     *
 12  ;   Refer to the MPASM User's Guide for additional information on     *
 13  ;   features of the assembler (Document DS33014).                     *
 14  ;                                                                     *
 15  ;   Refer to the respective PICmicro data sheet for additional        *
 16  ;   information on the instruction set.                               *
 17  ;                                                                     *
 18  ;**********************************************************************
 19  ;                                                                     *
 20  ;    Filename:      xxx.asm                                           *
 21  ;    Date:                                                            *
 22  ;    File Version:                                                    *
 23  ;                                                                     *
 24  ;    Author:                                                          *
 25  ;    Company:                                                         *
 26  ;                                                                     *
 27  ;                                                                     *
 28  ;**********************************************************************
 29  ;                                                                     *
 30  ;    Files required:                                                  *
 31  ;                                                                     *
 32  ;                                                                     *
 33  ;                                                                     *
 34  ;**********************************************************************
 35  ;                                                                     *
 36  ;    Notes:                                                           *
 37  ;                                                                     *
 38  ;                                                                     *
 39  ;                                                                     *
 40  ;                                                                     *
 41  ;**********************************************************************
 43      list      p=12f675           ; list directive to define processor
 44      #include <>        ; processor specific variable definitions
 46      errorlevel  -302              ; suppress message 302 from list file
 50  ; '__CONFIG' directive is used to embed configuration word within .asm file.
 51  ; The lables following the directive are located in the respective .inc file.
 52  ; See data sheet for additional information on configuration word settings.
 58  w_temp        EQU     0x20        ; variable used for context saving 
 59  status_temp   EQU     0x21        ; variable used for context saving
 60  mcount        EQU     22h
 61  ncount        EQU     23h
 62  new_tris        EQU     24h
 63  new_gpio        EQU     25h
 70  ;**********************************************************************
 71          ORG     0x000             ; processor reset vector
 72          goto    main              ; go to beginning of program
 75  ; (no interrupt)        ORG     0x004             ; interrupt vector location
 76  ; (no interrupt)        movwf   w_temp            ; save off current W register contents
 77  ; (no interrupt)        movf    STATUS,w          ; move status register into W register
 78  ; (no interrupt)        movwf   status_temp       ; save off contents of STATUS register
 79  ; (no interrupt)
 80  ; (no interrupt)
 81  ; (no interrupt); isr code can go here or be located as a call subroutine elsewhere
 82  ; (no interrupt)
 83  ; (no interrupt)
 84  ; (no interrupt)        movf    status_temp,w     ; retrieve copy of STATUS register
 85  ; (no interrupt)        movwf   STATUS            ; restore pre-isr STATUS register contents
 86  ; (no interrupt)        swapf   w_temp,f
 87  ; (no interrupt)        swapf   w_temp,w          ; restore pre-isr W register contents
 88  ; (no interrupt)        retfie                    ; return from interrupt
 91  ; these first 4 instructions are not required if the internal oscillator is not used
 92  main
 93          call    0x3FF             ; retrieve factory calibration value
 94          bsf     STATUS,RP0        ; set file register bank to 1 
 95          movwf   OSCCAL            ; update register with factory cal value 
 96          bcf     STATUS,RP0        ; set file register bank to 0
 99  ; remaining code goes here
101          bcf     STATUS,RP0  ;Bank 0
102          clrf    GPIO        ;Init GPIO
103          movlw   07h         ;Set GP<2:0> to
104          movwf   CMCON       ;digital IO
105          bsf     STATUS,RP0  ;Bank 1
106          clrf    ANSEL       ;Digital I/O
107          movlw   08h         ;Set GP<3:2> as inputs
108          movwf   TRISIO      ;and set GP<5:4,1:0>
109                              ;as outputs
110          bcf     STATUS,RP0  ;Bank 0
112  go
113          ; D0
114          bsf     STATUS,RP0  ;Bank 1
115          movlw   b'11001111'
116          movwf   TRISIO      ;and set GP<5:4,1:0>
117          bcf     STATUS,RP0  ;Bank 0
118          movlw   b'00010000'
119          movwf   GPIO
120          call    delay
121          ; D0
122          bsf     STATUS,RP0  ;Bank 1
123          movlw   b'11001111'
124          movwf   TRISIO      ;and set GP<5:4,1:0>
125          bcf     STATUS,RP0  ;Bank 0
126          movlw   b'00100000'
127          movwf   GPIO
128          call    delay
129          ; D0
130          bsf     STATUS,RP0  ;Bank 1
131          movlw   b'11101011'
132          movwf   TRISIO      ;and set GP<5:4,1:0>
133          bcf     STATUS,RP0  ;Bank 0
134          movlw   b'00010000'
135          movwf   GPIO
136          call    delay
137          ; D0
138          bsf     STATUS,RP0  ;Bank 1
139          movlw   b'11101011'
140          movwf   TRISIO      ;and set GP<5:4,1:0>
141          bcf     STATUS,RP0  ;Bank 0
142          movlw   b'00000100'
143          movwf   GPIO
144          call    delay
145          ; D7
146          bsf     STATUS,RP0  ;Bank 1
147          movlw   b'11111001'
148          movwf   TRISIO      ;and set GP<5:4,1:0>
149          bcf     STATUS,RP0  ;Bank 0
150          movlw   b'00000010'
151          movwf   GPIO
152          call    delay
153          ; D6
154          bsf     STATUS,RP0  ;Bank 1
155          movlw   b'11111001'
156          movwf   TRISIO      ;and set GP<5:4,1:0>
157          bcf     STATUS,RP0  ;Bank 0
158          movlw   b'00000100'
159          movwf   GPIO
160          call    delay
161          ; D5
162          bsf     STATUS,RP0  ;Bank 1
163          movlw   b'11011011'
164          movwf   TRISIO      ;and set GP<5:4,1:0>
165          bcf     STATUS,RP0  ;Bank 0
166          movlw   b'00000100'
167          movwf   GPIO
168          call    delay
169          ; D0
170          bsf     STATUS,RP0  ;Bank 1
171          movlw   b'11011011'
172          movwf   TRISIO      ;and set GP<5:4,1:0>
173          bcf     STATUS,RP0  ;Bank 0
174          movlw   b'00100000'
175          movwf   GPIO
176          call    delay
177         goto go
180  ;delay loop
181  delay   movlw   0x4f
182          movwf   mcount
183  loadn   movlw   0xff
184          movwf   ncount
185  repeat  decfsz  ncount,f
186          goto    repeat
187          decfsz  mcount,f
188          goto    loadn
189          return
191  ; initialize eeprom locations
193          ORG 0x2100
194          DE  0x00, 0x01, 0x02, 0x03
197          END                       ; directive 'end of program'

Oh, were you wondering how I got the nice formatting for the code? I used VIM like this
:runtime! syntax/2html.vim. Do :help 2html in VIM for more info.


PIC microcontroller

I’ve discovered an entirely new realm of geekiness in PIC microcontrollers. These inexpensive ( ~$2.00 ) computers can be programmed to control lights, motors or whatever and can also be controlled through switches or knobs. My mind is exploding with possibilities with what you can make with these. For example, the good old simon says toy, where lights flash in a random sequence which you have to remember, and then you press buttons in the same sequence back. Or a christmas decoration which twinkles. Or lights that zip in a pattern on a billboard sign. Or a robot that drives itself around towards a light source.
Help! I need some ideas of what my first project should be.
I’ve also noticed, as my friend Stacie the librarian preaches, that the internet is indeed a lousy place to find information. Thus as a public service to the world at large, I would like to publicly answer a question that took me about a half hour to figure out. With hope, Google will index this question and answer the future generations of geeks will be spared the pain.

Question: Where do you get GCC 3.1 for Mac OS X (Darwin) version 10.3 or higher?
Answer: It is in a package called gcc3.1.pkg on the XCode 1.5 disk image. You can download XCode from Apple if you set up a free Developer Connection user account.

Well, next I’m trying to use Fink to install libusb so I can build usb_pickit and hopefully get it to work with the PICKit 1 Onboard firmware version is 2.0.2. Apparently the Mac OS tools for the PICKit stopped working when Microchip updated the firmware — doh!



Becka got me into this week’s drawing. This week the word was Fiesta and this is what I drew:
(click for full size)


Give me a caption

I drew this picture a few days ago. Can you think of a caption for the picture?


Pitch Black Mountain Dew

If you haven’t read the first entry in about pitch black mountain dew’s blue foam
Well, after much eager anticipation, my analysis about why the bubbles on the weird pitch black mountain dew turn blue is complete. At the end of my previous post, I had a couple of ideas for some experiments to help clarify this issue. I’ve now finished my experiments and am happy to report that I think the mystery is solved!
I was able to collect a sample of the blue foam. This was difficult at first, because it doesn’t turn blue until it’s almost entirely gone. However, I discovered that if I shook the bottle up with the cap closed, and then carefully released some air, the soda would foam up inside the bottle. After a few moments, the foam in the bottle turned blue. Then I released some more air by opening the lid a small amount and collected some of the foam that ran out.
I blotted nine drops of the liquid from the blue foam and nine drops of regular soda onto a paper towel and let it dry for several days. Then I scanned the towel into Photoshop and drew rectangles around each drop and looked at the red and blue values for each
The picture doesn’t really do it justice, the difference is far more startling that that looks. But who am I to trust the human eye to discern differences? This table presents the raw data for the red and blue channels’ average pixel value as well as the ratio of the two, the averages of those six data sets and the p value from the Student’s T Test on the ratios.

regular red regular blue foam red foam blue regular ratio foam ratio
247 213 232 219 1.15962441 1.05936073
248 209 229 224 1.18660287 1.02232143
246 218 231 219 1.12844037 1.05479452
240 210 229 222 1.14285714 1.03153153
248 220 227 220 1.12727273 1.03181818
241 209 228 221 1.15311005 1.03167421
247 217 225 228 1.13824885 0.98684211
240 220 232 221 1.09090909 1.04977376
242 221 225 222 1.09502262 1.01351351
average 244.333333 215.222222 228.666667 221.7777778 1.13578757 1.03129222
std. Dev 3.5 4.99444135 2.6925824 2.818589088 0.03022589 0.02251282
p 3.6661E-05

The T Test comes to the same conclusion as my eye — the colors are different!
The results of a second experiment were negative. When I mixed dish detergent with the soda and whipped it up using my nifty milk frother, the resulting foam bubbles did not turn blue. This suggests that my hypothesis advanced in the first posting about blue dye having the ability to diffuse into bubbles is not correct.
So what does this mean? The conclusion I have come to has to do with a technique known as column chromatography. Column chromatography passes a mixture through a tube that is packed with a material that has an affinity for some of the molecules in the mixture. This will slow the molecules down a little, so as water is washed through the tube the molecules come out the other end at different times. Typically a person will collect a few drops of water into a series of tubes (these are called “fractions”). Then you test each fraction to see what is in it. Using a variety of different columns you can actually purify things pretty well.
Anyhow, I had noticed that the foam only turns blue after the bubbles on top had been bursting for a while. This causes those bubbles near the top to turn back into liquid and flow through the foam underneath. The foam bubbles underneath act like a column, to which the blue dye apparently has a higher affinity than the red dye.
Sorry, I can’t write now – West Wing is starting!


The Pinhole Camera

You may know that I work for a software company that is highly respected for its digital imaging products. As a result, I’ve been trying to learn more about photography. For example,

Near Snail Lake, MN

As it turns out, there is a lot of science in photography. It is much more than I can discuss in a single entry — there is the chemistry of film, optics, exposure, not to mention the artistic concepts such as composition, mood, etc… Besides, I’m not much of an expert yet so I’m not really qualified to discuss most of that (yet!).
So let’s start out by considering the worlds simplest camera, the Pinhole camera. Once we understand that camera and its limitations, we can move on to understand why people use other kinds of cameras most of the time.
A pinhole camera is quite simple. It consists of a box with a large piece of photographic paper mounted at one end, and a very tiny hole that can be covered up at the other end.
A Pinhole Camera

We all know that light moves in a straight line. By using a tiny pinhole, each point on the film only sees a tiny piece of the outside world. I’ve drawn to small grey lines showing how the light from the tree passes through the pinhole to a corresponding point on the film. One incidental result of this is that the image is upside down on the film.
If you make the box longer, the image will get bigger. If you don’t believe me, draw a new pinhole to the right, and trace from the back of the box to see how much of the tree you’ll see on the film. You should see less of the tree — so the image is “zoomed in”. This is one fundamental concept of photography : The longer your focal length, the more zoomed in you are. In fact, when photographers talk about lenses, the talk about the focal length. For a standard camera, a typical lens might have a focal length of 30mm. My friend Jessie’s favorite lens is a 50mm, which is a little bit more zoomed in. A “fish eye” lens might be 15mm. A telephoto lens is in the range of 75 to 300 (or more) mm. 300mm is about a foot, which starts to be a pretty awkward length of lens hang off the front of your camera.
This raises an interesting side question : Why do you need zoom, can’t you just move closer to the subject? For some things that is true, a similar effect can be achieved by moving the camera closer to the subject. But in some cases, the use of zoom provides an important tool in how an image is composed. Consider a scene with a tree and the moon on the corner of the block. You are the photographer, and you stand in the intersection using different focal lengths on your pinhole camera. For this example, I’ll assume that you adjust the position of the camera so that the tree is the same size in each picture.
The same moon and tree picture taken with a very short focal length, medium focal length and long focal length

What you notice is a striking difference in composition. With the very short focal length (e.g. “zoomed all the way out” according to our “focal length / zoom” rule) distant objects (such as the moon) appear very far away. Also, things at the perifery of your vision are more prominent in the picture, such as the street extending away to your right and left. With a very long focal length (e.g. “zoomed all the way in”), distant objects appear larger relative to close objects. Also, objects in the perfery are absent as being “zoomed in” restricts your field of view.
There is a corollary to the “focal length / zoom” rule. As the focal length gets longer, less light makes it to the film. Imagine that the tree is covered with ten christmas lights. If the whole tree is in frame, then ten christmas tree lights worth of light is making it to the film. If you zoom in to show only light, then one tenth as much light is making it to the film. Just because that light looks bigger doesn’t mean that it gets any brighter.
This brings us to the final issue I wanted to talk about: exposure. Exposure means how much light makes it to the film. Exposing film is a chemical reaction, and a specific amount of light is required to make the reaction work. Too much light will make the picture look washed out, or “over exposed”. Too little light will make the picture dark, or “under exposed”. A pinhole camera has four ways to adjust exposure. You can use a shorter focal length to get more light, but at the cost making distant objects look tiny (as discussed above). You can expose the film for a longer length of time (it is not uncommon for pinhole cameras to have exposures lasting minutes or even hours). Long exposures make it hard to take pictures of anything that moves, however. (Early cameras were really little better than pinhole cameras, and took several minutes to expose. This is why pictures from that time are so serious — it is not possible to hold a smile for several minutes without moving, so people held a relaxed pose that they could stay in for several minutes.) You can put a filter in front of the pinhole to reduce the amount of light getting in. You can also alter the chemistry of the film (this is called the ISO of the film) to change how reactive it is to light.
The long exposure time of a pinhole camera is the primary reason that people invented lenses. I’ll save a discussion of lenses for another entry, however.


Foggy lake

Jesse and I stopped by Lake Johanna on our way to work this morning. The fog was visually stunning:

Fog forms over bodies of water when the atmospheric temperature drops below the water temperature. The vapor pressure of the warm water is greater than the vapor pressure of water vapor in the air. Thus there is a movement of water into the air, which immediately condenses as it mixes and gets cold. Sun “burns off” fog by raising the temperature of the air. As the air temperature increases it’s vapor pressure also increases — which means that it can hold more water.