Background:
At my day job, we build custom test equipment and fixturing. (See attached
picture for a typical machine.) For troubleshooting purposes, I often need
to set up the equipment to automatically cycle for an extended period of
time. In the past, I would either modify the existing PLC program or borrow
an PLC from an upcoming project. The downside was that I might forget to
restore the program to its original state (possible safety issue) or we
wouldnt have an extra (expensive) PLC lying around to borrow. Plus,
I always had to drag the laptop out to the shop floor and knock together
a quick little program to make everything happen. I got tired of doing this,
so one Saturday I built this little project with about $5 worth of components.
Circuit Description:
1. Power from the machine, typically 24 vdc, is supplied to J2-1 and J2-2,
which feeds a 7805 voltage regulator to supply the PIC.
2. Reset button on MCLR allows user to reset the PIC and start the timing
sequence from zero.
3. ALIVE led flashes every 0.5 seconds just to let the user know the thing
is executing its program.
4. An optoisolator (from my junkbox) is driven by GP2.
5. The optoisolator drives a relay robbed from a dead PLC.
Link
to picture of the PCL
Link
to product information
6. The relays coil voltage is 4.5vdc. Setting JP1 allows the relay
to use power either from the 7805 regulator or from the machine. R4 and R5
need to be sized based on the supply voltage and rated coil voltage.
7. Relay contacts (J1-1 and J1-2) are wired in parallel with the machines
start button.
8. Potentiometer allows the user to manually set the amount of time between
subsequent machine cycles.
Software Description:
A PIC12F675 reads the voltage from the potentiometer wiper connected to AN0.
Timer0 rolls over on a 0.5 second interval and toggles ALIVE led to let the
user know the program is running. A register is also incremented for each
timer rollover. When the number of timer0 roll-overs is greater than or equal
to the A/D counts, the relay will turn on for 0.5 seconds to initiate a machine
cycle. Thus, by setting the pot, the delay between machine cycles can be
adjusted from approximately 0 to 8.5 minutes. The contacts of the relay are
wired in parallel with the machines start button(s).
Let me know if I forgot to include anything or you need any clarifications.
Regards,
Aaron Garber
;**********************************************************************
; *
; Filename: Pulser.asm *
; Date: 2-25-05 *
; File Version: *
; *
; Author: Aaron Garber *
; *
;**********************************************************************
; *
; Files required: *
; 12F675i.lkr *
; P12F675.inc *
; *
;**********************************************************************
; *
; Notes: *
; A quick and dirty program. Reads pot connected to AN0. *
; A TMR1 interrupt occurs every 0.5 seconds. *
; When the number of TMR1 rollovers >= the A/D result, a *
; relay will be turned on for a 0.5 second pulse. *
; *
;**********************************************************************
list p=12f675 ; list directive to define processor
#include <p12f675.inc> ; processor specific variable definitions
radix dec
errorlevel -302 ; suppress message 302 from list file
__CONFIG _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_ON & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_CLKOUT
; pin definitions
; GP0 - Analog input from wiper of 5k pot. Sets delay time between 0.5 second relay pulses.
; GP1 - Not used.
; GP2 - Drives 4N32 optoisolator thru 200 ohm resistor. 4N32 then drives relay output. Delays between 0.5 second relay pulses are set by pot.
; GP3 - Reset button between ground and MCLR. MCLR tied high via 10k resister.
; GP4 - Fosc/4 clockout for debug purposes.
; GP5 - Drives an LED on a clock tick. Visual indication that program is working.
; #defines
#define pot GPIO, GP0
#define relay GPIO, GP2
#define aliveLED GPIO, GP5
; Shared Uninitialized Data Section
INT_VAR UDATA_SHR 0x20
w_temp RES 1 ; variable used for context saving
status_temp RES 1 ; variable used for context saving
rollcntL RES 1 ; low byte of TMR1 rollovers
rollcntH RES 1 ; high byte of TMR1 rollovers
rollflag RES 1 ; bit 0 = TMR1 rollover flag for main loop to poll
;**********************************************************************
RESET_VECTOR CODE 0x000 ; processor reset vector
goto main ; go to beginning of program
INT_VECTOR CODE 0x004 ; interrupt vector location
movwf w_temp ; save off current W register contents
movf STATUS,w ; move status register into W register
movwf status_temp ; save off contents of STATUS register
; check for TMR1 rollover
banksel PIR1
btfss PIR1, TMR1IF ; TMR1 rollover?
goto nextIRQ
movlw 0xBD ; reload TMR1
banksel TMR1L
movwf TMR1L
movlw 0xB
banksel TMR1H
movwf TMR1H
banksel GPIO
bcf relay ; turn off relay
banksel GPIO
movlw b'00100000' ; toggle aliveLED for visual indication
xorwf GPIO, f
banksel rollflag
bsf rollflag, 0 ; set roll-over flag for main loop to poll
banksel PIR1
bcf PIR1, TMR1IF ; clear interrupt flag
nextIRQ
movf status_temp,w ; retrieve copy of STATUS register
movwf STATUS ; restore pre-isr STATUS register contents
swapf w_temp,f
swapf w_temp,w ; restore pre-isr W register contents
retfie ; return from interrupt
; Main Code
main
call 0x3FF ; retrieve factory calibration value
banksel OSCCAL
movwf OSCCAL ; update register with factory cal value
; initialize variables
banksel rollcntL
clrf rollcntL
banksel rollcntH
clrf rollcntH
banksel rollflag
clrf rollflag
; set up direction of I/O pins
banksel TRISIO
movlw b'00000001'
; xx------ not implemented
; --0----- 0=output, GP5, Drives an LED on a clock tick. Visual indication that program is working.
; ---0---- 0=output, GP4, Fosc/4 clockout for debug purposes
; ----x--- not used, GP3, Dedicated to MCLR
; -----0-- 0=output, GP2, Optoisolator, relay driver
; ------0- 0=output, GP1, not used (output defective)
; -------1 1=input, GP0, analog input
movwf TRISIO
; set up comparator
banksel CMCON
movlw b'00000111'
; x------- not implemented
; -0------ output bit
; --x----- not implemented
; ---0---- 0=non-inverted output
; ----0--- 0=Vin- to Cin-
; -----111 111=comparator off
movwf CMCON
; set up A/D converter
banksel ANSEL
movlw b'00010001'
; x------- not implemented
; -001---- 001=Focs/8 Conversion Clock
; ----0--- 0=digital I/O, GP4, Fosc/4 clockout for debug purposes.
; -----0-- 0=digital I/O, GP2, Optoisolator, relay driver
; ------0- 0=digital I/O, GP1, not used
; -------1 1=analog I/O, GP0, analog input
movwf ANSEL
banksel ADCON0
movlw b'10000001'
; 1------- 1=right justified result
; -0------ 0=Vdd is voltage reference
; --xx---- not implemented
; ----00-- 00=select channel 0 (GP0)
; ------0- 0=A/D conversion not started
; -------1 1=A/D converter module is operating
movwf ADCON0
; initialize output pins
init
banksel GPIO
movlw b'00000000'
movwf GPIO
; initialize interrupts
banksel INTCON
movlw b'01000000'
; 0------- 0=interrupts disabled
; -1------ 1=enable peripheral interrupts
; --0----- 0=disable TMR0 overflow interrupt
; ---0---- 0=disable GP2/INT external interrupt
; ----0--- 0=disable GPIO port change interrupt
; -----0-- 0=no on TMR0 overflow
; ------0- 0=no GP2/INT external interrupt
; -------0 0=no GPIO port change
movwf INTCON
banksel PIE1
movlw b'00000001'
; 0------- 0=disable EE write complete interrupt
; -0------ 0=disable A/D converter interrupt
; --xx---- not implemented
; ----0--- 0=comparator interrupt disabled
; -----xx- not implemented
; -------1 1=enable TMR1 overflow interrupt
movwf PIE1
banksel PIR1
movlw b'00000000'
; 0------- 0=no EE write complete
; -0------ 0=no A/D conversion complete
; --xx---- not implemented
; ----0--- 0=no comparator interrupt
; -----xx- not implemented
; -------0 0=no TMR1 overflow
movwf PIR1
; initialize TMR1
banksel T1CON
movlw b'00110101'
; x------- not implemented
; -0------ 0=gate disabled
; --11---- 01=1:8 prescaler
; ----0--- 0=LP oscillator is off
; -----1-- 1=external clock input not synchronized
; ------0- 0=internal clock
; -------1 1=enable timer
movwf T1CON
; preload for 500ms rollover @ 4 MHZ internal oscillator
; Fosc/4 = 1 MHZ = 1 uS per clock
; 500000 clocks per 500 ms
; with 1:8 prescaler: 65535 - (500000/8) = 3035 = 0xBDB initial value
banksel TMR1L
movlw 0xDB
movwf TMR1L
banksel TMR1H
movlw 0xB
movwf TMR1H
banksel INTCON
bsf INTCON, GIE ; enable interrupts
; Main Loop
forever
banksel ADCON0
bsf ADCON0, GO ; start A/D conversion
btfsc ADCON0, NOT_DONE
goto $-1
banksel rollflag
btfsc rollflag, 0 ; TMR1 rollover?
call compare
goto forever
; Compare subroutine - Test rollover counter to see if it >= the A/D result.
; If it is we turn on the relay.
compare
banksel rollflag
bcf rollflag, 0 ; reset ISR rollover flag
; increment number of rollovers
banksel rollcntL
incf rollcntL, f ; number of rollovers
btfsc STATUS, Z ; more than 255 rollovers?
incf rollcntH, f ; yes, increment high byte of rollover counter
; compare to see if rollover counter is >= A/D result (16 bit unsigned comparision)
banksel ADRESH
movfw ADRESH
banksel rollcntH
subwf rollcntH, w ; w = rollcntH - ADRESH
btfss STATUS, C ; if rollcntH >= ADRESH, C=1
return
btfss STATUS, Z ; if rollcntH = ADRESH, C=1
goto relay_on
banksel ADRESL
movfw ADRESL
banksel rollcntL
subwf rollcntL, w ; w = rollcntL - ADRESL
btfss STATUS, C ; if rollcntL >= ADRESL, C=1
return
; rollover counter >= A/D result
relay_on
banksel rollcntL ; reset roll-over counters
clrf rollcntL
banksel rollcntH
clrf rollcntH
banksel GPIO ; turn on relay
bsf relay
return
; initialize eeprom locations
EE CODE 0x2100
DE 0x00, 0x01, 0x02, 0x03
END