; Christmas Tree
; Copyright Michale Hofmann 1998
; Released under GNU GPL
 constant MODE = 0
 list p=16f84
 radix dec
 include "p16f84.inc"
 errorlevel -302
 errorlevel -224

 __config H'3FF9' ; xt, cp,wdt,pwrt off
 constant LEDDARK = -30 ; 30 Takte for one cycle on-off-on
 constant PWM = 10 ; 10 steps PWM
 cblock 0x20
   Flags
   CountPWM
   Count     ; Position in table
   CountB0
   CountB1
   CountB2
   CountB3
   CountB4
   CountB5
   CountB6
   CountA0
   CountA1
   CountA2
   CountA3
   CountA4
   OutLatchA
   OutLatchB
 endc

	ORG     0

	goto Init

	ORG     4

	goto Inter

; GetNextVal ---------
GetNextVal
  decf Count,w
  skpnz
  movlw GetNextValE-GetNextValS
  movwf Count
  addwf PCL,f ; Starts with 1
  nop
GetNextValS

; (Pseudo) random numbers
 IF MODE == 0
  retlw 255
  retlw 54
  retlw 236
  retlw 123
  retlw 89
  retlw 159
  retlw 164
  retlw 145
  retlw 77
  retlw 108
  retlw 203
  retlw 182
GetNextValE

 constant StartValA0 = 1
 constant StartValA1 = 1
 constant StartValA2 = 1
 constant StartValA3 = 1
 constant StartValA4 = 1
 constant StartValB0 = 1
 constant StartValB1 = 1
 constant StartValB2 = 1
 constant StartValB3 = 1
 constant StartValB4 = 1
 constant StartValB5 = 1
 constant StartValB6 = 1

 ELSE
 IF MODE == 1
 constant TIME = 90
  retlw TIME
GetNextValE

 constant StartValA0 = TIME/12*11
 constant StartValA1 = TIME/12*10
 constant StartValA2 = TIME/12* 9
 constant StartValA3 = TIME/12* 8
 constant StartValA4 = TIME/12* 6
 constant StartValB0 = TIME/12* 5
 constant StartValB1 = TIME/12* 4
 constant StartValB2 = TIME/12* 3
 constant StartValB3 = TIME/12* 7
 constant StartValB4 = TIME/12* 2
 constant StartValB5 = TIME/12* 1
 constant StartValB6 = TIME/12*12

 ENDIF
 ENDIF

; GetNextPWM ---------
GetNextPWM
  addwf PCL,f
GetNextPWMS
  retlw 1 ; Bright
  retlw 2
  retlw 3
  retlw 4
  retlw 5
  retlw 6
  retlw 7
  retlw 8
  retlw 9
  retlw 9
  retlw 10 ; Dark
  retlw 10
  retlw 10
  retlw 10
  retlw 10
  retlw 10
  retlw 10
  retlw 10
  retlw 10
  retlw 10
  retlw 9 ; Gets bright again
  retlw 9
  retlw 8
  retlw 7
  retlw 6
  retlw 5
  retlw 4
  retlw 3
  retlw 2
  retlw 1
GetNextPWME

; Main program
Init
  bsf STATUS,RP0

  bcf OPTION_REG,T0CS     ; Timer mode
  bcf OPTION_REG,PSA      ; Prescaler to Timer0

  bcf OPTION_REG,PS0      ; 010 - 1:8 - 2048 us - 500 Hz
  bsf OPTION_REG,PS1
  bcf OPTION_REG,PS2

  movlw 1                 ; Count to start value (>0)
  movwf Count
  movwf CountPWM
  movlw StartValA0
  movwf CountA0
  movlw StartValA1
  movwf CountA1
  movlw StartValA2
  movwf CountA2
  movlw StartValA3
  movwf CountA3
  movlw StartValA4
  movwf CountA4
  movlw StartValB0
  movwf CountB0
  movlw StartValB1
  movwf CountB1
  movlw StartValB2
  movwf CountB2
  movlw StartValB3
  movwf CountB3
  movlw StartValB4
  movwf CountB4
  movlw StartValB5
  movwf CountB5
  movlw StartValB6
  movwf CountB6

  clrf OutLatchA
  clrf OutLatchB

  bcf OPTION_REG,NOT_RBPU ; Pullups

  clrf TRISA              ; PortA is output
  movlw B'10000000'
  movwf TRISB             ; PortB is output, bit 7 input

  bcf STATUS,RP0

  bsf INTCON,GIE          ; Global
  bsf INTCON,T0IE         ; Timer 0
  bsf INTCON,RBIE         ; PortBChange

  goto $

; Timer 0 ---------
Inter
  btfss INTCON,T0IF
  goto Inter_NoTimer

  bcf Flags,0 ; New value
  decfsz CountPWM,f
  goto PWMOver
  movlw PWM
  movwf CountPWM
  bsf Flags,0
PWMOver

  movfw CountA0
  btfss Flags,0
  goto CountA0S
  bsf OutLatchA,0 ; Count down LED counters
  decfsz CountA0,f
  goto CountA0S
  call GetNextVal
  movwf CountA0
  goto CountA0S
CountA0S
  movfw CountA0
  addlw LEDDARK
  bc CountA0E
  movfw CountA0 ; PWM
  call GetNextPWM
  subwf CountPWM,w
  skpnz
  bcf OutLatchA,0
