Pulse Width Modulator using PIC16F84a

MMcLaren

Joined Feb 14, 2010
861
farscape,

Are you compelled to use only 5 duty cycle levels? Could you use 8 instead (0, 32, 64, 96, 128, 160, 192, 224)?

Anyway, I think you are very close.

Good luck on your project.

Mike
 

MMcLaren

Joined Feb 14, 2010
861
Your code is getting closer and closer in function to my original example.

I wonder if you couldn't eliminate the tables entirely by complementing the duty cycle or "on" time and using that for the "off" time?

Anyway, here's an example without tables using 8 pwm "steps" which I hope may help you Gentlemen get a little closer to your goal.

Kind regards, Mike

Rich (BB code):
processor 16F84A
INCLUDE <p16f84A.inc>
__CONFIG _CP_OFF & _WDT_OFF & _XT_OSC & _PWRTE_ON
org H'00'

portB    equ    0x06        
portA    equ    0x05
duty     equ    0x0c
timer    equ    0x0e
level    equ    0x0d

org     0x000

start 
        movlw   0x00        
        tris    portB        
        clrf    portB        
        movlw   0x1F        
        tris    portA        
        clrf    portA
        clrf    duty
cycle
        movlw   0xD3
        movwf   timer
loop
        movf    duty,W
        movwf   level
        bsf     portB,0         ; LED "on"
hi      decfsz  level,F
        goto    hi
        comf    duty,W
        movwf   level
        bcf     portB,0         ; LED "off"
lo      decfsz  level,F
        goto    lo
        decfsz  timer,F         ; timed out? yes, skip, else
        goto    loop
test0
        movf    duty,W          ; 0,32,64,...224
        addlw   0x20            ; add 32
        skpnz                   ; skip not 256 upper limit, else
        addlw   -0x20           ; subtract 32
        btfss   portA,0         ; up press? no, skip, else
        movwf   duty            ; update duty cycle
test1
        movf    duty,W          ; 0,32,64,...224
        skpz                    ; skip if 0 already, else
        addlw   -0x20           ; subtract 32
        btfss   portA,1         ; dn press? no, skip, else
        movwf   duty            ; update duty cycle
        goto    cycle           ; repeat cycle

        end
 
Last edited:

Markd77

Joined Sep 7, 2009
2,806
Just thought I'd correct the sublw 0x20 line.
It should be addlw 0xE0 because sublw 0x20 subtracts w from 0x20
Adding 224 is the same as subtracting 20 because of the overflow.
Otherwise looks very tidy.
 

Thread Starter

farscape

Joined May 16, 2010
26
Thanks for the example. I'm a confused by the "btfss" instructions you included in test0 and test1. Shouldn't they be "btfsc" because if the inputs are set, you want to include the next step where you mov the w register to duty?

We just tested the program on MPlab and it seems to begin at a 50% duty cycle and then adjusts from there. Is there a way to begin at 0% and then adjust based on the RA inputs?

Thanks
 
Last edited:

Thread Starter

farscape

Joined May 16, 2010
26
Okay. This seems to work fine on MPlab...


Rich (BB code):
processor 16F84A
INCLUDE <p16f84A.inc>
__CONFIG _CP_OFF & _WDT_OFF & _XT_OSC & _PWRTE_ON
org H'00'

portB    equ    0x06        
portA    equ    0x05
duty     equ    0x0c
timer    equ    0x0e
level    equ    0x0d

org     0x000

start 

movlw   0x00        
tris    portB        
clrf    portB        
movlw   0x1F        
tris    portA        
clrf    level

test0     btfss   portA, b'0'
          call    test1
          call    upLED

test1     btfss   portA, b'1'
          goto    test0
          call    downLED




upLED            movf level, W
                sublw 5
                btfsc STATUS, Z
                decf level, F ;if level was 5 make it 4, then the next line makes it 5 again
                 incf     level
                goto     $+5
downLED           movf level, W
                btfsc STATUS, Z
                incf     level
                decf     level
same            movlw    0x01
                 movwf    timer
                 movf     level, w
                 call     tableON
                 movwf    duty
