; ********************************************************* ; Programmable logic element. ; ; Pete Griffiths, April 2007 ; Version 2.01 ; ; If GPIO5 is pulled low immediatley after a reset (or power-up) ; the PIC reads the voltage applied to GP4 (Pin 3) and this is used to ; select the following functions. To select a new function, adjust the ; voltage and reset the PIC. ; The selected function is saved to EEPROM ; ; Function ; 0 AND GP4-Vss ; 1 OR Vdd-10K-GP4-2.2K-Vss ; 2 XOR Vdd-10K-GP4-4.7K-Vss ; 3 Astable mode F Vdd-10K-GP4-8.2-Vss ; 4 NAND Vdd-6.8-GP4-10K-Vss ; 5 NOR Vdd-4.7K-GP4-10K-Vss ; 6 XNOR Vdd-2.2K-GP4-10K-Vss ; 7 Astable mode S Vdd-10K-GP4 ; ; If GPIO5 IS NOT pulled low immediatley after a reset (or power-up) the PIC reads ; the previous function value from EEPROM and ignores the analogue input. Using this ; method the PIC can be programmed to perform a function once, and it will continue ; to perform the same function after subsequent resets / power-cycles without the need ; to be programmed from an analogue input each time. ; ; In addition to this, by programming the EEPROM at the same time the PIC code is ; written to the device, the function can be preset so that no runtime programming is ; needed. ; To do this the EEPROM needs the following values programming into it ; Address 00 = function from 0 to 7 (see table above) ; Address 01 = 81 ; Address 02 = 69 ; The second two bytes are validation data. If these are not correct and present ; the device reinitializes the EEPROM and sets the function value to 0. ; ; ; The function is defined by the voltage applied to GP4 and is found by using ; ((Vdd/8) x Function) + Vdd/16 ; Using a potentiometer or a pair of resistors (values shown above) the function ; can be selected and is independant of supply voltage. ; ; In Astable mode the PIC outputs a square wave. There are two Astable modes ; Fast with periods of 4mS, 10mS, 20mS and 40mS and ; slow with periods of 400mS, 1S, 2S and 4S ; The data on GPIO 0,1 is sampled each cycle and the astable period selected. ; Since this is checked each cycle, the frequency can be changed during operation. ; B A Freq' ; 0 0 1KHz, 2.5Hz ; 0 1 100Hz, 1Hz (1s) ; 1 0 50Hz, 0.5Hz (2s) ; 1 1 25Hz, 0.25Hz (4s) ; ; Inputs are applied to GP0 (Pin 7) and GP1 (Pin 6) with the logic ; function output appearing on GP2 (Pin 5) ; ; If you want an invertor just use a NAND or NOR gate with both inputs tied together. ; ; With a 4Mhz internal clock speed, instructions execute at 1Mhz, so the propogation ; delay from input change to output is ; AND = 6 micro seconds ; NAND = 7 micro seconds ; NAND,OR,NOR, XOR = 8 micro seconds ; XNOR = 8 micro seconds ; for slow clocked circuits for experimenting and teaching it ; works quite well. ; ; ********************************************************* ; #include "p12f675.inc" __CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT & _MCLRE_OFF & _CPD_OFF errorlevel -302 ; suppress banksel warning messages dOuter EQU 0x20 ;delay loop working variable dInner EQU 0x21 ;delay loop working variable function EQU 0x22 ;Logic function x00 AND. x01 OR. x10 XOR 1xx = Invert output input EQU 0x23 ;Copy of GPIO output EQU 0x24 ;Temp data to output dtime EQU 0x25 ;Software delay ltime EQU 0x26 ;Software delay #define bank0 bcf STATUS,RP0 ; Sel Bank 0 #define bank1 bsf STATUS,RP0 ; Sel Bank 1 ; *************************************** ; To preset a function, uncomment the code below and ; edit the data to be loaded into the EEPROM during ; programming below: ; ; org 0x2100 ; de 0x00 ;function ; de 0x81,0x69 ;validation bytes ; *************************************** ; Start of the main code. Here the PIC ; peripherals and I/O are configured. ; It also gets the interbal OSC Calibration ; value and sets the OSCCAL register. ; org 0x00 nop _main bcf STATUS,RP0 ; Sel Bank 0 movlw 0x07 ; movwf CMCON ; Disable Comparator on GPIO pins movlw b'00001101' ; movwf ADCON0 ; Enable A/D for Channel 3, Left Justified bsf STATUS,RP0 ; Sel Bank 1 ; **************** ; Remove if factory setting at 0x3FF ; has been erased for any reason. ; See 12F675 manual P54 - Sec 9.2.5.1 ; call 0x3FF ; calls RETLW with factory setting ; movwf OSCCAL ; Set int OSC to factory calibrated ; **************** movlw b'01011000' ; Enable GP4 Analogue, GP0,1,2 Digital movwf ANSEL ; Disable Analogue on GPIO pins movlw b'11111011' ; Specifiy GPIO port direction movwf TRISIO ; Set GPIO ports as xxIIIOII bcf OPTION_REG,NOT_GPPU ; enable global weak pull-up. bcf STATUS,RP0 ; Sel Bank 0 bsf WPU,5 ; enable weak pull-up on GPIO5 bsf WPU,0 ; enable weak pull-up on GPIO0 bsf WPU,1 ; enable weak pull-up on GPIO1 movlw 0x00 ; Initialize output movwf GPIO ; port to 0 movlw 0x10 ; Call a short call _Delay ; delay to allow voltages to settle ; ************************************** ; Validate EEPROM and initialise if needed ; Read current function from EEPROM call _eeValidate call _getFunc movwf function ; ************************************** ; This part of the code reads the A/D port ; to determine what function is required. ; If you really hate the idea of using the ; A/D convertor for this job, you could ; rework the code so that GPIO 3,4 & 5 are ; used as digital inputs and then read ; the 3 bit binary value directly from these ; ports - but where's the fun in that? ; _adloop btfsc GPIO,5 ; Test if GPIO5 input is low goto _logic ; If not low, use previous saved function bsf ADCON0,1 ; sample the A/D input on GP4 _poll btfsc ADCON0,1 ; wait while conversion takes place goto _poll _readad movf ADRESH,W ; read in analogue data movwf function ; get Hi byte from conversion swapf function,F ; swap nibbles of Hi byte rrf function,F ; Rotate right one bit ; the lowest three bits in function ; now contain the hi three bits from ; the A/D conversion. We need it this ; way for the computed goto's later. movfw function ; save function to EEPROM call _saveFunc ; ************************************** ; this computes a goto based on the ; value of function and then jumps to ; the required logic function. ; _logic movlw 0x07 ; Mask out all but required andwf function,W ; bits of function variable addwf PCL,F ; computed Gotos used to call the logic function ; Changing the order of the goto statments below ; affects what voltage implements what function. ; You could edit this so that you can get the ; required function by taking the Analogue input to ; Vss or Vdd, avoiding the need for any resistors. ;function value goto _and ;0000 0000 goto _or ;0000 0001 goto _xor ;0000 0010 goto _astable ;0000 0011 goto _nand ;0000 0100 goto _nor ;0000 0101 goto _xnor ;0000 0110 goto _astable ;0000 0111 ; It may not be immediatly obvious how this code emulates the logic ; functions but if you follow it through you'll see how we derive ; the logic function on bit 3 from bits 0/1 ; These funtions rely on the inputs being on bits 0/1 and the ; output on bit 2. ; ****************************************************************** ; AND / NAND functions ; _and movfw GPIO ; read inputs andlw 0x03 ; mask off unwanted bits addlw 0x01 ; add +1 movwf GPIO ; write to outputt goto _and ; repeat _nand movfw GPIO ; read inputs andlw 0x03 ; mask off unwanted bits addlw 0x01 ; add +1 xorlw 0x04 ; invert output bit movwf GPIO ; write to output goto _nand ; repeat ; ****************************************************************** ; OR / NOR functions ; _or movfw GPIO andlw 0x03 skpz movlw 0x04 movwf GPIO goto _or _nor movfw GPIO andlw 0x03 skpnz movlw 0x04 movwf GPIO goto _nor ; ****************************************************************** ; XOR / XNOR functions ; _xor movfw GPIO ; read input addlw 0x01 ; add +1 andlw 0x03 ; mask off 3rd bit addlw 0x02 ; add +2 movwf GPIO ; write to output goto _xor ; repeat _xnor movfw GPIO ; read input addlw 0x01 ; add +1 andlw 0x03 ; mask off 3rd bit addlw 0x02 ; add +2 xorlw 0x04 ; invert 3nd bit movwf GPIO ; write to output goto _xnor ; repeat ; ******************************************** ; Square wave output routine. ; Operates at either ~1Hz, or ~0.5Hz depending on bit 2 ; of function variable ; _astable clrf output ; clear output _swloop movf GPIO,W ; Read data on inputs A and B andlw 0x03 ; Mask out upper 6 bits call _delay_lookup btfsc function,2 ; test for function bit 2 clear call _LDelay ; call delay in 100mS btfss function,2 ; test for function bit 2 set call _Delay ; call delay in 1mS comf output,F ; toggle bits in output movf output,W ; put result in W movwf GPIO ; write to GPIO port goto _swloop _delay_lookup addwf PCL,F retlw d'2' ; mS / mS x 100 retlw d'5' ; mS / mS x 100 retlw d'10' ; mS / mS x 100 retlw d'20' ; mS / mS x 100 ; ******************************************** ; SUBROUTINE ; Delay loop _Delay movwf dtime ; Call for W x 1mS __Dcall call __1mS decfsz dtime,F goto __Dcall __DlyEnd return _LDelay movwf ltime ; Call for W x 100mS __Dlcall movlw d'100' call _Delay decfsz ltime,F goto __Dlcall return __1mS movlw 0xC6 _next nop addlw 0xFF btfss STATUS,Z goto _next nop nop nop return ;********************************** ; EEPROM functions ; all functions return with bank0 selected ; ********************************* ; EEPROM read ; call with W reg containg address to read ; returns with eeprom read data in W reg _getFunc clrw _eeRead bank1 movwf EEADR bsf EECON1,RD movf EEDATA,W bank0 return ; ********************************* ; EEPROM write ; calling code must set EEADR register ; and call with W reg containg data to write _saveFunc movfw function bank1 clrf EEADR _eeWrite bank1 movwf EEDATA bsf EECON1,WREN movlw 0x55 movwf EECON2 movlw 0xAA movwf EECON2 bsf EECON1,WR bank0 _eeWait btfss PIR1,EEIF ; test EEIF flag goto _eeWait ; wait while flag is 0 bcf PIR1,EEIF ; write complete, clear flag. return ; ************************************************************************* ; Test EEPROM to see if it contains valid data from previous use. ; Initialise EEPROM if it doesn't ; Two bytes are used to validate the EEPROM data. If these two bytes ; contain the correct values then the data is assumed to be correct, ; Returns W=0 if validation okay, or initialises EEPROM and returns W=FF _eeValidate movlw 0x01 ; set EE address 1 call _eeRead ; read data xorlw 0x81 ; compare to 0x81 skpz ; skip next if match goto _eeInit ; if validation failed initialise EEPROM movlw 0x02 ; set EE address 2 call _eeRead ; read data xorlw 0x69 ; compare to 0x69 skpz ; skip next if match goto _eeInit ; if validation failed initialise EEPROM retlw 0x00 ; validation okay W=0 ; ********************************* ; Initializes EEPROM _eeInit bank1 movlw 0x00 ; set initial mode to 0 movwf function ; save in mode call _saveFunc ; write to EEPROM bank1 ; now write validation bytes movlw 0x01 movwf EEADR movlw 0x81 ; init validation byte #0 call _eeWrite bank1 incf EEADR,F movlw 0x69 ; init validation byte #1 call _eeWrite bank0 retlw 0xFF ; *********************************************** dt "Pete Griffiths 2006 - R100407.01" end