About |
This was one of my bigger challenges — converting a Hawkeye MS14A PIR motion sensor, originally running a PIC12C508 with X10 RF protocol, into a fully Thorian-compatible sensor. The goal was to retain the existing PIR hardware and repurpose the casing, while rewriting the microcontroller code entirely to support the Thorian wireless protocol. |
|
Background & Research |
The Hawkeye is a remarkably efficient motion sensor. Initial testing showed:
~50 μA idle at 3 V
~450 μA when active
Up to 2 mA during RF transmission bursts
It uses a PIC12C508 8-pin microcontroller, which handles PIR input, daylight sensing, and X10 RF communication. Interestingly, several pins on the PIC serve dual functions, including both I/O and communication. This made tracing and decoding the firmware slightly more involved.
My Firmware:
Written in Assembly (main.asm) with X10 routines in transRF10.inc
Delay and timing logic in delays02.inc
Final compiled file: PIC12F1501.hex
|
Circuit info |
The unit is powered by 2× AAA batteries (3 V total)
Motion is detected using a PIR element amplified by a TLC27 op-amp
Ambient light sensing is done via an LDR
RF transmission is handled by a discrete RF oscillator + transistor stage
The PCB shows creative use of shared signal lines
Photos and reverse-engineering annotations:
|
Signal mapping |
 |
|
 |
Conversion process |
Desoldered the PIC12C508 and replaced it with a socket for flexibility.
Wired up the PIC12F1501 for development and programming using a PICkit 3.
Carefully traced and documented all signal paths from the original schematic.
Used original hardware:
PIR amplifier (TLC27 op-amp)
RF transmitter circuit
Green and red LEDs
AAA battery power
Wrote new code for the PIC12F1501 that:
Reads PIR motion and ambient light
Responds with encoded Thorian RF packets
Sleeps between detections for ultra-low power |

