; Timer Experiment list p=16F628 #include #include "macross.inc" __CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _BODEN_OFF &_INTRC_OSC_NOCLKOUT & _MCLRE_OFF & _LVP_OFF ERRORLEVEL -302 ; Each 1-bit dac is maintained as 2 bytes: ; the brightness and the running-sum. ; (a third byte is sometimes the "target brightness") ; Put the current 1-bit dac on-offness ; into the specified bit of the dest ; cycles: 3 StepDac MACRO dacState,destReg,destBit MOVFW dacState ADDWF dacState+1,F IFC BSF destReg,destBit IFNC BCF destReg,destBit ENDM CopyBit MACRO sourceReg,sourceBit,destReg,destBit IFBS sourceReg,sourceBit BSF destReg,destBit IFBC sourceReg,sourceBit BCF destReg,destBit ENDM DacStateCurrentLinear EQU 0 DacStateRunningSum EQU 1 DacStateTarget EQU 2 DacStateRate EQU 3 DacStateCurrentLow EQU 4 DacStateCurrentHigh EQU 5 StepBrightness MACRO dacState LOCAL _doBumpUp,_didBump,_upperHalf,_done MOVFW dacState+DacStateCurrentHigh SUBWF dacState+DacStateTarget,W ; target - current: positive sets C and means, increment towards ; negative clears C and means, decrement towards IFZ GOTO _didBump MOVFW dacState+DacStateRate ; moving up IFC GOTO _doBumpUp ; GOTO _didBump ; SUBWF dacState+DacStateCurrentLow,F ; IFNC DECF dacState+DacStateCurrentHigh,F ; MOVFF dacState+DacStateTarget,dacState+DacStateCurrentHigh ; just slam it NOT RIGHT GOTO _didBump _doBumpUp: ADDWF dacState+DacStateCurrentLow,F IFC INCF dacState+DacStateCurrentHigh,F _didBump: IFBS dacState+DacStateCurrentHigh,7 GOTO _upperHalf ; we are in lower half of brightness range, slow it down ; map 0-0x7f into 0-0x3f BCF STATUS,C RRF dacState+DacStateCurrentHigh,W MOVWF dacState+DacStateCurrentLinear GOTO _done _upperHalf: ; we are in upper half of brighness range, speed it up ; map 0x80-0xff into 0x40-0xff ; f(x) = 0x40 + (x - 0x80) + (x - 0x80) / 2 ; f(x) = 0x40 + (x - 0x80) + x/2 - 0x40 ; f(x) = x + x/2 - 0x80 BCF STATUS,C RRF dacState+DacStateCurrentHigh,W ; x/2 ADDWF dacState+DacStateCurrentHigh,W ; +x ADDLW 0x80 MOVWF dacState+DacStateCurrentLinear _done: ;MOVFF dacState+DacStateCurrentHigh,dacState+DacStateCurrentLinear ENDM ; All-bank variables (16 bytes) CBLOCK 70h wTemp statusTemp cblock70End ENDC IF cblock70End > 0x7F ERROR "CBLOCK70 exceeded" ENDIF ; Bank 0 variables (80 bytes) CBLOCK 20h ; port shadows, ports themselves are in Bank 0, so. portAShadow portBShadow ; delay del0 del1 ; irq blinker irqCount ; LED brightnesses ; each one uses 5 bytes: ; 0: linear brightness ; 1: running sum for DAC ; 2: target true brightness ; 3: approach rate ; 4: true brightness low ; 5: true brightness high led0:6 ; 1st: linear brightness, 2nd: running sum, 3rd: target brightness led1:6 led2:6 cblock20End ENDC IF cblock20End > 0x6f ERROR "CBLOCK20 exceeded" ENDIF ; ok. org 0x0000 goto INIT org 0x0004 goto IRQ #include "bitsets.inc" DELAY: INCFSZ del0,F GOTO DELAY INCFSZ del1,F GOTO DELAY RETURN ; Advance all the dacs we need. ; It's a subroutine, so can call it during the IRQ, as well. ; Anything, everything to reduce flicker. StepDacs: StepDac led0,portAShadow,0 StepDac led1,portAShadow,1 StepDac led2,portAShadow,2 CALL MPUTSA CopyBit portAShadow,0,portBShadow,4 CALL MPUTSB RETURN INIT: ; + -------------------------------- ; | Hardware setup ; | as per datasheet, set up port, tris, and CMCON. MOVLW 0x07 MOVWF CMCON ; no comparitors on PORTA thanks CLRF PORTA CLRF PORTB CLRF portAShadow CLRF portBShadow BANK1 CLRF TRISA ; Port A is output CLRF TRISB ; Port B is output BANK0 ; +----------------------------------- ; | led values MOVLF 0x80,led0 MOVLF 0xc0,led1 MOVLF 0x00,led2 MOVLF 0xFF,led0+DacStateTarget MOVLF 0x00,led0+DacStateCurrentHigh MOVLF 0x07,led0+DacStateRate MOVLF 0xFF,led1+DacStateTarget MOVLF 0x00,led1+DacStateCurrentHigh MOVLF 0x0a,led1+DacStateRate MOVLF 0xFF,led2+DacStateTarget MOVLF 0x00,led2+DacStateCurrentHigh MOVLF 0x05,led2+DacStateRate ; set up timer interrupt\ BANK1 BCF OPTION_REG,T0CS BCF OPTION_REG,PSA BSF OPTION_REG,PS2 BCF OPTION_REG,PS1 BCF OPTION_REG,PS0 BANK0 BSF INTCON,T0IE BSF INTCON,GIE ; +--------------------------- ; | the only foreground task is to maintain ; | the brightnesses of all the LEDs. Enjoy! ledLoop: BCF INTCON,GIE CALL StepDacs CALL MPUTSA BSF INTCON,GIE GOTO ledLoop loop: CALL DELAY BSPA1 CALL DELAY BCPA1 GOTO loop IRQ: IntStart wTemp,statusTemp BANK0 INCF irqCount,F StepBrightness led0 CALL StepDacs ; StepBrightness led1 CALL StepDacs ; StepBrightness led2 CALL StepDacs MOVFW led0+DacStateCurrentHigh SUBWF led0+DacStateTarget,W IFNZ GOTO leaveLed0Alone MOVLW 0xff XORWF led0+DacStateTarget,W MOVWF led0+DacStateTarget MOVWF led2+DacStateCurrentLinear MOVLW 0x47 ADDWF led1+DacStateCurrentLinear,F leaveLed0Alone: MOVLF 0,TMR0 BCF INTCON,T0IF ; clear the timer irq IntFinish wTemp,statusTemp RETFIE END