Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Assembly and PWM

Status
Not open for further replies.

jacks

New Member
Friends

I have an assembly code for PWM but not sure how to vary the duty cyle. As it stands, its 50 %. How will I vary the duty cycle? I am using mplab simulator.

Jacks
 
PIC16F628 in Simulator

Friends

I have been on it for 3.5 weeks and the PWM signal generation in MPLAB is still giving me problems. I simply want to input 4 bits which altered will vary the duty cycle. It is currently set at 50% and if I change the binary digits of the 4 bit input it will alter the PWM signal which is a square wave. Thanks

Jacks
 
Just change the inputs to CCPR1L:CCP1CON<5:4> pair depending on the inputs.
 
Last edited:
Hi Asp1987

Thanks for the reply but I am a real newbie when it comes to PICs and programming. May I ask what a CCPR1L:CCP1CON<5:4> pair is? Thanks

Jacks
 
From the datasheet:-
The PWM duty cycle is specified by writing to the
CCPR1L register and to the CCP1CON<5:4> bits. Up
to 10-bit resolution is available. The CCPR1L contains
the eight MSbs and the CCP1CON<5:4> bits contain
the two LSbs.

CCP1CON<5:4> means bits 5 and 4 of CCP1CON

CCPR1L:CCP1CON<5:4> just means 10 bits made up of the contents of CCPR1L followed by bits 5 and 4 of CCP1CON

If you want 4 bits of PWM resolution and you are using the PWM module, you only need to write to the top half of CCPR1L
 
Diver300

Thanks for your response. Here is the code, where is the top half of the ccpril? Thanks


Bathini





IFDEF __16F628A
#include "p16f628a.inc"
ENDIF

IFDEF __16F627A
#include "p16f627a.inc"
ENDIF

__CONFIG _CP_OFF & _WDT_OFF & _BOREN_OFF & _PWRTE_ON & _INTOSC_OSC_NOCLKOUT & _MCLRE_ON & _LVP_OFF


errorlevel -302 ; suppress banksel warning messages


cblock 0x70 ;0x70-0x7F common to all banks
save_W ;0. save W during interupt
save_Status ;1. save STATUS during interupt
save_PCLATH ;2. save PCLATH
portAcopy ;3. working variable holds data to write to PORTA
period ;4. period counter variable
duty ;5. duty cycle loop counter variable
dutyReload ;6. duty cycle variable
switches ;7. switch state variable
temp ;8. temp variable used in switch functions

endc

; Define port bit use
;-----------------------------
pb.pwm equ 0 ; pwm output
pb.swinc equ 0 ; duty cycle increment switch
pb.swdec equ 1 ; duty cycle decrement switch

; Define constants
;-----------------------------
Cperiod equ .15 ; (0-15 = 16 levels or 4-bits)


;=============================================================
org 0x000 ;RESET VECTOR
goto startup ;goto to startup code on reset


; ************************************************************
;
; Initialise peripherals and registers at startup
;
startup movlw 0x07
movwf CMCON ;disable comparator

movlw 0x00
movwf portAcopy
call output

banksel OPTION_REG


movlw ~(1<<pb.pwm)
movwf TRISA

movlw b'11111111'
movwf TRISB

;all unused I/O lines on both ports are set to input and should be tied to Vss


movlw b'00000000' ;setup option register
; ||||||||---- PS0 - Timer 0: Prescalar 1:2
; |||||||----- PS1
; ||||||------ PS2
; |||||------- PSA - Assign prescaler to Timer0
; ||||-------- TOSE - LtoH edge
; |||--------- TOCS - Timer0 uses IntClk
; ||---------- INTEDG - falling edge RB0
; |----------- RBPU - pull-ups enabled
movwf OPTION_REG

banksel PORTA

movlw Cperiod ; Initialise period
movwf period

movlw .8 ; set inital duty cycle to 50%
movwf dutyReload


;--------------------------------------------------------------
; Run this code loop to generate PWM
;
loop call pwm ; compute PWM output
call output ; write to physical I/O port
goto loop ; repeat


;--------------------------------------------------------------
; Compute the state of the PWM output bit
;
pwm decfsz period,F ; decrement period counter
goto pwm.cycle ; run duty cycle code until period times out

pwm.reload movlw Cperiod ; if one PWM period has elapsed, reload
movwf period ; the period counter
incf dutyReload,W ; and duty cycle counter
movwf duty
bsf portAcopy, pb.pwm
call duty.switch ; test switches each once per period


pwm.cycle decfsz duty,F
return
bcf portAcopy, pb.pwm
return




;--------------------------------------------------------------
; Write port copy variable to physical I/O Port

output movfw portAcopy ;load output var' into W
movwf PORTA ;write to Port A
return ;and return




;--------------------------------------------------------------
; Test two switches and adjust duty cycle if switch pressed.
;
duty.switch decfsz temp,F
return
movfw PORTB
movwf temp
xorwf switches,W
andwf switches,F
btfsc switches, pb.swinc
call duty.inc
btfsc switches, pb.swdec
call duty.dec
movfw temp
movwf switches
clrf temp
return



duty.inc incf dutyReload,F
movfw dutyReload
sublw Cperiod
skpc dutyReload,4
decf dutyReload,F
return

duty.dec movf dutyReload,F
skpz
decf dutyReload,f
return
;--------------------------------------------------------------



end
 
There are two ways of producing a PWM signal.

1) The way that you are doing it, getting the code to count cycles and deciding when to raise the output and when to lower it.

2) Using the CAPTURE/COMPARE/PWM (CCP) MODULE
With that you just set it up and it will produce a fixed PWM signal until you change something.

CCPR1L is the register that sets the duty cycle in the CAPTURE/COMPARE/PWM (CCP) MODULE. It basically does the same as the "dutyReload" register in your code. PR1 does what "Cperiod" does in your code.

When I suggested the top half of CCPR1L, I thought that you were using the CAPTURE/COMPARE/PWM (CCP) MODULE. If PR1 is 0, timer 2 rolls round every 256 clock cycles, so to get 16 steps of duty cycle, you need to go up by 256/16 = 16 in CCPR1L for each step.

Code:
Step         CCPR1L
0             00000000
1             00010000
2             00100000
3             00110000
4             01000000
5             01010000
       -
       -
14           11100000
15           11110000

That is what I meant by the top half of CCPR1L. You can use the swap command to get data there.

Back to your code, it seems to work on the simulator. The output frequency is 4 kHz with the internal oscillator.

The only problem that I can see is that the timing isn't consistent when the pushbuttons are checked, so one cycle every 63 ms is a bit longer than it should be.

Also, clearing the temp register after you use it is totally unnecessary.

How are you checking the duty cycle? The stopwatch showed the code getting to

bsf portAcopy, pb.pwm

every 251 cycles and it gets to

bcf portAcopy, pb.pwm

(16 * dutyReload) cycles later.

That looks to me like it is working.
 
Thanks, I will read about the CCPRL and see whether I can use that instead. I think what I am trying is when I change the input bits the duty cycle will vary. I will see this in mplab.

Jacks
 
Status
Not open for further replies.

Latest threads

Back
Top