radiosparks
Well-known member

After watching The Day the Earth Stood Still (1951) for the gazillionth time, I was inspired by the gesture control panel in Klaatu’s ship.
My code library is now pretty solid, thanks to digging through the Forum for all the snippets I needed. I mashed together a little gesture control setup for myself. There’s a lot of silicon in this project, but the wiring is surprisingly simple.
The main microcontroller is the infamous PICAXE 08M2+. Right next to it is a VL53L0X Time-of-Flight (ToF) laser-ranging module, which also handles gesture recognition via I2C. Beside that is a WS2801—a PWM constant-current LED driver with an integrated RGB LED, controlled by the MCU using bit-banged ports. For this to work, the PICAXE runs at 16MHz. The RGB LED uses logarithmic brightness ramping stored in EEPROM.
In this snippet, gesture detection toggles the LED:
- Move toward the sensor → LED turns on
- Move away → LED turns off
- If the LED stays on, it times out after ~10 seconds
I’ve got one precious pin left—C.3. Perfect for a future IR remote-controlled lighting effect.
Memory usage is super low. Syntax Check reports 183 bytes, plus 32 bytes of EEPROM for the brightness table.
Code:
#rem
---[ Program Description ]---------------------------------
NITELITE V2.0A ? Gesture-Controlled RGB LED using
PICAXE 08M2+ Microcontroller
VL53L0X Time-of-Flight (ToF) laser-ranging
WS2801 PWM constant current LED driver
===========================================================
PICAXE Editor ... Version 6.2.1.0
Library File ... 08M2_WS2801_RGB_LED_LIGHTHOUSE_FLASH.bas
Library File ... PICAXE_08M2_VL53L0X_TOF V2.bas
Author ... radioSPARKS [VE3XRM]
Started ... rhb.20250828
Nitelite ... rhb.20250903 Refactored code for ToF Nitelite
===========================================================
Memory Used: 183 BYTES plus 32 BYTES for EEPROM - rhb.20250904
#endrem
' ---[ Compiler Directives ]--------------------------------
#picaxe 08M2
setfreq M16 ; It's "The need for Speed", to Bit-Bang the WS2801
#no_data ; REM to store EEPROM data in the PICAXE chip
' ---[ MCU PORT Connections ]-------------------------------
'// WS2801
symbol SDataPIN = pinC.0 ; SDI PIN #7 - used to output 1 bit of data to WS2801 Data-In Pin
symbol S_Data = C.0 ; SDI - also defined this way to use with the LOW command in Init:
symbol S_Clock = C.4 ; CKI PIN #3 - clock to WS2801 Clock-In Pin
'// VL53L0X
symbol SDA = c.1 ; I2C Serial Data on PIN #5
symbol SCL = c.2 ; I2C Serial Clock on PIN #6
' ---[ Constants ]------------------------------------------
symbol Step_Delay = 10 ; 4000 for a 1 sec delay at 16 MHz on M2 MCU
symbol RAMbaseADDR = $08 ; start of LED data - stored in B8, B9, and B10 RAM registers
symbol NUM_LED = 3 ; number of individual LEDs in one RGB LED (RED,GREEN,BLUE)
symbol stepCount = 31 ; number of EEPROM steps in brightness
' ---[ Variables ]------------------------------------------
'// WS2801
symbol LED_Data = b0 ; NOTE: BIT register for subroutine: sendData
symbol MemPTR = b2 ; RAM memory pointer for LED RGB Byte Data
symbol sendBYTE = b3 ; BYTE counter for data to WS2801
symbol ledTimer = w3 ; LED Auto OFF Timer
symbol RED_Data = b8 ; RAM Data byte for RED
symbol GREEN_Data = b9 ; RAM Data byte for GREEN
symbol BLUE_Data = b10 ; RAM Data byte for BLUE
'// VL53L0X
symbol DISTANCE = w2 ; distance in mm recorded in registers (b5:b4) as word w2
symbol hiByte = b5 ; high byte data from VL53L0X
symbol loByte = b4 ; low byte data from VL53L0X
'symbol ircmd = b13 ; not used
; - reserved [Future Feature!] to add IR remote control - rhb.20250903
' ---[ EEPROM Data WS2801 ]---------------------------------
#rem - from stackoverflow
5 bit CIE Lightness to 8 bit PWM conversion Math
L* = 116(Y/Yn)^1/3 - 16 , Y/Yn > 0.008856
L* = 903.3(Y/Yn), Y/Yn <= 0.008856
#endrem
'// RAMP LONG 32 logarithmic values - RAMP OFF/ON Data
EEPROM $00, ( 0, 1, 2, 3, 4, 5, 7, 9)
EEPROM ( 12, 15, 18, 22, 27, 32, 38, 44)
EEPROM ( 51, 58, 67, 76, 86, 96,108,120)
EEPROM (134,148,163,180,197,216,235,255)
'// RAMP SHORT 19 logarithmic values - RAMP OFF/ON/OFF Data for a quick blink
'EEPROM $00, (0,1,2,3,7,15,31,63,127,255,127,63,31,15,7,3,2,1,0)
' ---[ Program Start ]--------------------------------------
' ---[ Initialization ]-------------------------------------
Init:
' WS2801
Low S_Data ; set pin as an output
Low S_Clock ; set pin as an output
' VL53L0X
hi2csetup i2cmaster, 0x52, i2cfast_16, i2cbyte
' ---[ Program Code ]---------------------------------------
Main:
do
' ---[ Toggle LED Controller ]---
call readDistance
if DISTANCE > 50 and DISTANCE < 150 and MemPTR = 0 then
call LED_ON ; LED ON only when object closer than 150mm and LED is OFF
ledTimer = time + 10 ; Set Auto-off LED Timer - currently for demo is 10 seconds
elseif DISTANCE > 150 and DISTANCE < 200 and MemPTR > 0 then
call LED_OFF ; LED OFF when object moves away and LED is ON
else
if time > ledTimer and MemPTR > 0 then
call LED_OFF ; Auto-off after timeout - rem if using dim over time feature
' Slowly dim the LED over a long period of time
' - starts after the timeout - takes a little over 1 minute to be OFF
'dec MemPTR
'call assignColour
'ledTimer = time + 1
end if
endif
loop
' ---[ END Program Code ]-----------------------------------
end ; I don't know why putting an END here saves 2 BYTES of memory, must be a compiler thing - rhb?
' ---[ Subroutines ]----------------------------------------
LED_ON:
MemPTR = 0 ; SET EEPROM data pointer to the first location
do
inc MemPTR
call assignColour
loop until MemPTR = stepCount
return
LED_OFF:
MemPTR = stepCount ; SET EEPROM data pointer to the last location
do
dec MemPTR
call assignColour
loop until MemPTR = 0
return
assignColour:
'// This could be used for future features, such as colour blending
read MemPTR, LED_Data
RED_Data = LED_Data
GREEN_Data = LED_Data
BLUE_Data = LED_Data
call sendData
return
sendData:
'// BIT-BANG data to the WS2801 chip
bptr = RAMbaseADDR ; set start RAM address for RGB LED data
for sendBYTE = 1 to NUM_LED
LED_Data = @bptrinc ; load the data into b0 to extract each bit
SDataPIN = bit7 : PulsOut S_Clock, 1 ; msb first
SDataPIN = bit6 : PulsOut S_Clock, 1
SDataPIN = bit5 : PulsOut S_Clock, 1
SDataPIN = bit4 : PulsOut S_Clock, 1
SDataPIN = bit3 : PulsOut S_Clock, 1
SDataPIN = bit2 : PulsOut S_Clock, 1
SDataPIN = bit1 : PulsOut S_Clock, 1
SDataPIN = bit0 : PulsOut S_Clock, 1 ; lsb last
next sendBYTE ; continue until all bytes sent
return
readDistance:
'// I2C data to VL53L0X chip
hi2cout 0x00,(0x01) ; start and re-arm
pause 25 ; chip init settle pause
hi2cin 0x1e,(hiByte,loByte) ; read the range in mm from 0x1e
return
' ---[EOF]---

NOTE: PEBBLE has been silently updated to version 4.1, with most changes tucked away in code refactoring.
Attachments
Last edited: