; 29JUL13
; DEVICE = 16F628A
; Electroluminescent Lamp Controller
; Outputs 10 kHz PWM drive for MOSFET switch, comparator feedback for voltage, 1.0 kHz drive for EL lamp
; Filename: elbl.asm
LIST P=16F628a, F=INHX8M
#include <p16f628a.inc>
__CONFIG _INTRC_OSC_NOCLKOUT & _WDT_ON & _LVP_OFF & _CP_OFF
; Equates
RESET_V EQU 0x00 ; Address of RESET Vector
OSC_FREQ EQU D'4000000' ; Oscillator Frequency is 4.0 MHz
; Registers
#define EL1 PORTB,1 ; EL lamp one electrode
#define EL2 PORTB,2 ; EL lamp other electrode
#define FET PORTB,3 ; Booster FET gate (CCP1)
#define PKD PORTB,4 ; Set if output voltage has peaked
#define COMPLO PORTA,0 ; Lower voltage input for EL lamp voltage
#define COMPHI PORTA,1 ; Upper voltage input for EL lamp voltage
ORG 0x00
GOTO START
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.
BTFSC PIR1,TMR1IF ; Check to see if the interrupt was caused by a TIMER1 rollover Overflow)
GOTO Drive ; 0.5 ms timer for EL driver
BCF PIR1,TMR2IF ; In case Timer2 generates an interrupt
RETFIE ; Leave the interrupt handler
Drive ; EL driver, also comparator for output voltage
BCF PIR1,TMR1IF ; Clear Interrupt Source
MOVLW 0xFE ; Preload TIMER1 (0.5 ms)
MOVWF TMR1H
CLRF TMR1L
CALL ToglEL ; Toggle EL outputs
BTFSC PKD ; If set HV is falling, check COMPLO
GOTO Falling
BTFSC CMCON,C2OUT ; Test for upper voltage high
RETFIE
BSF PKD ; HV peaked, reduce PWM drive to FET
MOVLW 0x09 ; Set PWM to 10% duty cycle
MOVWF CCPR1L
RETFIE
Falling
BTFSS CMCON,C1OUT ; Test for lower voltage high
RETFIE
BCF PKD ; Lower voltage reached, set PWM to 85% duty cycle
MOVLW 0x55
MOVWF CCPR1L
RETFIE
START
CLRF STATUS ; Do initialization, Select bank 0
CLRF INTCON ; Clear int-flags, Disable interrupts
CLRF PCLATH ; Keep in lower 2KByte
MOVLW B'00000010' ; AN0 & AN1 Inputs Multiplexed to Comparators, Outputs Inverted
MOVWF CMCON
BSF STATUS, RP0 ; Select bank 1
MOVLW 0xFF
MOVWF TRISA ; RA7-0 Inputs
CLRF TRISB ; RB7-0 Outputs
CLRF OPTION_REG ; Clear everything in OPTION reg (see par. 4.2.2.2)
MOVLW B'11101100' ; Set voltage reference to 0.50*VDD, output on RA2 (input)
MOVWF VRCON
BCF STATUS, RP0 ; Select bank 0
CLRF PORTB ; Make all PORT B outputs Low
; 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 and 2)
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
; Setup Timer1
BCF T1CON,T1CKPS1 ; These set the TIMER1 prescaler. Values:
BCF 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
MOVLW 0xFE ; Preload TIMER1 (0.5ms)
MOVWF TMR1H
CLRF TMR1L
; Setup PWM
MOVLW B'00001100' ; Set CCP module to PWM
MOVWF CCP1CON
MOVLW 0x55 ; Set PWM to 85% duty cycle
MOVWF CCPR1L
MOVLW 0x04 ; Set T2CON for TMR2 1:1 pre/postcale and enabled
MOVWF T2CON
BSF STATUS, RP0 ; Select bank 1
MOVLW 0x63 ; Set PWM period to 100 us
MOVWF PR2
BCF STATUS, RP0 ; Select bank 0
MAIN
GOTO MAIN ; Loop forever
; Subroutine
ToglEL ; Toggles EL outputs
CLRWDT ; Clear Watchdog (runs every 0.5 ms)
BTFSC EL1 ; Test for "10"
GOTO SET01
BSF EL1 ; SET "10"
BCF EL2
RETURN
SET01
BCF EL1
BSF EL2
RETURN
END