Listing 1. This program outputs PWM on port B pins 0 and 1. ;; PWM Demo for 16F877 with ICD ;; Al Williams PROCESSOR 16F877 __CONFIG 0x3FF6 INCLUDE ; PIC include file ; NOTE: ICD uses RAM at 0x70 and 0x1EB-0x1EF W_TEMP EQU 0x7F ; shared between banks STATUS_TEMP EQU 0x6F PCLATH_TEMP EQU 0x6E PWM0 EQU 0x20 DUTY0 EQU 0x21 PWM1 EQU 0x22 DUTY1 EQU 0x23 IMAGE EQU 0x24 ; port image TICK_L EQU 0x25 TICK_H EQU 0x26 FLAGS EQU 0x27 TIMEOUT EQU 0 ORG 0 NOP ; ICD Wants a NOP here GOTO START ORG 4 ; ISR MOVWF W_TEMP ;Copy W to TEMP register SWAPF STATUS,W ;Swap status to be saved into W CLRF STATUS ;bank 0, regardless of current bank, Clears IRP,RP1,RP0 MOVWF STATUS_TEMP ;Save status to bank zero STATUS_TEMP register MOVF PCLATH, W ;Only required if using pages 1, 2 and/or 3 MOVWF PCLATH_TEMP ;Save PCLATH into W CLRF PCLATH ;Page zero, regardless of current page MOVF DUTY0,W ADDWF PWM0,F ; change port and keep time constant BTFSS STATUS,C BCF IMAGE,0 BTFSC STATUS,C BSF IMAGE,0 MOVF DUTY1,W ADDWF PWM1,F ; change port and keep time constant BTFSS STATUS,C BCF IMAGE,1 BTFSC STATUS,C BSF IMAGE,1 ISROUT: MOVF IMAGE,W MOVWF PORTB ; do real output BTFSC FLAGS,TIMEOUT GOTO NOTICK MOVLW 1 SUBWF TICK_L,F BTFSS STATUS,C DECF TICK_H,F MOVF TICK_L,W IORWF TICK_H,W BTFSC STATUS,Z BSF FLAGS,TIMEOUT NOTICK: ; adjust TMR0 to turn over in 250 cycles ; @20MHz this gives a 50uS tick instead of 51.2uS MOVLW 6 ADDWF TMR0,F MOVF PCLATH_TEMP, W ;Restore PCLATH MOVWF PCLATH ;Move W into PCLATH SWAPF STATUS_TEMP,W ;Swap STATUS_TEMP register into W ;(sets bank to original state) MOVWF STATUS ;Move W into STATUS register SWAPF W_TEMP,F ;Swap W_TEMP SWAPF W_TEMP,W ;Swap W_TEMP into W BCF INTCON,T0IF RETFIE START: CLRF DUTY0 CLRF DUTY1 CLRF PWM0 CLRF PWM1 CLRF PORTB ; output 0's CLRF IMAGE CLRF TICK_L CLRF TICK_H CLRF FLAGS BSF FLAGS,TIMEOUT ; start timedout MOVLW 0xFC ; bit 0 and 1 are outputs BSF STATUS,RP0 MOVWF PORTB ; direction register MOVLW 0x0F ; pullups on, timer on MOVWF OPTION_REG&0x7F BCF STATUS,RP0 MOVLW 0xA0 ; timer 0 interrupt on MOVWF INTCON MLOOP: ; Set up a 1 second pause ; Since timeout=1, no chance ISR ; will mess up the count in the middle! MOVLW 0x4E MOVWF TICK_H MOVLW 0x20 MOVWF TICK_L BCF FLAGS,TIMEOUT ; GO GO GO ; wait for 1 second ILOOP: BTFSS FLAGS,TIMEOUT GOTO ILOOP ; DUTY0++, DUTY1-- INCF DUTY0,F DECF DUTY1,F GOTO MLOOP END