Beacons using a PIC10F200 August 14, 2015
Before there were standards like iBeacon and Eddystone we had to “roll our own.” This is a primitive beacon using a PIC10F200 (8pin DIP) along with a simple 315MHz OOK transmitter. Later versions, not shown here, use SDR.
beacon.asm
This is written in PIC assembly. It simply transmits my FCC Call sign with a number tacked on the end. Production versions would substitute a UUID and checksum in place of my Call sign. The signal is intentionally weak, we only want to know if the watch (wearable device) is within a few meters. Battery life is important too, this thing should be good for about 57 years on a couple AAA batteries.
The gist of what this code does is to set a timer and go to sleep. When the timer expires the chip wakes up and increments some counter (the timer durations are rather short) and we need some randomization to minimize the possibility of interference betwixt proximal beacons1. If it’s time to send a burst, my Call sign, then it does so, resets the counter and timer and goes back to sleep. The idea is to spend as much time asleep as possible to conserve batteries.
beacon.asm
; FILE: beacon.asm
; AUTH: Tim Allen
; DATE: 1.0 - 18 April `11
; DESC: Controls a 315MHz radio, sends a
; serial number periodically (~30s)
; NOTE: Tested on PIC10F200
include <p10f200.inc>
list p=10F200
radix hex
__config _WDT_ON
;----------------------------------------------------------------------
; macro(s)
xmit macro r0
call txstart
movlw r0
call txhex
call txstop
endm
;----------------------------------------------------------------------
; ram "variables"
cblock 0x10
warmcnt ; counter for radio warm-up
count0 ; counter for main prog
txcount ; counter for tx0 and tx1
hex ; scratch for txhex
xmitcnt ; bit counter for txhex
lfsr ; pseudo-random number
endc
;----------------------------------------------------------------------
org 0x000
goto main
main ;code start
movlw b'11001111' ; set watchdog post-scaler
option
movlw b'11111000' ; 0,1,& 2 output
tris GPIO ; set GPIO I/O
btfss STATUS,NOT_PD
goto run
;----------------------------------------------------------------------
powerup ; initialize things
clrwdt ; clear watchdog timer
movlw b'00000000'
movwf GPIO ; turn GPIOs off
movlw 0x05
movwf count0 ; initialize the counter
goto burst ; send an initial burst
;----------------------------------------------------------------------
run ; is it time for a burst?
decfsz count0,F
sleep ; no go back to sleep
; generate a pseudo-random number
bcf STATUS,C
rrf lfsr,W
btfsc STATUS,C
xorlw 0xb4
movwf lfsr
andlw 0x03 ; limit the random to 0-3
movwf count0 ; set the counter
incf count0,F ; just make sure it's not 0
burst ; send a beacon string
bsf GPIO,2 ; power-up the radio
movlw 0xff
movwf warmcnt
warmlp decfsz warmcnt,F ; give it a sec
goto warmlp
xmit 'K'
xmit 'G'
xmit '4'
xmit 'E'
xmit 'U'
xmit 'K'
xmit '0'
xmit '0'
xmit 0xf5
bcf GPIO,2 ; power-down the radio
sleep ; go back to sleep
txstart; transmit a start
bsf GPIO,0 ; trigger the scope
call tx0
retlw 0x00
txstop ; transmit a stop
call tx1
bcf GPIO,0 ; un-trigger the scope
retlw 0x00
tx1 ; transmit a 1 bit subroutine
bcf GPIO,1
movlw d'185'
movwf txcount
tx1lp nop
decfsz txcount,F
goto tx1lp
retlw 0x00
tx0 ; transmit a 0 bit subroutine
bsf GPIO,1
movlw d'180'
movwf txcount
tx0lp nop
decfsz txcount,F
goto tx0lp
retlw 0x00
txhex ; transmit a hex
movwf hex
movlw 0x08 ; set the counter
movwf xmitcnt
nxtop rrf hex,F
btfsc STATUS,C
goto x1
call tx0 ; zero
goto nxbtm
x1 call tx1 ; one
nxbtm decfsz xmitcnt,F
goto nxtop
retlw 0x00
end
makefile
beacon.hex: beacon.asm
gpasm beacon.asm
burn:
pk2cmd -PPIC10F200 -J -R -F beacon.hex -M
clean:
rm *.hex *.lst *.cod
-
This is a bit tough to explain so bare with me. The oscillators on these things are not precise. So imagine we were to send a burst every 30 wake-ups (e.g. no randomization). Okay so lets say you have two of these close together and we put batteries in them at the same time. Now every 30 wake-ups they both wake up and clobber each other (the wearable can’t hear either because they “talk” over each other). Now eventually, because the oscillators are imprecise, they drift apart but that may take hours; therefore, we introduce some randomization to keep them asynchronous. I’m skipping some nuance here but I hope you get the idea. ↩