repeat         bsf      portB, b'0'
on             decfsz   duty
                goto     on
                movf     level, w
                call     tableOFF
                movwf    duty
                bcf      portB, b'0'
off            decfsz   duty
                goto     off
                decfsz   timer
                goto     repeat
                btfss     portA, b'0'
                goto     $+2
                goto     upLED
                btfss     portA, b'1'
                goto     same    
                goto     downLED
    
tableON    addwf    PCL
                retlw    d'1'
                retlw    d'51'
                retlw    d'102'
                retlw    d'153'
                retlw    d'204'
                retlw    d'255'

tableOFF   addwf    PCL
                retlw    d'255'
                retlw    d'204'
                retlw    d'153'
                retlw    d'102'
                retlw    d'51'
                retlw    d'1'

end
 
Last edited:

MMcLaren

Joined Feb 14, 2010
861
Thanks for the example. I'm a confused by the "btfss" instructions you included in test0 and test1. Shouldn't they be "btfsc" because if the inputs are set, you want to include the next step where you mov the w register to duty?
If the switches are "active low" then those should be "btfsc" instructions. Sorry!
 

Thread Starter

farscape

Joined May 16, 2010
26
Rich (BB code):
processor 16F84A
INCLUDE <p16f84A.inc>
__CONFIG _CP_OFF & _WDT_OFF & _XT_OSC & _PWRTE_ON
org H'00'

portB    equ    0x06        
portA    equ    0x05
duty    equ    0x0c
timer    equ    0x0e
level    equ    0x0d

org    0x000

start 

movlw    0x00        
tris    portB               
clrf    portB
movlw    0x03        
tris    portA  ;RA0,RA1 input, RA2 outputs      
clrf    level

test0    btfss    portA, b'0'
        call    test1
        call    upLED

test1    btfss    portA, b'1'
        goto    test0
        call    downLED




upLED    movf     level, W
        sublw     9
        btfsc     STATUS, Z
        decf     level, F     ;if level was 5 make it 4, then the next line makes it 5 again
        btfss    portA, b'1'
        incf    level
        movf    level, w
        call    tableDIS
        movwf    portB
        goto    $+8

downLED    movf    level, W
        btfsc    STATUS, Z
        incf    level
        decf    level
        movf    level, w
        call    tableDIS
        movwf    portB


same    movlw    0x01
        movwf    timer
repeat    movf    level, w
        call    tableON
        movwf    duty
        bcf        portA,2
on        decfsz    duty
        goto    on
        movf    level, w
        call    tableOFF
        movwf    duty
        bsf        portA,2
off        decfsz    duty
        goto    off
        decfsz    timer
        goto    repeat
        btfss    portA, b'0'
        goto    $+2
        goto    upLED
        btfss    portA, b'1'
        goto    same    
        goto    downLED
    


tableON        addwf    PCL
        retlw    d'1'
        retlw    d'28'
        retlw    d'56'
        retlw    d'84'
        retlw    d'112'
        retlw    d'140'
        retlw     d'168'
        retlw     d'196'
        retlw     d'224'
        retlw     d'255'

tableOFF    addwf    PCL
        retlw    d'255'
        retlw    d'227'
        retlw    d'199'
        retlw    d'171'
        retlw    d'143'
        retlw    d'115'
        retlw     d'87'
        retlw     d'59'
        retlw     d'31'
        retlw     d'1'

tableDIS    addwf    PCL
        retlw    b'10000000'
        retlw    b'11110010'
        retlw    b'01001000'
        retlw    b'01100000'
        retlw    b'00110010'
        retlw    b'00100100'
        retlw    b'00000100'
        retlw    b'11110000'
        retlw    b'00000000'
        retlw    b'00110000'


end
 

Thread Starter

farscape

Joined May 16, 2010
26
Final

Rich (BB code):
processor 16F84A
INCLUDE <p16f84A.inc>
__CONFIG _CP_OFF & _WDT_OFF & _XT_OSC & _PWRTE_ON
org H'00'

