;; Copyright (c) 2006 Phil Short ;; ;; This program is provided free for you to use in any way that you wish, ;; subject to the laws and regulations where you are using it. Due diligence ;; is strongly suggested before using this code. ;; ;; The Author makes no warranty of any kind, express or implied, with regard ;; to this program or the documentation contained in this document. The ;; Author shall not be liable in any event for incidental or consequential ;; damages in connection with, or arising out of, the furnishing, performance ;; or use of these programs. ;; ;; 5 Sept 2006 PJS First diagnostics test version, derived from the 0701a ;; working version. ;; ;; 15 Aug 2007 PJS Modified to use external 18.432 MHz oscillator ;; ;; Hardware mappings ;; PIN 13 (RA0) - triac driver 1 (output) - flashing heartbeat LED (sink) ;; PIN 12 (RA1) - triac driver 2 (output) ;; PIN 11 (RA2) - triac driver 3 (output) ;; PIN 4 (RA3) - zero-crossing (input only) ;; PIN 3 (RA4) - triac driver 0 (output) ;; PIN 10 (RC0) - triac driver 4 (output) - flashing zero-cross detect LED ;; PIN 9 (RC1) - triac driver 5 (output) - 'one-shot' rx_okay LED ;; PIN 8 (RC2) - triac driver 6 (output) - 'one-shot' rx_frame_error LED ;; PIN 7 (RC3) - triac driver 7 (output) - 'one-shot' rx_overrun LED ;; PIN 6 (RC4/TX) - uart_out (output) ;; PIN 5 (RC5/RX) - uart_in (input) ;; PIN 2 (RA5) - reserved (maybe for clock input) ;; ;; Weak pullups are used on pin RA5 (currently a spare pin). ;; Outputs are good to drive 15 mA opto-isolators. ;; ;; The interrupt used by this program is timer0, which is intended to create ;; a periodic (32 us) clock. Since the timer is reset inside of the ISR, the ;; foreground routine should disable interrupts for as short a time as ;; possible (or not at all, if this can be accomplished). LIST R=DEC INCLUDE "p16f688.inc" __CONFIG _FCMEN_OFF & _IESO_OFF & _BOD_OFF & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _EC_OSC ;; __CONFIG _FCMEN_OFF & _IESO_OFF & _BOD_OFF & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTOSCIO CBLOCK 0x020 ;; variables used by the interrupt service routine (ISR) _w, _status state_bitmap porta_image portc_image isr_counter isr_counter_msb hz_counter rx_counter rx_frame_err_counter rx_overrun_counter ENDC ;; units in Hz for the following rate constants #define CLOCKRATE 18432000 #define BAUDRATE 19200 #define TIMERRATE 30720 #define TIMER_CONSTANT (CLOCKRATE /(4 * TIMERRATE)) #define BAUDRATE_CONSTANT (CLOCKRATE / (16 * BAUDRATE) - 1) #define STATE_BITMAP_REG state_bitmap #define TIMER_BIT 7 #define ZC_STATE_REG state_bitmap ;; approximate value for 60 hertz #define TIMECONSTANT_1SEC_60HZ 240 ;; port A LED #define HEARTBEAT_LED_BIT 1 #define ZC_INPUT_BIT 3 ;; port C LEDs #define HZ_LED_BIT 0x01 #define RX_LED_BIT 0xFD #define RX_FRAME_ERR_LED_BIT 0xFB #define RX_OVERRUN_LED_BIT 0xF7 org 0 nop goto initialize org 4 ;; interrupt routine ;; Just the timer interrupt for now... Int movwf _w ; save 'w' movf STATUS, w ; src, dst clrf STATUS ; unnecessary, as nothing changes the status ; bits RP0, RP1, IRP movwf _status ; save f to _status ; maybe save PCLATH register bcf INTCON,T0IF ; reset the interrupt movlw TIMER_CONSTANT ; subwf TMR0,f ; subtraction is atomic, hopefully bsf STATE_BITMAP_REG, TIMER_BIT movf _status, w ; fairly standard interrupt epilogue code movwf STATUS swapf _w,f swapf _w,w retfie initialize: clrf STATUS clrf state_bitmap clrf isr_counter clrf isr_counter_msb clrf hz_counter clrf rx_counter clrf rx_frame_err_counter clrf rx_overrun_counter ;; configure the I/O ports bcf STATUS,RP0 ; select bank 0 movlw 7 movwf CMCON0 ; disable the comparators clrf porta_image ; should turn some of the LEDs off clrf portc_image ; and the rest of the LEDS clrf PORTA clrf PORTC bsf STATUS,RP0 movlw 0x74 movwf OSCCON ^ 0x80 movlw 0x0C movwf TRISA ^ 0x80 ; h/w ignores bit 3 of this register movlw 0xF0 ; upper four bits are tri-stated for uart op. movwf TRISC ^ 0x80 ; clrf ANSEL ^ 0x80 bcf OPTION_REG ^ 0x80,7 ; global weak-pullup enable movlw 0x20 ; turn on weak pullup for unused input (RA5) movwf WPUA ^ 0x80 bcf STATUS,RP0 ;; configure the UART clrf BAUDCTL movlw BAUDRATE_CONSTANT; 19230 baud movwf SPBRG clrf SPBRGH movlw 0x24 ; enable 8-bit transmitter in async mode ; (x16 baud divisor) movwf TXSTA movlw 0x90 ; enable serial port with continuous 8-bit rx movwf RCSTA ;; setup timer - desired action is an interrupt every 60 instructions bsf STATUS,RP0 movlw 0x08 ; assign prescaler to WDT (i.e. not used) movwf OPTION_REG ^ 0x80; timer mode bcf STATUS,RP0 movlw (~TIMER_CONSTANT) movwf TMR0 movlw (1 < 4 transition? goto test_uart_rx movlw HZ_LED_BIT ; increment the hz counter incf hz_counter,f incf hz_counter,f btfss STATUS,Z goto test_uart_rx xorwf portc_image,f ; toggle the LED if necessary movlw 16 addwf hz_counter,f goto test_uart_rx zc_off: movlw 0xF8 andwf ZC_STATE_REG,f ; zc off -> reset the debounce filter ;; ;; done handling possible zero-crossing event, now look at uart events ;; test_uart_rx: btfss PIR1,RCIF ; skip if UART has a rx character to process goto mainloop ; no character available btfss RCSTA,2 ; test for framing error goto no_frame_err movlw TIMECONSTANT_1SEC_60HZ movwf rx_frame_err_counter ; mark occurance of error - (re)starts LED movf RCREG,w goto mainloop no_frame_err: ; movf RCREG,w ; read and discard the received character movlw TIMECONSTANT_1SEC_60HZ btfsc RCSTA,1 ; now check for overrun error goto overrun_err ; movwf rx_counter ; no error - (re)start the rx LED goto mainloop overrun_err: ; should never occur, but handle it anyway movwf rx_overrun_counter; (re)start the rx overrun LED bcf RCSTA,CREN bsf RCSTA,CREN ; restart the uart goto mainloop END