;********************************************************************** ; lightbar8-revb.asm * ; This file is code for an emergency light bar controller * ; on the PICmicro PIC16F627. See lightbar.dwg for cct. * ; This version was built on a pic-proto board designed in Eagle. * ; see pic-proto.sch and pic-proto.brd * ; This version is simplified to 8 bit output (PORTB)and 1 p/b switch * ; input on PORTA,2. Flash mode is preserved in eeprom between power * ; cycles so that starting the truck doesnt put a new flash mode up. * ; * ;********************************************************************** ; * ; Filename: lightbar8-revb.asm * ; Date: Dec 8 2003 * ; File Version: beta test * ; tested on hardware * ; rev B. March15/04 minimal pic config * ; * ; Author: Lawrence Glaister VE7IT * ; Company: Glaister Consulting * ; * ; Jan 7 2004 - added off as one of the modes, also new pattern added* ; 15 March 2004 - minimal pic config using internal osc * ; * ;********************************************************************** ; * ; Files required: * ; p16f627.inc * ; * ; * ;********************************************************************** ; * ; Notes: * ; * ; - build using * ; assembler package found at * ; http://gputils.sourceforge.net/ or download page of * ; https://sourceforge.net/project/showfiles.php?group_id=41924 * * ; gpasm lightbar8-revb.asm * ; * ; * ; - burn using * ; pp627 ( a modified version of pp84 by L.P Glaister ) * ; pp627 lightbar8-revb.hex * ; * ; This project uses the top 1/2 of the 1k code space for patterns. * ; The lower 512 bytes contains the controller code and is roughly * ; 1/4 used. * ;********************************************************************** list p=16f627, n=58, c=80 ; list directive to define processor radix dec #include ; processor specific variable definitions ; see page 96 of data sheet for description of config bits ; code protection off ; watch dog timer off ; brown out detection on ; power up timer enabled ; int rc osc (4mhz) with clk/4 on osc2 pin 15 ; master clear pin used as I/O ; low voltage programming off ; NOTE: rb4 pin 10 must be pulled low to be sure HVP mode will work. __CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _INTRC_OSC_CLKOUT & _MCLRE_OFF & _LVP_OFF ; THESE 4 NIBBLES CAN BE USED FOR SOFTWARE VERSION NUMBER __idlocs H'F0AD' XTAL_FREQ equ 4000000 ; nominal clock freq in hz ;***** RAM LOCATION DEFINITIONS ; locations 70-7f are common to all 4 banks (no bank select issues) ; Bank 0 has 96 bytes of general purpose regs 20h-7fh (hi 16 are common to all banks) ; *** Bank0 *** 80 bytes 0x20 - 0x6f CBLOCK 0x020 cycle ; counter for current pattern subcycle 0..35 fcycle ; counter for stepping through flash patterns 0..7 bmode ; current mode selected by pushbutton ; 0 = code 3, ; 1 = director left ; 2 = director right ; 3 = director split ; 4 = off temp ; local variable used by various routines mtemp ; temp used in main ENDC ; *** Bank1 *** 80 bytes 0xA0 - 0xEF CBLOCK 0x0A0 ENDC ; *** Bank2 *** 48 Bytes 0x120 - 0x14f CBLOCK 0x120 ENDC ; *** Bank0/1/2/3 mirrored in all banks 0x70, 0xF0, 0x170, 0x1F0, 16 bytes CBLOCK 0x070 w_temp ; variable used for context saving status_temp ; variable used for context saving ENDC ; ****************** Macro definitions ******************************** ;+++++ ; PAGE/BANK0/1/2/3 selects register bank 0/1/2/3. ; Leave set to BANK0 normally. BANK0 MACRO BCF STATUS,RP0 ; clear bank select bits BCF STATUS,RP1 ; BCF STATUS,IRP ; clear indirect adressing bit ENDM BANK1 MACRO BSF STATUS,RP0 ; BCF STATUS,RP1 ; ; BCF STATUS,IRP ; clear indirect adressing bit ENDM BANK2 MACRO BCF STATUS,RP0 ; BSF STATUS,RP1 ; BSF STATUS,IRP ; set bit for indirect adressing ENDM BANK3 MACRO BSF STATUS,RP0 ; BSF STATUS,RP1 ; BSF STATUS,IRP ; set bit for indirect adressing ENDM ;********************************************************************** ;* Program description ;* ;* The basic timing function is handled by timer1 that sets the ;* int flag at a rate of 72*12 timeslots/minute (69.4ms / timeslot). ; ;* This cause the main program loop to re-examine the input ;* switches to determine the current mode and to update the output ;* image. The main loop goes back to sleep. ;********************************************************************** ;********************************************************************** ORG 0x000 ; processor reset vector NOP ; required for the ICD CLRF STATUS ; ensure we are at bank0 CLRF PCLATH ; ensure page bits are cleared ( before GOTO xxx !!! ) goto start ; go to beginning of program ORG 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 ; isr code can go here or be located as a call subroutine elsewhere 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 start MOVLW B'11111111' ; PORT REGS TO DEFAULTS MOVWF PORTA MOVLW B'11111111' MOVWF PORTB MOVLW 7 ; turn comparators off MOVWF CMCON ; and enable pins for I/O MOVLW B'00000111' ; B7: RBPU - ENABLE PORT B PULL-UP RES, 0=OFF ; B6: INTEDG - RB0 INT EDGE SEL 0=-VE ; B5: T0CS - TMR0 SOURCE, 0=FOSC/4, 1=RA4 PIN ; B4: T0SE - RA4CLK PIN EDGE SELECT, 0=+VE ; B3: PSA - PRESCALE ASSIGN 0=TIMER, 1=WDG ; B2-0: PS2-0 - PRESCALE RATE 111=256 FOR TIMER (=127 FOR WDT) ERRORLEVEL -306, -302 BSF STATUS,RP0 ; OPTION & TRIS & VRCON ARE IN BANK 1 MOVWF OPTION_REG movlw b'00000000' ; vref powered down, vref not using ra2, movwf VRCON ; set port B for outputs MOVLW B'00000000' ; 0=OUTPUT MOVWF TRISB ; set port A as inputs MOVLW B'11111111' ; 1=INPUT MOVWF TRISA BCF STATUS,RP0 ; BACK TO LO REGS ERRORLEVEL +306, +302 MOVLW B'00000000' ; B7: GIE - GLOBAL INT ENABLE, 0=OFF ; B6: EEIE - EERAW WRITE DONE INT ENABLE, 0=OFF ; B5: T0IE - TMR0 O/FLOW INT ENABLE, 0=OFF ; B4: INTE - RB0 INT ENABLE, 0=OFF ; B3: RBIE - PORTB CHANGE-OF-STATE INT ENABLE, 0=OFF ; B2: T0IF - TMR0 O'FLOW FLAG, 1=O/FLOW, S/WARE MUST RESET ; B1: INTF - RB0 INT FLAG, ACTIVE HIGH ; B0: RBIF - PORTB CHANGE-OF-STATE FLAG, ACTIVE HIGH MOVWF INTCON call init_timer1 ; init any i/o that needs to behave on powerup ; add application specific inits here clrf cycle ; 1 of 36 counter clrf fcycle ; code 3 pattern number clrw ; read display mode from eeprom at offset 0 call read_eeprom movwf bmode ; power up in last selected mode ; ====== MAIN ====== dispatch to correct light mode main btfss PIR1,TMR1IF ; check to see if time to do something goto main ; if the timer is running correctly, we get here 14.4 times/sec call init_timer1 ; restart the timer for next time ; manage the basic 36 cycle counter used to step through a pattern incf cycle,f ; bump up the cycle counter movf cycle,w sublw 35 ; check if its too big (0..35 valid) btfsc STATUS,C goto main01 ; manage the counter used to cycle through the list of flash patterns clrf cycle ; reset counter 0 incf fcycle,f ; bump major full cycle counter up main01 btfsc PORTA,2 ; check if mode sw input is pressed goto main05 ; user has requested a new flash mode incf bmode,F clrf PORTB ; turn all lights out while button pushed main02 btfss PORTA,2 goto main02 ; wait for user to release button clrf cycle ; clr 1 of 36 counter so pattern starts cleanly movf bmode,w ; save state selected to eeprom at offset 0 call write_eeprom0 main05 movf bmode,w andlw B'00000111' ; limit choices to 0,1,2,3,4,5,6,7 movwf mtemp btfss STATUS,Z goto main06 call code3 ; (0) setup display for cycling code3 pattern goto main12 main06 decfsz mtemp,F goto main07 call scanl ; (1) setup display for move left goto main12 main07 decfsz mtemp,F goto main08 call scanr ; (2) setup display for move right goto main12 main08 decfsz mtemp,F goto main09 call scansplit ; (3) setup display for move to both sides goto main12 main09 decfsz mtemp,F ; (4) cherry goto main10 call cherry goto main12 main10 decfsz mtemp,F ; (5) night rider goto main11 call nrider goto main12 main11 movlw 0 ; (6,7) all lights off main12 movwf PORTB goto main ; ; --------------------------------------------------------------------- ; code3 ; Setup output bits for attention getting series of patterns. ; Variables cycle and fcycle are used to determine pattern. ; fcycle is used to sequence through several 2.5 second long patterns. ; cycle is used to pick up one of 36 samples in a particular pattern. ; The required led bit pattern is returned in the w register. ; ; --------------------------------------------------------------------- ; code3 ; lookup which pattern routine we should be using based on fcycle ; feel free to change this order if sequencial patterns do not ; look good together. jmptab movlw HIGH jmptab ; setup to index into jump table movwf PCLATH movf fcycle,w movwf temp rlf temp,W andlw B'00001110' ; force to 0,2,4,6,8,10,12,14 for case addwf PCL,F ; jump into state table call alt ; 0) alternating led modules on goto front_00 call comet_alt ; 1) strobe effect alternating modules on goto front_00 call wigwag ; 2) left and right groups of 3 alternate goto front_00 call cometww ; 3) strobe effect alternating groups of 3 goto front_00 call centersww ; 4) center steady alternating groups of 2 goto front_00 call cscww ; 5) center steady strobe effect alternating groups of 2 goto front_00 call flash ; 6) all 6 leds flash goto front_00 call cometflash ; 7) all 6 leds simulate strobe goto front_00 ; this is a spare pattern that never gets called ; call nrider ; 8) 2 leds sweep back and forth ; goto front_00 jtabend if ((jmptab & 0xff00 ) != (jtabend & 0xff00)) error "Table must not cross page boundary - please movit!" endif front_00 return ; ; --------------------------------------------------------------------- ; init_timer1 ; set up registers associated with timer1 so that TMR1IF in PIR1 gets ; set at the interval we require ( 69.4ms ) ; Sample timer calcs: ; XTAL_FREQ = 12mhz => .0000833 milliseconds period ; basic flash freq = 14.4hz => 69.4ms period ; .0000833ms * 4 * 8 = .0026656ms for 1 count of timer1 when using ; fosc/4 and prescaler of 8. ; we want a period of 69.4ms (72 flashes/min and 12 subsamples/flash) ; so the divider gets set to 69.4/.0026656 = 26035 ; --------------------------------------------------------------------- ; init_timer1 ; shut off the timer bcf T1CON,TMR1ON ; load the divider registers (clears prescaler counter) ; divider calcs... scaled to use integer math. ; to be totally correct, the preset value should be reduced ; by the time it takes to call this routine and get the timer ; restarted. In a polled environment detecting the TMR1IF is ; going to vary, so the actual time interval will wander slightly. base equ (XTAL_FREQ/4/8) divi equ (10 * base/144) divh equ (65536 - divi) >> 8 divl equ (65536 - divi) & 0x00ff movlw divh movwf TMR1H movlw divl movwf TMR1L ; clr the interrupt flag bcf PIR1,TMR1IF ; see page 50 of data sheet for definition of T1CON ; set timer 1 prescaler to /8 ; set timer 1 osc enable to off ; dont care on sync bit ; set timer 1 to use fosc/4 as input ; enable timer 1 movlw (1<