Code:
TITLE 'SUPER PWM FOR 12-BIT PIC'
;--------------------------------------------------------------------------------------------------------------------------------------
; PROGRAM DESCRIPTION
;--------------------------------------------------------------------------------------------------------------------------------------
;
; THIS EXAMPLE SHOWS HOW TO CREATE A HIGH RESOLUTION VARIABLE PWM IN A 12-BIT PIC
;
; FEATURES:
; 16-BIT BIT-BANG PWM
; VARIABLE PERIOD
; VARIABLE DUTY CYCLE
; INSTRUCTION CYCLE RESOLUTION
; NO INTERRUPTS
;
; THIS PROGRAM EXECUTES THE MAIN PROGRAM CODE IN SMALL CHUNKS, BETWEEN THESE CHUNKS THE PROGRAM LOOKS AT THE TIMER VALUE AND
; UPDATES THE OUTPUT WHEN NEEDED
;
; NOTE: DUE TO THE TIMER OVERHEAD THERE IS A LIMIT TO THE MAXIMUM FREQUENCY (VERY SHORT PERIODS ARE NOT POSSIBLE WITH THIS CODE)
;
;--------------------------------------------------------------------------------------------------------------------------------------
; CONSTANTS DEFINITIONS
;--------------------------------------------------------------------------------------------------------------------------------------
; GPIO BITS
PWM EQU 0 ; PWM OUTPUT (ACTIVE HIGH)
;--------------------------------------------------------------------------------------------------------------------------------------
; VARIABLE DEFINITIONS
;--------------------------------------------------------------------------------------------------------------------------------------
CBLOCK H'10'
TIMER_LOW ; ENABLE PROBLEM FREE (ROLLOVER FREE) TESTING AND COPYING OF THE TIMER
TIMER_HIGH ; USED TO EXTEND THE TIMER0 RESOLUTION TO A 16-BIT TOTAL
CALCPOINTER ; USED TO SEQUENTIALLY PERFORM ALL CALCULATIONS
A0 ; PWM HIGH TIME (INSTRUCTION CYCLES)
A1 ;
B0 ; PWM LOW TIME (INSTRUCTION CYCLES) TO BE COPIED TO Y
B1 ;
Y0 ; PWM LOW TIME (INSTRUCTION CYCLES)
Y1 ;
ENDC
;--------------------------------------------------------------------------------------------------------------------------------------
; START OF PROGRAM
;--------------------------------------------------------------------------------------------------------------------------------------
ORG H'000' ; TELL THE ASSEMBLER TO PLACE FOLLOWING PROGRAM CODE AT BOTTOM OF THE PROGRAM MEMORY
START MOVLW B'00000000' ; MAKE GP0(PWM) LOW: PWM OFF
MOVWF GPIO ;
MOVLW B'11111110' ; MAKE GP0(PWM) OUTPUT
TRIS GPIO ;
CLRF ADCON0 ; AD-CONVERTER OFF
CLRWDT ; WE NEED TO CLEAR THE WATCHDOG TIMER FIRST OR ELSE WE MAY GET A RESET, ALSO CLEARS PRESCALER
CLRF TMR0 ; CLEAR TIMER0 AND THE PRESCALER
MOVLW B'11001111' ; VALUE FOR NO WAKE-UP ON PIN CHANGE, NO PULL-UPS, TMR0 FROM INSTRUCTION CLOCK 1:1, ASSIGN THE
OPTION ; PRESCALER TO THE WATCHDOG 1:128 (2.3 SECOND WATCHDOG TIMEOUT)
CLRF A0 ; PWM FREQUENCY IS 100 HZ SO PWM PERIOD IS 10000 INSTRUCTIONS (FOSC = 4 MHZ)
CLRF A1 ; A1:A0 = PWM HIGH TIME = 0
MOVLW D'16' ; B1:B0 = PWM LOW TIME = 10000 = 39:16
MOVWF B0 ;
MOVLW D'39' ;
MOVWF B1 ;
GOTO PWM_DOWNFLANK_4 ; NOW GO RUN PWM LOOP
;--------------------------------------------------------------------------------------------------------------------------------------
; PWM CODE
;--------------------------------------------------------------------------------------------------------------------------------------
JUMP_TO_CALC MOVF CALCPOINTER,W ; WE PERFORM ALL CALCULATION PARTS SEQUENTIALLY SINCE WE MUST ALLOW TIME FOR THE MAIN LOOP
MOVWF PCL ; JUMP TO CALCULATION
; NOTE: FOR THIS 12-BIT PROCESSOR WE CAN ONLY JUMP THIS WAY IN THE LOWER 256 MEMORY LOCATIONS,
; BECAUSE THE 8TH BIT WILL ALWAYS BE RESET TO ZERO
;--------------------------------------------------------------------------------------------------------------------------------------
WAIT4DOWNFLANK CALL JUMP_TO_CALC ; GO DO MAIN STUFF AND PWM CALCULATIONS (THIS LINE CAN TAKE UP TO 36 INSTRUCTION CYCLES)
MOVWF CALCPOINTER ; USE RETURN VALUE TO KEEP TRACK OF CALCULATION PROGRESS
MOVF TMR0,W ; WE WANT A COPY FOR PROBLEM FREE (ROLLOVER FREE) TESTING AND COPYING OF THE TIMER VALUE
SUBWF TIMER_LOW,F ; TEST FOR ROLLOVER, WE NEED TO BE HERE AT LEAST EVERY 256 INSTRUCTIONS OR WE'LL MISS ROLLOVER
MOVWF TIMER_LOW ;
SKPNC ; HAS TMR0 ROLLED OVER ?
INCF TIMER_HIGH,F ; YES, INCREMENT TIMER HIGH BYTE
MOVLW D'105' ; SEE IF IS TIME TO UPDATE THE PWM OUTPUT OR IF WE CAN DO THE OTHER STUFF
ADDWF TIMER_LOW,W ; CHECK FOR ROLLOVER: T+36+25+44 = T + 105 = 256 = ROLLOVER, SO WE NEED TO ADD 105
SKPNC ; ROLLOVER ?
INCFSZ TIMER_HIGH,W ; IS THERE TIME LEFT FOR THE OTHER TASKS ?
GOTO WAIT4DOWNFLANK ; YES, GO DO THESE OTHER TASKS
;--------------- ----------------------------------------------------------------------------------------------
MOVLW D'44' ; CORRECT FOR OVERHEAD, WE WANT TO CHANGE THE PWM OUTPUT AT EXACT MOMENT OF TIMER ROLLOVER
ADDWF TMR0,F ; RESULT OF THIS ADD MUST BE 255 MAXIMUM OR WE GET ILLEGAL JUMP
; REMEMBER TIMER KEEPS THE NEW VALUE FOR THREE FOLLOWING CYCLES BEFORE INCREMENTING
; BUT WE ALREADY START TESTING TIMER VALUE
LOOP_1 BTFSC TMR0,7 ; HAS TIMER 0 ROLLED OVER ?
GOTO LOOP_1 ; NO, LOOP AGAIN
DECF TMR0,W ; W=1,2,3
ADDWF PCL,F ; NOTE: FOR THIS 12-BIT PROCESSOR WE CAN ONLY JUMP THIS WAY IN THE LOWER 256 MEMORY LOCATIONS,
; REMEMBER THAT THE 8TH BIT OF THE PROGRAM COUNTER WILL ALWAYS BE RESET TO ZERO
C0 RETLW LOW(C0) ; PCL+0 ALL CALCULATIONS DONE, WAITING FOR START OF NEW PWM PERIOD
NOP ; PCL+1
NOP ; PCL+2
COMF Y0,W ; PCL+3, SET NEW TIME SETPOINT:
MOVWF TMR0 ; T = 65535 - Y = 65535 - PWM LOW TIME
MOVWF TIMER_LOW ;
COMF Y1,W ;
MOVWF TIMER_HIGH ;
;--------------- ----------------------------------------------------------------------------------------------
CHOOSE_DELAY_1 MOVLW D'123' ; PCL+3, SHORTEST TIME FOR LONG DELAY IS 123? INSTRUCTIONS (INCLUDING MEAS/CALC)
SUBWF Y0,W ; CARRY IS CLEAR WHEN LESS
MOVF Y1,W ; TEST HIGH BYTE OF DELAY TIME FOR ZERO
SKPNZ ; IS THE HIGH BYTE ZERO ?
SKPNC ; YES, IS THE LOW BYTE LESS THAN 123 ?
GOTO PWMLONGDELAY2 ; NO, HIGH BYTE IS NOT ZERO/NO, LOW BYTE IS MORE, GO USE THE LONG DELAY LOOP
MOVLW D'16' ; VARIABLE DELAY FROM 0..255 INSTRUCTIONS
SUBWF Y0,W ; CHECK THE DELAY TIME
SKPC ; IS THE DESIRED DELAY MORE THAN 16 ?
GOTO LOW_VERYSHORT ; NO, SO THE PWM LOW TIME IS VERY SMALL: 0..15 CYCLES, GO USE THE VERY SHORT DELAY
;--------------- ----------------------------------------------------------------------------------------------
PWM_LOW_SHORT MOVWF TIMER_HIGH ; SET DELAY
GOTO $+1 ; THREE INSTRUCTION CYCLE DELAY
NOP ;
MOVLW D'4' ; NEEDED FOR ADJUSTABLE DELAY
PWM_DOWNFLANK_1 BCF GPIO,PWM ; MAKE THE PWM OUTPUT LOW
LOOP_2 SUBWF TIMER_HIGH,F ; WE USE AN ADJUSTABLE DELAY
SKPNC ;
GOTO LOOP_2 ;
COMF TIMER_HIGH,W ;
IORLW B'00001000' ; ADD 8 TO W TO JUMP OVER VERY SHORT DELAY
ADDWF PCL,F ; NOTE: FOR THIS 12-BIT PROCESSOR WE CAN ONLY JUMP THIS WAY IN THE LOWER 256 MEMORY LOCATIONS,
; REMEMBER THAT THE 8TH BIT WILL ALWAYS BE RESET TO ZERO
;--------------- ----------------------------------------------------------------------------------------------
LOW_VERYSHORT ADDWF Y0,W ; INVERT W AND THEN INCREMENT W
SUBWF Y0,W ;
ADDWF PCL,F ; NOTE: FOR THIS 12-BIT PROCESSOR WE CAN ONLY JUMP THIS WAY IN THE LOWER 256 MEMORY LOCATIONS,
; REMEMBER THAT THE 8TH BIT WILL ALWAYS BE RESET TO ZERO
NOP ; PCL+0
PWM_DOWNFLANK_2 BCF GPIO,PWM ; 15, PCL+1, MAKE THE PWM OUTPUT LOW
BCF GPIO,PWM ; 14, PCL+2
BCF GPIO,PWM ; 13
BCF GPIO,PWM ; 12
BCF GPIO,PWM ; 11
BCF GPIO,PWM ; 10
BCF GPIO,PWM ; 9
BCF GPIO,PWM ; 8
BCF GPIO,PWM ; 7
BCF GPIO,PWM ; 6
BCF GPIO,PWM ; 5
BCF GPIO,PWM ; 4
BCF GPIO,PWM ; 3
BCF GPIO,PWM ; 2
BCF GPIO,PWM ; 1
;--------------- ----------------------------------------------------------------------------------------------
PWM_UPFLANK_1 BSF GPIO,PWM ; 0: MAKE THE PWM OUTPUT HIGH
MOVF B0,W ; COPY NEW PWM TIMING VALUES:
MOVWF Y0 ; Y = B = PWM LOW TIME
MOVF B1,W ;
MOVWF Y1 ;
MOVLW LOW(C1) ; START NEW CALCULATIONS
MOVWF CALCPOINTER ;
COMF A1,W ; SET NEW TIME SETPOINT:
MOVWF TIMER_HIGH ; T = 65535 - A = 65535 - PWM HIGH TIME
COMF A0,W ;
MOVWF TMR0 ; THE EXACT MOMENT OF WRITING THE NEW VALUE TO TMR0 IS CRITICAL
MOVWF TIMER_LOW ;
GOTO WAIT4DOWNFLANK ;
;--------------------------------------------------------------------------------------------------------------------------------------
;--------------------------------------------------------------------------------------------------------------------------------------
PWMLONGDELAY2 CALL C0 ; EIGHT CYCLE DELAY
CALL C0 ;
PWM_DOWNFLANK_3 BCF GPIO,PWM ; MAKE THE PWM OUTPUT LOW
;--------------- ----------------------------------------------------------------------------------------------
WAIT4UPFLANK CALL JUMP_TO_CALC ; GO DO MAIN STUFF AND PWM CALCULATIONS (THIS LINE CAN TAKE UP TO 36 INSTRUCTION CYCLES)
MOVWF CALCPOINTER ; USE RETURN VALUE TO KEEP TRACK OF CALCULATION PROGRESS
MOVF TMR0,W ; WE WANT A COPY FOR PROBLEM FREE (ROLLOVER FREE) TESTING AND COPYING OF THE TIMER VALUE
SUBWF TIMER_LOW,F ; TEST FOR ROLLOVER, WE NEED TO BE HERE AT LEAST EVERY 256 INSTRUCTIONS OR WE'LL MISS ROLLOVER
MOVWF TIMER_LOW ;
SKPNC ; HAS TMR0 ROLLED OVER ?
INCF TIMER_HIGH,F ; YES, INCREMENT TIMER HIGH BYTE
MOVLW D'72' ; SEE IF IS TIME TO UPDATE THE PWM OUTPUT OR IF WE CAN DO THE OTHER STUFF
ADDWF TIMER_LOW,W ; CHECK FOR ROLLOVER: T+36+25+11 = T + 72 = 256 = ROLLOVER, SO WE NEED TO ADD 72
SKPNC ; ROLLOVER ?
INCFSZ TIMER_HIGH,W ; IS THERE TIME LEFT FOR THE OTHER TASKS ?
GOTO WAIT4UPFLANK ; YES, GO DO THESE OTHER TASKS
;--------------- ----------------------------------------------------------------------------------------------
MOVLW D'11' ; CORRECT FOR OVERHEAD, WE WANT TO CHANGE THE PWM OUTPUT AT EXACT MOMENT OF TIMER ROLLOVER
ADDWF TMR0,F ; RESULT OF THIS ADD MUST BE 255 MAXIMUM OR WE GET ILLEGAL JUMP
; REMEMBER TIMER KEEPS THE NEW VALUE FOR THREE FOLLOWING CYCLES BEFORE INCREMENTING
; BUT WE ALREADY START TESTING TIMER VALUE
LOOP_3 BTFSC TMR0,7 ; HAS TIMER 0 ROLLED OVER ?
GOTO LOOP_3 ; NO, LOOP AGAIN
DECF TMR0,W ; W=1,2,3
ADDWF PCL,F ; NOTE: FOR THIS 12-BIT PROCESSOR WE CAN ONLY JUMP THIS WAY IN THE LOWER 256 MEMORY LOCATIONS,
; REMEMBER THAT THE 8TH BIT OF THE PROGRAM COUNTER WILL ALWAYS BE RESET TO ZERO
NOP ; PCL+0
NOP ; PCL+1
NOP ; PCL+2
COMF A0,W ; PCL+3, SET NEW TIME SETPOINT:
MOVWF TMR0 ; T = 65535 - A = 65535 - NEW PWM HIGH TIME
MOVWF TIMER_LOW ; THE EXACT MOMENT OF WRITING THE NEW VALUE TO TMR0 IS CRITICAL
COMF A1,W ;
MOVWF TIMER_HIGH ;
;--------------- ----------------------------------------------------------------------------------------------
CHOOSE_DELAY_2 MOVLW D'123' ; PCL+3, SHORTEST TIME FOR LONG DELAY IS 123? INSTRUCTIONS (INCLUDING MEAS/CALC)
SUBWF A0,W ; CARRY IS CLEAR WHEN LESS
MOVF A1,W ; TEST HIGH BYTE OF DELAY TIME FOR ZERO
SKPNZ ; IS THE HIGH BYTE ZERO ?
SKPNC ; YES, IS THE LOW BYTE LESS THAN 123 ?
GOTO DELAYED_JUMP ; NO, HIGH BYTE IS NOT ZERO/NO, LOW BYTE IS MORE, GO USE THE LONG DELAY LOOP
MOVLW D'16' ; VARIABLE DELAY FROM 0..255 INSTRUCTIONS
SUBWF A0,W ; CHECK THE DELAY TIME
SKPC ; IS THE DESIRED DELAY MORE THAN 16 ?
GOTO HIGH_VERYSHORT ; NO, SO THE PWM LOW TIME IS VERY SMALL: 0..15 CYCLES, GO USE THE VERY SHORT DELAY
;--------------- ----------------------------------------------------------------------------------------------
PWM_HIGH_SHORT MOVWF TIMER_HIGH ; SET DELAY
GOTO $+1 ; THREE INSTRUCTION CYCLE DELAY
NOP ;
MOVLW D'4' ; NEEDED FOR ADJUSTABLE DELAY
PWM_UPFLANK_2 BSF GPIO,PWM ; MAKE THE PWM OUTPUT HIGH
LOOP_4 SUBWF TIMER_HIGH,F ; WE USE AN ADJUSTABLE DELAY
SKPNC ;
GOTO LOOP_4 ;
COMF TIMER_HIGH,W ;
IORLW B'00001000' ; ADD 8 TO W TO JUMP OVER VERY SHORT DELAY
ADDWF PCL,F ; NOTE: FOR THIS 12-BIT PROCESSOR WE CAN ONLY JUMP THIS WAY IN THE LOWER 256 MEMORY LOCATIONS,
; REMEMBER THAT THE 8TH BIT WILL ALWAYS BE RESET TO ZERO
;--------------- ----------------------------------------------------------------------------------------------
HIGH_VERYSHORT ADDWF A0,W ; INVERT W AND THEN INCREMENT W
SUBWF A0,W ;
ADDWF PCL,F ; NOTE: FOR THIS 12-BIT PROCESSOR WE CAN ONLY JUMP THIS WAY IN THE LOWER 256 MEMORY LOCATIONS,
; REMEMBER THAT THE 8TH BIT WILL ALWAYS BE RESET TO ZERO
NOP ; PCL+0
PWM_UPFLANK_3 BSF GPIO,PWM ; 15, PCL+1, MAKE THE PWM OUTPUT HIGH
BSF GPIO,PWM ; 14, PCL+2
BSF GPIO,PWM ; 13
BSF GPIO,PWM ; 12
BSF GPIO,PWM ; 11
BSF GPIO,PWM ; 10
BSF GPIO,PWM ; 9
BSF GPIO,PWM ; 8
BSF GPIO,PWM ; 7
BSF GPIO,PWM ; 6
BSF GPIO,PWM ; 5
BSF GPIO,PWM ; 4
BSF GPIO,PWM ; 3
BSF GPIO,PWM ; 2
BSF GPIO,PWM ; 1
;--------------- ----------------------------------------------------------------------------------------------
IF $ > H'FF' ; LET THE ASSEMBLER WARN US IF WE PUT THE FOLLOWING INSTRUCTION AT AN ADDRESS > 255
ERROR 'WE CANNOT JUMP TO THIS LOCATION !'
ENDIF ;
; REMEMBER THAT ALL SUBROUTINE CALLS OR COMPUTED JUMPS ARE LIMITED TO THE FIRST 256 PROGRAM
; MEMORY LOCATIONS ! WE CAN'T USE "ADDWF PCL,F","CALL","MOVWF PCL,F" OR "BSF PCL,X"
; INSTRUCTIONS TO JUMP TO AN ADDRESS > 255, BUT WE CAN STILL USE 'GOTO' AND 'RETLW'.
;--------------- ----------------------------------------------------------------------------------------------
PWM_DOWNFLANK_4 BCF GPIO,PWM ; 0: MAKE THE PWM OUTPUT LOW
MOVLW D'29' ; MAKE CORRECTION
SUBWF B0,F ;
SKPC ;
DECF B1,F ;
COMF B0,W ; SET NEW TIME SETPOINT:
MOVWF TMR0 ; T = 65535 - B = 65535 - PWM HIGH TIME
MOVWF TIMER_LOW ; THE EXACT MOMENT OF WRITING THE NEW VALUE TO TMR0 IS CRITICAL
COMF B1,W ;
MOVWF TIMER_HIGH ;
MOVLW LOW(C1) ; START NEW CALCULATIONS
MOVWF CALCPOINTER ;
GOTO WAIT4UPFLANK ;
;--------------------------------------------------------------------------------------------------------------------------------------
DELAYED_JUMP GOTO $+1 ;
GOTO PWM_UPFLANK_1 ;
;--------------------------------------------------------------------------------------------------------------------------------------
; MAIN PROGRAM CODE
;--------------------------------------------------------------------------------------------------------------------------------------
C1 ; MAIN PROGRAM CODE GOES HERE (NOT MORE THAN 32 INSTRUCTION CYCLES)
RETLW LOW(C2) ; THIS PART OF CALCULATIONS DONE
;--------------------------------------------------------------------------------------------------------------------------------------
C2 ; ..MORE PROGRAM CODE GOES HERE (NOT MORE THAN 32 INSTRUCTION CYCLES)
RETLW LOW(C3) ; THIS PART OF CALCULATIONS DONE
;--------------------------------------------------------------------------------------------------------------------------------------
C3 ; ..MORE PROGRAM CODE GOES HERE (NOT MORE THAN 32 INSTRUCTION CYCLES)
RETLW LOW(C4) ; THIS PART OF CALCULATIONS DONE
;--------------------------------------------------------------------------------------------------------------------------------------
C4 ; ..MORE PROGRAM CODE GOES HERE (NOT MORE THAN 32 INSTRUCTION CYCLES)
RETLW LOW(C5) ; THIS PART OF CALCULATIONS DONE
;--------------------------------------------------------------------------------------------------------------------------------------
C5 ; NOTE: DO NOT CHANGE THE DUTY CYCLE FROM MINIMUM TO MAXIMUM (OR VICE VERSA) INSTANTLY,
; PUT SOME AVERAGING CODE HERE (OR THE PULSE WIDTH MAY BE AFFECTED TEMPORARILY)
MOVLW D'208' ; SET A1:A0 = PWM HIGH TIME = 2000 = 7:208
MOVWF A0 ;
MOVLW D'7' ;
MOVWF A1 ;
; NOW A IS NEW PWM HIGH TIME (TO BE USED IN PWM CODE)
MOVLW D'16' ; SET B1:B0 = PWM PERIOD = 10000 = 39:16
MOVWF B0 ;
MOVLW D'39' ;
MOVWF B1 ;
; NOW CALCULATE B, THE NUMBER OF INSTRUCTIONS THAT PWM OUTPUT IS LOW PER PWM PERIOD
MOVF A0,W ; B = B - A
SUBWF B0,F ;
MOVF A1,W ;
SKPC ;
INCFSZ A1,W ;
SUBWF B1,F ;
; NOW B IS NEW PWM LOW TIME (TO BE USED IN PWM CODE)
RETLW LOW(C0) ; ALL CALCULATIONS DONE !
;--------------------------------------------------------------------------------------------------------------------------------------
;--------------------------------------------------------------------------------------------------------------------------------------
ORG H'100' ; ADDRESS BEYOND THE JUMP RANGE OF A MODIFY PCL INSTRUCTION
C6 ; WE CANNOT MODIFY THE PCL REGISTER TO JUMP HERE DIRECTLY, BUT WE CAN PLACE A GOTO POINTING TO
; HERE IN THE LOWER PART OF THE MEMORY AND JUMP TO THE GOTO INSTEAD
; ..MORE PROGRAM CODE GOES HERE (NOT MORE THAN 32 INSTRUCTION CYCLES)
RETLW LOW(C0) ; THIS PART OF CALCULATIONS DONE
;--------------------------------------------------------------------------------------------------------------------------------------
END ; TELL THE ASSEMBLER TO STOP
;--------------------------------------------------------------------------------------------------------------------------------------
+
| file: /Techref/member/AT-planet-T9/superpwm.htm, 24KB, , updated: 2010/10/13 00:34, local time: 2025/10/25 03:49,
owner: AT-planet-T9,
216.73.216.180,10-8-63-169:LOG IN
|
| ©2025 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://massmind.org/Techref/member/AT-planet-T9/superpwm.htm"> Super Bit-Bang PWM for 12-bit PIC</A> |
| Did you find what you needed? |