; PWM port (in w), pin, duty
; Generates a bit stream of 256 1s and 0s with the specified
; duty cycle. If this bit stream is run through a simple RC
; integrator, the result is an analog voltage output of
; (duty/255) * (PIC supply voltage). For example, if duty is
; 100 and the supply is 5 volts, then the integrated output of
; pwm would be (100/255) * 5 = 1.96 volts. In many applications,
; pwm output should be buffered with a unity-gain op-amp
; circuit. In those cases, the pwm output pin should be set up
; as an output when Pwm is called, then immediately switched to
; input when Pwm is done. This prevents the steady-state output
; of the pin from affecting the voltage set by Pwm.
org 8
duty ds 1 ; Pwm duty cycle.
acc ds 1 ; Pwm accumulator.
index ds 1 ; Temporary counter for pwm.
pin ds 1 ; Pin number to pulse (0-7).
; Device data and reset vector
device pic16c55,xt_osc,wdt_off,protect_off
reset start
org 0
; Table to convert pin number (0-7) into bit mask (00000001b to 10000000b).
Pinz jmp pc+w
retw 1,2,4,8,16,32,64,128
start mov !ra, #0 ; All outputs.
clr ra ; Start with LED off.
clr duty ; Initial brightness = 0.
clr index ; Clear loop counter for pwm.
:loop mov pin,#2 ; Pin 2.
mov w,#0 ; of port ra.
CALL PWM ; Send pwm to LED.
inc duty ; Turn up brightness.
jmp :loop ; Endless loop
; Upon entry, the desired pin must already be set up as an output.
; Variable "pin" contains the pin number (0-7). The w register contains a
; number representing the output port (0-2) for RA through RC. The variable
; duty contains the desired duty cycle from 0 to 255.
PWM mov fsr,w ; Point to the port number.
add fsr,#RA ; Add offset for port RA.
mov w,pin
CALL Pinz ; Get bit mask from the table.
mov pin,w ; Put the mask into pin.
:loop add acc,duty ; Let acc = acc + duty
mov w,pin
snc ; IF carry THEN pin = 1
OR indirect,w ; ELSE pin = 0.
mov w,/pin
sc
AND indirect,w
djnz index,:loop ; Repeat 256 times.
ret
BACK