portB    equ    0x06        
portA    equ    0x05
duty    equ    0x0c
timer    equ    0x0e
timer1    equ    0x0f
level    equ    0x0d

org    0x000

start 

movlw    0x00        
tris    portB               
clrf    portB
movlw    0x03        
tris    portA  ;RA0,RA1 input, RA2 outputs      
clrf    level

test0    btfss    portA, b'0'
        call    test1
        call    upLED

test1    btfss    portA, b'1'
        goto    test0
        call    downLED




upLED    movf     level, W
        sublw     9
        btfsc     STATUS, Z
        decf     level, F     ;if level was 5 make it 4, then the next line makes it 5 again
        btfss    portA, b'1'
        incf    level
        movf    level, w
        call    tableDIS
        movwf    portB
        goto    $+8

downLED    movf    level, W
        btfsc    STATUS, Z
        incf    level
        decf    level
        movf    level, w
        call    tableDIS
        movwf    portB


same    movlw    0xFF
        movwf    timer
        movlw    0x02
        movwf    timer1
repeat    movf    level, w
        call    tableON
        movwf    duty
        bcf        portA,2
on        decfsz    duty
        goto    on
        movf    level, w
        call    tableOFF
        movwf    duty
        bsf        portA,2
off        decfsz    duty
        goto    off
        decfsz    timer
        goto    repeat
        decfsz     timer1
        goto    repeat
        btfss    portA, b'0'
        goto    $+2
        goto    upLED
        btfss    portA, b'1'
        goto    same    
        goto    downLED
    


tableON        addwf    PCL
        retlw    d'1'
        retlw    d'28'
        retlw    d'56'
        retlw    d'84'
        retlw    d'112'
        retlw    d'140'
        retlw     d'168'
        retlw     d'196'
        retlw     d'224'
        retlw     d'255'

tableOFF    addwf    PCL
        retlw    d'255'
        retlw    d'227'
        retlw    d'199'
        retlw    d'171'
        retlw    d'143'
        retlw    d'115'
        retlw     d'87'
        retlw     d'59'
        retlw     d'31'
        retlw     d'1'

tableDIS    addwf    PCL
        retlw    b'10000000'
        retlw    b'11110010'
        retlw    b'01001000'
        retlw    b'01100000'
        retlw    b'00110010'
        retlw    b'00100100'
        retlw    b'00000100'
        retlw    b'11110000'
        retlw    b'00000000'
        retlw    b'00110000'


end
 

Thread Starter

farscape

Joined May 16, 2010
26
Rich (BB code):
processor 16F84A
INCLUDE <p16f84A.inc>
__CONFIG _CP_OFF & _WDT_OFF & _XT_OSC & _PWRTE_ON
org H'00'

portB    equ    0x06        
portA    equ    0x05
duty     equ    0x0c
timer    equ    0x0e
timer1   equ    0x0f
level    equ    0x0d
duty2    equ    0x1A
timer2   equ    0x1B
timer12  equ    0x1C
level2   equ    0x1D

org    0x000

start

movlw    0x01        
tris    portB               
clrf    portB
movlw   b'00011'        
tris    portA  ;RA0,RA1 input, RA2, RA3 outputs      
clrf    level
clrf    level2
clrf    portA

test0   bsf        portA, 3
        btfsc   portB, b'0'
        goto    test02
        btfss   portA, b'0'
        goto    test1
        call    upLED

test1    btfss  portA, b'1'
        goto    test0
        call    downLED




upLED   movf     level, W
        sublw     9
        btfsc     STATUS, Z
        decf     level, F     ;if level was 5 make it 4, then the next line makes it 5 again
        btfss    portA, b'1'
        incf    level
        movf    level, w
        call    tableDIS
        movwf    portB
        goto    $+8

downLED movf    level, W
        btfsc    STATUS, Z
        incf    level
        decf    level
        movf    level, w
        call    tableDIS
        movwf    portB


same    movlw    0xFF
        movwf    timer
        movlw    0x02
        movwf    timer1
