In this
article:
Source Code
License
Navigation:
HomeHardware
Software
Techniques
Controllers
Reviews
Index
Description
This simple program was designed to turn an inexpensive 8 pin microcontroller into a self-contained low power transmitter. The goals of that were described in the EELB article. Transmitting is accomblished by enhancing signal leakage into the AM band, its hardly a threat to your neighbor but it’s a great way to demonstrate how AM radios work in a fun way.
The Source Code
; ; Emergency Egg Locator Beacon ; Written 02-Nov-2004 ; Copyright (C) 2004, Charles McManis, All Rights Reserved ; ; A non-exclusive, non-transferrable right to use, modify, or ; distribute is granted to non-commercial purposes. ; ; This is a fairly simple hack that is fun and educational. ; All the way back to the 1950's scientists have known that ; putting an AM radio near the computer allowed you to "pick up" ; interference related to what was going on inside. Some creative ; individuals figured out they could make timing loops that actually ; generated tones such that music could be played. ; ; This program brings that hack into the 21st century (or at least ; late 20th century) using a PIC12F6xx chip. The interesting thing ; about this chip is that it has an internal 4Mhz oscillator, that ; you can route as a divide/4 value (1Mhz) to one of its output pins. ; 1Mhz happens to be smack dab in the middle of the AM radio band. ; The other feature of PIC chips that comes into play is that they ; can drive 25mA or sink 25mA with their I/O pins. ; ; So take the 1Mhz output, modulate it with another pin, and voila' ; instant CW AM transmitter. Given an inexpensive AM radio the signal ; generated can be picked up for 30 - 50' away. Probably more if you ; had a directional antenna on your reciever. ; ; CHUCK MCMANIS MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE ; SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING ; BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, ; FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. CHUCK MCMANIS ; SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT ; OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. ; ; TITLE "Emergency Egg Locator Beacon v1.0" LIST P=PIC12F629, C=120, N=50, R=HEX include "P12F629.inc" __FUSES _CP_OFF&_WDT_ON&_MCLRE_OFF&_INTRC_OSC_CLKOUT&_BODEN_ON&_PWRTE_ON ERRORLEVEL 2 CBLOCK H'20' BIT_COUNT:1 ; One byte of BIT Count BYTE_COUNT:1 ; Counter for bytes BIT_DELAY:1 ; Delay for one bit. BOOLS:1 ; Our flags register ISR_W ; Storage for W ISR_FSR ; Copy of the FSR ISR_STATUS ; Copy of the Status register EE_SRC ; EEPROM Source Pointer EE_DST ; EEPROM Destination Pointer EE_LEN ; EEPROM Byte count MSG_BUF ; Buffer byte for message MSG:16 ; 16 Bytes (128 bits) for our message ENDC BIT_WIDTH EQU D'100' ; 100 mS or .1 seconds BIT_FLIP EQU 0 ; Bit 0 of our bools is 'time to flip' T0_CONST_4MHZ EQU D'133' ; Constant for 1mS ticks at 4Mhz ORG H'2100' ; ; 16 Bytes of Message ; in this case EELB ALPHA ONE ; ; EGG_MSG: ; B'01234567' ; E E LLLLLLLLLLLLL BBBBBBBBBBBBB DE B'10001000',B'10111010',B'10001110',B'10101000' ; AAAAA LLLLLLLLLLLLL PPPPPPPPPPPPP DE B'00010111',B'00010111',B'01010001',B'01110111' ; PP HHHHHHHHHHH AAAAAAAAA OOOOOO NNNNNNNNN E DE B'01000101',B'01010001',B'0111000', B'00010101',B'00011101',B'00010000' DE B'00000000' ; EGG_MSG_SIZE EQU $-EGG_MSG ; ; EEREAD macro ; Written 12-Apr-2002, Chuck McManis ; ; Uses the temporary variable EE_LEN, EE_SRC, and EE_DST ; During read, Source is EEPROM and Destination is RAM ; ; Read a block of EEPROM and store it in RAM ; Assumes RAM block is in BANK0. ; EEREAD MACRO SRC_ADDR, DST_ADDR, LEN LOCAL RLOOP MOVLW LEN ; Number of bytes to copy MOVWF EE_LEN ; Store the byte count. MOVLW SRC_ADDR ; Get the source address in EEPROM MOVWF EE_SRC ; Store it here. MOVLW DST_ADDR ; Get the destination address MOVWF EE_DST ; Store it here. RLOOP: MOVF EE_DST,W ; Get byte destination MOVWF FSR ; Store it in the FSR BSF STATUS, RP0 ; Switch to bank 1 MOVF EE_SRC,W ; Address to read MOVWF EEADR ; Start address BSF EECON1, RD ; Read the byte MOVF EEDATA, W ; Assume a single cycle read? BCF STATUS, RP0 ; Back to bank 0 MOVWF INDF ; Store in Destination INCF EE_SRC,F ; Next source address INCF EE_DST,F ; Next destination address DECFSZ EE_LEN,F ; Decrement the count GOTO RLOOP ; Loop if not done. ENDM ORG H'0000' INIT: GOTO MAIN ; ; The only interrupt source in this program is timer0. I've empirically ; determined a 'reload' value such that the interrupts occur at approximately ; 1mS intervals. If we toggle a pin, the pin generates a squarewave with a ; frequency of approximately 500Hz (somewhere above middle A 440 in the scale) ; This pin is tied externally to a voltage divider to modulate the CLKOUT ; signal. ; ; Additionally there is a counter for determining one "bit" width. Each bit ; is held for approximately .1s so three "one" bits in a row generates a ; .3s tone and a single one bit generates a .1s tone. ; ORG H'0004' ISR_ENTER: MOVWF ISR_W ; Preserve W SWAPF STATUS,W ; And Status register CLRF STATUS ; Force Page 0 MOVF FSR,W ; Get the FSR MOVWF ISR_FSR ; Check to see if it is Timer 0 interrupting us (it should be!) BTFSS INTCON, T0IF GOTO ISR_EXIT ; Else exit BCF INTCON, T0IF MOVLW T0_CONST_4MHZ ; 1Khz interrupt 500hz waveform MOVWF TMR0 BTFSC BOOLS, BIT_FLIP ; If this is true we're waiting for next bit GOTO ISR_EXIT ; next ... CLRWDT BTFSS MSG_BUF,7 ; Check high order bit of MSG buffer GOTO NO_TONE ; If zero don't generate a tone ; ; Generates a tone ; Should generate 500 hz on GPIO.5 (0x20 is 00100000b) ; TONE: MOVF GPIO,W ; Read the GPIO Register XORLW H'20' ; Toggle GPIO,0 MOVWF GPIO ; Write it out BSF GPIO,GPIO2 ; Turn on GPIO2 GOTO BIT_TIMER NO_TONE: MOVF GPIO,W ; Get GPIO pins IORLW H'20' ; Set output high MOVWF GPIO ; Write it out BCF GPIO,GPIO2 ; Turn off GPIO2 ; ; run down the clock on the bit timer. ; BIT_TIMER: DECFSZ BIT_DELAY ; This is the beep timer GOTO ISR_EXIT ; Not timed out. MOVLW BIT_WIDTH MOVWF BIT_DELAY BSF BOOLS, BIT_FLIP ; Next bit please ; ; Worst case the ISR takes about 26 instructions or 26 uS out of 1mS ; ISR_EXIT: MOVF ISR_FSR,W ; Get FSR register MOVWF FSR ; put it back into FSR SWAPF ISR_STATUS,W ; Pull Status back into W MOVWF STATUS ; Store it in status SWAPF ISR_W,F ; Prepare W to be restored SWAPF ISR_W,W ; Return it, preserving Z bit in STATUS RETFIE ; ; Initialize Timer 0 to drive everything ; MAIN: MOVLW BIT_WIDTH ; Basic bit width MOVWF BIT_DELAY ; Store it BSF BOOLS, BIT_FLIP ; CLRF GPIO ; Clear GPIO Bits BSF GPIO, GPIO5 CLRF MSG_BUF ; Make sure MSG byte 0 is clear MOVLW 07h ; Make GPIO bits digital MOVWF CMCON ; Like so. BSF STATUS, RP0 ; Set Bank 1 CALL H'03FF' ; Get calibration constant MOVWF OSCCAL ; Store it MOVLW B'0000010' ; Set TMR0 prescaler to 8 MOVWF OPTION_REG ; Store it in the OPTION register BSF INTCON, T0IE ; Enable Timer 0 to interrupt BCF INTCON, T0IF ; Reset flag that indicates interrupt MOVLW 0 ; Make GPIO all outputs MOVWF GPIO ; Using the TRISO register in bank 1 BCF STATUS, RP0 ; Now in bank 0. BSF INTCON, GIE ; Enable interrupts ; ; The purpose of this code is to read out the data bits in ; EEPROM and then one by one put them out on the LED pin ; (GPIO5 in this case). To send morse, the convention of three ; one bits is a dash, one one bit is a dit, and three zero bits ; are a space. ; 128 bits lets you send about 10 characters in morse. ; ; In C code, this is what is going on: ; ; memcpy(eeprom, msg, 16); /* get message from EEPROM */ ; for (i = 0; i < 16; i++) { ; msg = data[i]; ; flip = 0; /* reset bit timer */ ; for (j = 0; j < 8; j++) { ; while (!flip); /* wait time allotment */ ; msg = msg >> 1; /* shift out a bit */ ; } ; } ; msg = 0; ; halt(); ; OUTER: ; ; Copy message from EEPROM to the MSG memory ; EEREAD EGG_MSG, MSG, EGG_MSG_SIZE ; Read msg bytes out of the EEPROM MOVLW EGG_MSG_SIZE MOVWF BYTE_COUNT MOVLW MSG MOVWF FSR MSG_LOOP: MOVF INDF,W ; Read message byte MOVWF MSG_BUF ; Store it in the message buffer byte MOVLW D'8' ; Send 8 bits MOVWF BIT_COUNT ; out. BIT_LOOP: BCF BOOLS, BIT_FLIP ; Send next bit out BTFSS BOOLS, BIT_FLIP ; Wait for it to flip GOTO $-1 RLF MSG_BUF,F ; Rotate next bit out DECFSZ BIT_COUNT,F GOTO BIT_LOOP ; INCF FSR,F ; Point to next byte of message DECFSZ BYTE_COUNT,F ; Until all sent GOTO MSG_LOOP ; ; Now ideally the chip should go to sleep here, and wake up again in 10 ; seconds or so and re-transmit. But its hard to get a fix on it that way ; so for now we just loop back to the beginning and do it all again. ; GOTO OUTER END
License
This work is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported License. You are free to play around with it and modify it but you are not licensed to use it for commercial purposes. Click the link for more details.