; filename: "atp.asm" ; This is an automatic trolley puller. When used to climb onto a wooden pony the puller will count down when started ; and then start a motor (12 RPM) that pulls the trolley away. When the end switch is pressed it stops. Sound input ; to speed up countdown. ; v0.0 221119 Copied from maglocktimer ; v0.1 221125 Fixed tens display ; GPL Copyleft 2012-2022 pic@smmedical.eu LIST P=16F628A, F=INHX8M #include <p16f628a.inc> __CONFIG _INTRC_OSC_NOCLKOUT & _WDT_ON & _LVP_OFF & _CP_OFF & _BODEN_OFF ERRORLEVEL -302 ; sod message about using proper bank ; Equates RESET_V EQU 0x00 ; Address of RESET Vector OSC_FREQ EQU D'4000000' ; Oscillator Frequency is 4 MHz ; Registers GPFLAGS EQU 0x20 ; General Purpose Flags TENS EQU 0x21 ; Left digit (MSB) UNITS EQU 0x22 ; Right digit (LSB) TICKS EQU 0x24 ; 0.25 seconds, 256 ticks per unit total 99*256*0.25=105.6 min ehrm... ; Defines #define FET PORTA,2 ; Switch motor FET on (active high), wait for motor endswitch #define UPSW PORTA,4 ; "UP" switch #define LED1 PORTA,1 ; MSB Anode (via PNP like BC557B) #define LED2 PORTA,0 ; LSB Anode #define ENDSW PORTA,6 ; End switch input (active low) #define LEDTOGL GPFLAGS,0 ; toggles LED1 and 2 (0: LSB=LED2, 1: MSB=LED1) #define RUNNING GPFLAGS,1 ; Counting down, when unset display dot only #define LAST GPFLAGS,2 ; Countdown almost done, display 0x #define LAMPTST GPFLAGS,4 ; Lamp Test org 0x00 GOTO Main org 0x04 ; Interrupt handlers ; NOTE: Since virtually every part of this program runs inside an interrupt handler, it's not necesssary ; to back up any critical registers when entering or exiting the handler. Copied from someone. BTFSC PIR1,TMR1IF ; Check to see if the interrupt was caused by a TIMER1 rollover Overflow) GOTO Timehandler ; 0.25 second timer BTFSC PIR1,TMR2IF ; Check to see if the interrupt was caused by a TIMER2 rollover (overflow) GOTO Multiplex ; 16 ms multiplex time for LED display RETFIE ; If none of the above is true, then just leave the interrupt handler Timehandler BCF PIR1,TMR1IF ; Clear Interrupt Source MOVLW 0xFA ; Preload TIMER1 (approx. 5 min countdown) MOVWF TMR1H MOVLW 0x3B MOVWF TMR1L BCF LAMPTST ; No need to have those after the first half second BTFSS RUNNING ; If not counting down we must keep our hands off the time counters RETFIE BTFSC FET ; Countdown ended? GOTO CHKENDSW ; Yes, check endswitch ; Check "TICKS" DECFSZ TICKS,F RETFIE ; Check if UNITS is zero DECFSZ UNITS,F RETFIE ; Check if TENS is also zero BTFSC LAST ; TENS zero? GOTO STARTMOTOR ; Yes MOVLW 0x0A MOVWF UNITS DECFSZ TENS,F RETFIE BSF LAST RETFIE STARTMOTOR BSF FET ; Start motor RETFIE CHKENDSW BTFSC ENDSW RETFIE BCF FET BCF RUNNING BCF LAST MOVLW 0x09 MOVWF TENS MOVWF UNITS RETFIE Multiplex BCF PIR1,TMR2IF ; Clear Interrupt source CLRWDT ; Clear Watchdog Timer (this runs every 4.0 ms, so with 18 ms WDT time-out that should be OK) ; Check UP switch first BTFSC UPSW ; Read UP switch ("clear" is pressed, active LOW) GOTO DoMPX BSF RUNNING DoMPX ; Toggle LEDs MOVLW B'00000001' XORWF GPFLAGS,1 ; Toggle LEDs BTFSS LEDTOGL ; set means LSB display GOTO MSBLED BSF LED1 BCF LED2 ; LSB LED, check if LAMPTST BTFSC LAMPTST GOTO LSBLAMPTST BTFSS RUNNING GOTO LSBDISPDOT MOVFW UNITS CALL bin2seg MOVWF PORTB RETFIE LSBLAMPTST CLRF PORTB RETFIE LSBDISPDOT MOVLW 0x7F ; Display dot only MOVWF PORTB RETFIE MSBLED ; MSB LED, check if LAMPTST BSF LED2 BCF LED1 BTFSC LAMPTST GOTO MSBLAMPTST BTFSS RUNNING GOTO MSBDISPDOT MOVLW 0x0A SUBWF UNITS,W BTFSC STATUS,Z ; UNITS zero? GOTO FIXMSB ; Yes, compensate TENS and move to WREG MOVFW TENS CALL bin2seg MOVWF PORTB RETFIE FIXMSB INCF TENS,W ; Compensate TENS and move to WREG (UNITS is zero) CALL bin2seg MOVWF PORTB RETFIE MSBLAMPTST CLRF PORTB RETFIE MSBDISPDOT MOVLW 0xFF ; Display blank MOVWF PORTB RETFIE ; END Interrupthandlers Main ;Init stuff BCF STATUS,RP0 ; Go to bank 0 BCF STATUS,RP1 ; Go to bank 0 MOVLW 0x07 ; Turn comparators off MOVWF CMCON BSF STATUS,RP0 ; Go to bank 1 MOVLW B'11111000' ; PORTA,0-2 Outputs MOVWF TRISA CLRF TRISB ; Set port B as all outputs BSF OPTION_REG,PSA ; Something with Watchdog Timer BCF STATUS,RP0 ; Go back to bank 0 BSF T1CON,T1CKPS1 ; These set the TIMER1 prescaler. Here are the possible values: BSF T1CON,T1CKPS0 ; 00=1:1 01=1:2 10=1:4 11=1:8 BCF T1CON,T1OSCEN ; Turn off the TIMER1 oscillator to save power (we don't need it because we're using the internal oscillator) BCF T1CON,TMR1CS ; Select the internal oscillator for TIMER1 BSF T1CON,TMR1ON ; Enable TIMER1 BSF T2CON,T2CKPS1 ; Prescale 1:16 for TIMER2 BCF T2CON,T2CKPS0 ; BCF T2CON,TOUTPS3 ; Postscale 1:1 for TIMER2 BCF T2CON,TOUTPS2 ; BCF T2CON,TOUTPS1 ; BCF T2CON,TOUTPS0 ; BSF T2CON,TMR2ON ; Enable TIMER2 ; Enable interrupts BCF INTCON,INTF ; Clear INTF flag before enabling interrupts BCF INTCON,T0IF ; Clear T0IF (TIMER0 Interrupt Flag) before enabling interrupts BCF PIR1,TMR1IF ; Clear TMR1IF (TIMER1 Interrupt Flag) before enabling interrupts BCF PIR1,TMR2IF ; Clear TMR2IF (TIMER1 Interrupt Flag) before enabling interrupts BCF INTCON,INTE ; Clear interrupt on RB0/INT pin (an External interrupt) BSF INTCON,PEIE ; Enable PEIE (PEripheral Interrupt Enable - for TIMER1, the 16 bit timer) BSF STATUS,RP0 ; Go to bank 1 BSF PIE1,TMR1IE ; Enable interrupt on TIMER1 overflow (when the TMR1 register pair wraps around from 0xFFFF to 0x0000) BSF PIE1,TMR2IE ; Enable interrupt on TIMER2 overflow BCF PIE1,CMIE ; Disable interrupt on comparator output change BCF STATUS,RP0 ; Go to bank 0 BSF INTCON,GIE ; Enable global interrupts ; INIT Registers CLRF GPFLAGS BCF FET BSF LAMPTST ; Lamp Test during the first second CLRF TMR1H CLRF TMR1L MOVLW 0x09 MOVWF TENS MOVWF UNITS ; Preload 99 counts MOVLW 0x78 ; 0x78=120 half-TICKS MOVWF TICKS WaitForInterrupt GOTO WaitForInterrupt ; Do Nothing ; Subroutines bin2seg ; Convert hex value to 7-segment display ADDWF PCL, F ; Jump into the lookup table RETLW 0xC0 ; Return segment code for 0 RETLW 0xF9 ; Return segment code for 1 RETLW 0xA4 ; Return segment code for 2 RETLW 0xB0 ; Return segment code for 3 RETLW 0x99 ; Return segment code for 4 RETLW 0x92 ; Return segment code for 5 RETLW 0x82 ; Return segment code for 6 RETLW 0xF8 ; Return segment code for 7 RETLW 0x80 ; Return segment code for 8 RETLW 0x90 ; Return segment code for 9 RETLW 0xC0 ; Return segment code for A (0) END