repeat  movf     level, w
        call     tableON
        movwf    duty
        bcf      portA,2
on      btfsc    portB, b'0'
        goto    test02
        decfsz    duty
        goto    on
        movf    level, w
        call    tableOFF
        movwf    duty
        bsf        portA,2
off     btfsc    portB, b'0'
        goto    test02
        decfsz    duty
        goto    off
        decfsz    timer
        goto    repeat
        decfsz     timer1
        goto    repeat
        btfss    portA, b'0'
        goto    $+2
        goto    upLED
        btfss    portA, b'1'
        goto    same    
        goto    downLED
    


tableON        addwf    PCL
        retlw    d'1'
        retlw    d'28'
        retlw    d'56'
        retlw    d'84'
        retlw    d'112'
        retlw    d'140'
        retlw    d'168'
        retlw    d'196'
        retlw    d'224'
        retlw    d'255'

tableOFF    addwf    PCL
        retlw    d'255'
        retlw    d'227'
        retlw    d'199'
        retlw    d'171'
        retlw    d'143'
        retlw    d'115'
        retlw     d'87'
        retlw     d'59'
        retlw     d'31'
        retlw     d'1'

tableDIS    addwf    PCL
        retlw    b'10000000'
        retlw    b'11110010'
        retlw    b'01001000'
        retlw    b'01100000'
        retlw    b'00110010'
        retlw    b'00100100'
        retlw    b'00000100'
        retlw    b'11110000'
        retlw    b'00000000'
        retlw    b'00110000'


test02  bsf        portA,2
        btfss    portB, b'0'
        goto    test0
        btfss    portA, b'0'
        goto    test12
        call    upLED2

test12  btfss    portA, b'1'
        goto    test02
        call    downLED2




upLED2   movf     level2, W
        sublw     9
        btfsc     STATUS, Z
        decf     level2, F     ;if level was 5 make it 4, then the next line makes it 5 again
        btfss    portA, b'1'
        incf    level2
        movf    level2, w
        call    tableDIS2
        movwf    portB
        goto    $+8

downLED2    movf    level2, W
        btfsc    STATUS, Z
        incf    level2
        decf    level2
        movf    level2, w
        call    tableDIS2
        movwf    portB


same2   movlw    0xFF
        movwf    timer2
        movlw    0x02
        movwf    timer12
repeat2 movf    level2, w
        call    tableON2
        movwf    duty2
        bcf        portA,3

on2     btfss    portB, b'0'
        goto    test0
        decfsz    duty2
        goto    on2
        movf    level2, w
        call    tableOFF2
        movwf    duty2
        bsf      portA,3

off2    btfss    portB, b'0'
        goto    test02
        decfsz    duty2
        goto    off2
        decfsz    timer2
        goto    repeat2
        decfsz     timer12
        goto    repeat2
        btfss    portA, b'0'
        goto    $+2
        goto    upLED2
        btfss    portA, b'1'
        goto    same2    
        goto    downLED2
    


tableON2        addwf    PCL
        retlw    d'1'
        retlw    d'28'
        retlw    d'56'
        retlw    d'84'
        retlw    d'112'
        retlw    d'140'
        retlw     d'168'
        retlw     d'196'
        retlw     d'224'
        retlw     d'255'

tableOFF2    addwf    PCL
        retlw    d'255'
        retlw    d'227'
        retlw    d'199'
        retlw    d'171'
        retlw    d'143'
        retlw    d'115'
        retlw     d'87'
        retlw     d'59'
        retlw     d'31'
        retlw     d'1'

tableDIS2    addwf    PCL
        retlw    b'10000000'
        retlw    b'11110010'
        retlw    b'01001000'
        retlw    b'01100000'
        retlw    b'00110010'
        retlw    b'00100100'
        retlw    b'00000100'
        retlw    b'11110000'
        retlw    b'00000000'
        retlw    b'00110000'


end
 

Markd77

Joined Sep 7, 2009
2,806
Does it work?
Spotted a couple of times where you incf and then decf the same file and the goto $+8 could be replaced with "goto same" for better readability.
 
Top