|
|
|
Firmware and Integration
The new firmware is 100% custom-written in Assembly for the 12F1501. It maintains the same ultra-low power profile by sleeping most of the time and only waking on motion.
Key features:
Idle power: ~50 μA
Active sense: ~450 μA
TX burst: ~2 mA (short duration only)
Protocol: Fully compatible with Thorian
NOTE: The original main.asm and X10 code (transRF10.inc) are preserved for future reference and disassembly comparison.
|
|
View Thorian Firmware (main.asm)
; 12F1501 Hawkeye MS14A Replacement Firmware - Thorian Protocol
; Author: Ian Thorington (2018)
; Version: v05
; Description: Custom firmware to replace X10 with Thorian RF protocol.
; Runs ultra-low power PIR sensor with interrupt and RF transmission.
; === CONFIGURATION ===
#include p12f1501.inc
LIST P=PIC12F1501,ST=OFF,R=DEC
errorlevel -302
__CONFIG _CONFIG1 , _FOSC_INTOSC & _WDTE_SWDTEN & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOREN_OFF & _CLKOUTEN_OFF
__CONFIG _CONFIG2 , _WRT_OFF & _STVREN_OFF & _BORV_HI & _LPBOR_OFF & _LVP_OFF
; === VARIABLES ===
enablePIR EQU 0x04
TX EQU 0x05
temp EQU 0x21
twoloops EQU 0x22
bytes EQU 0x23
temperatureH EQU 0x24
temperatureL EQU 0x25
RFaddress EQU 0x26
RFdata EQU 0x27
RFdataComp EQU 0x28
count EQU 0x29
counter EQU 0x2A
devicetype EQU 0x2B
deviceaddress EQU 0x2C
data1 EQU 0x2D
delayCounter EQU 0x2E
delayValue EQU 0x2F
ADDRH EQU 0x70
ADDRL EQU 0x71
; === RESET VECTOR ===
RST code 0x0
goto Start
NOP
NOP
NOP
GOTO PIR_TRIPPED
; === MAIN CODE SEGMENT ===
PGM code
Start:
; === Oscillator Setup ===
BANKSEL OSCCON
MOVLW b'01101010' ; 4 MHz internal clock
MOVWF OSCCON
Stable:
BTFSS OSCSTAT, HFIOFR
GOTO Stable ; Wait until oscillator stable
; === Watchdog Setup ===
BANKSEL WDTCON
MOVLW B'00011100' ; 16 sec (simulator), enable WDT
MOVWF WDTCON
; === I/O Setup ===
BANKSEL TRISA
MOVLW B'00001011' ; Configure RA pins: RA5-TX, RA4-enablePIR, etc.
MOVWF TRISA
BANKSEL ANSELA
CLRF ANSELA ; All digital
BANKSEL 0
BSF LATA, 2 ; Red LED off (active low)
BCF LATA, enablePIR ; Enable PIR (active low)
BCF LATA, TX ; TX pin low
; === Interrupt Setup ===
BANKSEL IOCAP
BSF IOCAP, IOCAP0 ; Interrupt on rising edge RA0 (PIR)
BANKSEL INTCON
BSF INTCON, IOCIE ; Enable IOC interrupt
BCF INTCON, IOCIF ; Clear interrupt flag
BSF INTCON, 7 ; Enable global interrupt
BANKSEL 0
; === Initial RF Packet ===
MOVLW D'4' ; THIS IS THE DEVICES ADDRESS AND SHOULD BE SET TO ANYTHING BETWEEN 1-254
MOVWF deviceaddress
MOVLW D'1'
MOVWF temperatureL
MOVLW D'0'
MOVWF temperatureH
CALL RFtx ; Send boot/test packet
PIRLOOP:
NOP
NOP
tired:
NOP
NOP
MOVLW 200
CALL MSdelay
SLEEP ; Go to sleep, wake on interrupt
NOP
NOP
NOP
GOTO PIRLOOP
; === Interrupt Handler ===
PIR_TRIPPED:
BANKSEL INTCON
BCF INTCON, IOCIE ; Disable interrupt
BANKSEL 0
CALL RFtx ; Send RF message first (before LED)
BCF LATA, 2 ; RED LED ON
checkPIR:
BSF LATA, enablePIR ; Disable PIR (active low logic)
CALL secondDelay
BSF LATA, 2 ; RED LED OFF
BCF LATA, enablePIR ; Enable PIR again
BTFSC PORTA, 0
GOTO checkPIR ; Wait for PIR to settle
; === Extra RF Notification ===
BSF LATA, enablePIR
MOVLW 200
CALL MSdelay
MOVLW 200
CALL MSdelay
MOVLW 255
CALL MSdelay
CALL RFtx
; === Sleep Until Next Trigger ===
BANKSEL WDTCON
BSF WDTCON, SWDTEN ; Enable watchdog (8 sec)
CLRWDT
SLEEP
NOP
NOP
NOP
BCF WDTCON, SWDTEN ; Disable watchdog
; === Re-enable Interrupts ===
BANKSEL INTCON
BSF INTCON, IOCIE
BCF INTCON, IOCIF
BANKSEL IOCAF
BCF IOCAF, 0
BANKSEL 0
BCF LATA, enablePIR ; Re-enable PIR
RETFIE
; === Includes ===
include delays02.inc
include transRF10.inc
END
|
View RF Transmit Routine (transRF10.inc)
; Thorian RF Transmit Routine
; Sends a structured RF packet:
; - Preamble for AGC sync
; - Address byte
; - Data bytes (e.g. temperatureL, temperatureH)
; - Stop bit
; Uses LATA.5 as the RF output pin (change if needed)
RFtx: ; Start of transmission
; === Preamble ===
; AGC burst: 9ms on, 4.5ms off (to wake up/sync receiver)
bsf LATA, 5 ; Set RF pin HIGH
movlw D'18' ; 9ms
call MSdelay
bcf LATA, 5 ; Set RF pin LOW
movlw D'9' ; 4.5ms
call MSdelay
; === Address Byte ===
movf deviceaddress, w ; Load device address
movwf data1
call doRFbyte
; === Data 1: temperatureL ===
movf temperatureL, w
movwf data1
call doRFbyte
; === Data 2: temperatureH ===
movf temperatureH, w
movwf data1
call doRFbyte
; === Data 3: Unused (send blank) ===
clrw
movwf data1
call doRFbyte
; === Stop Bit ===
bsf LATA, 5
movlw D'33' ; ~336us pulse
call uSdelay
bcf LATA, 5
; Optional: Wait before retransmitting
movlw D'81' ; 40ms delay
call MSdelay
bcf LATA, 5
return
; ================================
; Transmit 1 byte + its inverse
; Each bit: ~330us HIGH, then delay based on bit value
doRFbyte:
movlw 0x02 ; 2 loops: original + inverted byte
movwf bytes
byteloop:
movlw 0x08 ; 8 bits
movwf count
rfloop:
bsf LATA, 5 ; Start bit (HIGH)
movlw D'33' ; ~330us
call uSdelay
bcf LATA, 5 ; End bit (LOW)
movlw D'23' ; Default off time (~230us for 0)
btfsc data1, 7 ; If bit7 is 1, skip next
movlw D'80' ; Longer off for 1 bit (~800us)
call uSdelay
rlf data1 ; Rotate left (get next bit into bit7)
decfsz count, f
goto rfloop
comf data1, f ; Invert byte for second pass
decfsz bytes, f
goto byteloop
return
|
|
|
Final Result
|
The converted Hawkeye now acts as a drop-in, battery-powered motion sensor for my Thorian ecosystem.
No physical changes to the casing or lens
All components reused
Completely silent and efficient
Much lower power than even the ESP-based sensors
Now emits Thorian packets upon motion detection, with light-level gating |
|
Files |
The link to the assembly and hex files are here
IMPORTANT - The device address is set to 4. To change this, you will need to change it in the ASM file and recomplile the code.
Other Thorian devices include an ICSP header which allows easy reprogramming. This unit does not, so changes require desoldering the re-flashing the chip.
|
Unfortunately no Labcenter Proteus simulation this time. The 12F1501 chip is too new and isn't supported in my version of Proteus.
It took a long time to write the code for this. |
|
|
|
|