; Keith Neufeld ; 27-Feb-2006 ; ; LogoChip program to demo measuring ambient light level ; with CdS photocell wired from LogoChip port A1 to +5V ; and 1K resistor wired from A1 to GND. ; ; When light level suddenly becomes dimmer, trigger audio playback ; using Radio Shack 276-1323 20-second recording modules ; with play buttons wired to LogoChip ports C6 and C7. ; Play buttons are active low. ; Port assignments for the photocell and audio units constants [ [cds-port porta] [cds-ddr porta-ddr] [cds-bit 1] [squawk-port portc] [squawk-ddr portc-ddr] [squawk-left-bit 6] [squawk-right-bit 7] ] ; Array for averaging brightness global [array0 array1 array2 array3 array4 array5 array6 array7 array-index] constants [ [array-base 2] [array-len 8] ] ; Current brightness, sum of recent brightness, average recent brightness global [bright sum-bright avg-bright] ; Calculated brightness values that indicate dimming global [threshold-shady threshold-dark] ; At powerup, run the main program. to powerup startup end ; At startup, clear the array storage space, initialize some ; global variables, and configure the I/O ports. to startup init-array init-vars init-squawk-port init-cds-port prs "starting watch-brightness end ; Loop forever, taking samples and watching for dimming. global [already-shady already-dark] to watch-brightness loop [ ; Calculate what fractions of previous brightness ; constitute being dim calc-thresholds ; Get current brightness read-bright ; The following logic for different brightness conditions ; is carefully arranged to make a successful test exclude ; success on subsequent tests. I would have preferred to ; write this using ; ; if [ block 1 ] ; elseif [ block 2 ] ; elseif [ block 3 ] ; ; but LogoChip Logo doesn't support that, and I got cranky ; nesting the conditional blocks three deep using the syntax ; that _is_ supported. ; ; Caveat maintainer. ; If we're getting brighter, if bright > avg-bright [ ; Start paying attention to getting dimmer again setalready-dark 0 setalready-shady 0 ] ; If we're significantly darker than before, if bright < threshold-dark [ ; And we haven't already done something about it, if not already-dark [ ; Then cause an event dim-a-lot-event ; And remember that we're already dark ; and don't need to trigger another event. setalready-dark 1 setalready-shady 1 ] ] ; If we're a little darker than before, if bright < threshold-shady [ ; And we haven't already done something about it, if not already-shady [ ; Then cause an event dim-a-little-event ; And remember that we're already shady ; and don't need to trigger another event. setalready-shady 1 ] ] ] end ; Event routine for when slight dimming is detected to dim-a-little-event prs "|dimming a little| ; Play the message from the right speaker. squawk squawk-right-bit ; Give it a couple of seconds to finish. wait 20 end ; Event routine for when significant dimming is detected to dim-a-lot-event prs "|dimming a lot| ; Play the message from the left speaker. squawk squawk-left-bit ; Give it a couple of seconds to finish. wait 20 end ; Clear the array. to init-array setarray-index 0 repeat array-len [ setglobal (array-base + array-index) 0 setarray-index (array-index + 1) % array-len ] end ; Initialize global variables. to init-vars setsum-bright 0 setalready-shady 0 setalready-dark 0 end ; Configure the audio trigger I/O port. to init-squawk-port ; Set left and right triggers off (active low, so set high) setbit squawk-left-bit squawk-port setbit squawk-right-bit squawk-port ; Set left and right triggers as outputs clearbit squawk-left-bit squawk-ddr clearbit squawk-right-bit squawk-ddr end ; Configure the photocell I/O port. to init-cds-port ; Set photocell port as input setbit cds-bit cds-ddr ; Give time for the operator to get their hand out of the way ; and find out how bright the room can be repeat 10 [ ; Read the current brightness and store rolling average read-bright ;prs "average ;print avg-bright ] ;prs "|final average| ;print avg-bright end ; Trigger the external playback modules ; Parameter: which module to trigger to squawk :squawk-bit ; Trigger it (active low, so set low) clearbit :squawk-bit squawk-port ; Wait a smidge to be sure it registers wait 1 ; Clear the trigger (active low, so set high) setbit :squawk-bit squawk-port end ; Read the brightness and work it into a rolling average. ; Uses a ring buffer to compute the rolling average. If you know what ; that means, there's not much I can teach you about LogoChip Logo. to read-bright ; Read current brightness setbright read-ad cds-bit ;prs "|current brightness| ;print bright ; Roll off oldest value from rolling average and add current ; Parentheses around first two operands are necessary-- ; returns random result without setsum-bright (sum-bright - global (array-base + array-index)) + bright ; Save current brightness and advance history pointer setglobal (array-base + array-index) bright setarray-index (array-index + 1) % array-len ; Calculate recent average brightness, rounding the fraction setavg-bright (sum-bright + (array-len / 2)) / array-len ; A/D converter seems to require .2 sec between readings wait 2 end ; Calculate thresholds of dimming based on recent average brightness. ; Multiply then divide because fractions become 0 in integer arithmetic. to calc-thresholds setthreshold-shady (9 * avg-bright) / 10 ;prs "|shady threshold| ;print threshold-shady setthreshold-dark (5 * avg-bright) / 10 end