CountA0E

  movfw CountA1
  btfss Flags,0
  goto CountA1S
  bsf OutLatchA,1
  decfsz CountA1,f
  goto CountA1S
  call GetNextVal
  movwf CountA1
  goto CountA1S
CountA1S
  movfw CountA1
  addlw LEDDARK
  bc CountA1E
  movfw CountA1
  call GetNextPWM
  subwf CountPWM,w
  skpnz
  bcf OutLatchA,1
CountA1E

  movfw CountA2
  btfss Flags,0
  goto CountA2S
  bsf OutLatchA,2
  decfsz CountA2,f
  goto CountA2S
  call GetNextVal
  movwf CountA2
  goto CountA2S
CountA2S
  movfw CountA2
  addlw LEDDARK
  bc CountA2E
  movfw CountA2
  call GetNextPWM
  subwf CountPWM,w
  skpnz
  bcf OutLatchA,2
CountA2E

  movfw CountA3
  btfss Flags,0
  goto CountA3S
  bsf OutLatchA,3
  decfsz CountA3,f
  goto CountA3S
  call GetNextVal
  movwf CountA3
  goto CountA3S
CountA3S
  movfw CountA3
  addlw LEDDARK
  bc CountA3E
  movfw CountA3
  call GetNextPWM
  subwf CountPWM,w
  skpnz
  bcf OutLatchA,3
CountA3E

  movfw CountA4
  btfss Flags,0
  goto CountA4S
  bcf OutLatchA,4
  decfsz CountA4,f
  goto CountA4S
  call GetNextVal
  movwf CountA4
  goto CountA4S
CountA4S
  movfw CountA4
  addlw LEDDARK
  bc CountA4E
  movfw CountA4
  call GetNextPWM
  subwf CountPWM,w
  skpnz
  bsf OutLatchA,4
CountA4E

  movfw CountB0
  btfss Flags,0
  goto CountB0S
  bsf OutLatchB,0
  decfsz CountB0,f
  goto CountB0S
  call GetNextVal
  movwf CountB0
  goto CountB0S
CountB0S
  movfw CountB0
  addlw LEDDARK
  bc CountB0E
  movfw CountB0
  call GetNextPWM
  subwf CountPWM,w
  skpnz
  bcf OutLatchB,0
CountB0E

  movfw CountB1
  btfss Flags,0
  goto CountB1S
  bsf OutLatchB,1
  decfsz CountB1,f
  goto CountB1S
  call GetNextVal
  movwf CountB1
  goto CountB1S
CountB1S
  movfw CountB1
  addlw LEDDARK
  bc CountB1E
  movfw CountB1
  call GetNextPWM
  subwf CountPWM,w
  skpnz
  bcf OutLatchB,1
CountB1E

  movfw CountB2
  btfss Flags,0
  goto CountB2S
  bsf OutLatchB,2
  decfsz CountB2,f
  goto CountB2S
  call GetNextVal
  movwf CountB2
  goto CountB2S
CountB2S
  movfw CountB2
  addlw LEDDARK
  bc CountB2E
  movfw CountB2
  call GetNextPWM
  subwf CountPWM,w
  skpnz
  bcf OutLatchB,2
CountB2E

  movfw CountB3
  btfss Flags,0
  goto CountB3S
  bsf OutLatchB,3
  decfsz CountB3,f
  goto CountB3S
  call GetNextVal
  movwf CountB3
  goto CountB3S
CountB3S
  movfw CountB3
  addlw LEDDARK
  bc CountB3E
  movfw CountB3
  call GetNextPWM
  subwf CountPWM,w
  skpnz
  bcf OutLatchB,3
CountB3E

  movfw CountB4
  btfss Flags,0
  goto CountB4S
  bsf OutLatchB,4
  decfsz CountB4,f
  goto CountB4S
  call GetNextVal
  movwf CountB4
  goto CountB4S
CountB4S
  movfw CountB4
  addlw LEDDARK
  bc CountB4E
  movfw CountB4
  call GetNextPWM
  subwf CountPWM,w
  skpnz
  bcf OutLatchB,4
CountB4E

  movfw CountB5
  btfss Flags,0
  goto CountB5S
  bsf OutLatchB,5
  decfsz CountB5,f
  goto CountB5S
  call GetNextVal
  movwf CountB5
  goto CountB5S
CountB5S
  movfw CountB5
  addlw LEDDARK
  bc CountB5E
  movfw CountB5
  call GetNextPWM
  subwf CountPWM,w
  skpnz
  bcf OutLatchB,5
CountB5E

  movfw CountB6
  btfss Flags,0
  goto CountB6S
  bsf OutLatchB,6
  decfsz CountB6,f
  goto CountB6S
  call GetNextVal
  movwf CountB6
  goto CountB6S
CountB6S
  movfw CountB6
  addlw LEDDARK
  bc CountB6E
  movfw CountB6
  call GetNextPWM
  subwf CountPWM,w
  skpnz
  bcf OutLatchB,6
CountB6E

  movfw OutLatchA
  movwf PORTA

  movfw OutLatchB
  movwf PORTB

  bcf INTCON,T0IF

Inter_NoTimer

Inter_Return
  retfie

  end
