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