SAMPLE CODE FOR THE PIC16F84 

SAMPLE PWM CODE
THE THEORY:

A simple routine to generate 50% PWM motor control signal.

This code uses a simple delay loop to generate a 1 mS delay based on a 4MHz osc.
If you use a different freq. you will have to recalculate the delay values.

The output is set to 1
The 1mS delay is called
The output is set to 0
The 1mS delay is called
The cycle is then repeated in an endless loop

As the output is on for 1mS and off for 1mS the PWM ratio and thus power to the motor is 50%

The time period (time for 1 cycle to complete) is 2mS (on for 1mS off for 1mS)
The frequency of the generated waveform is therefor 1/0.002 = 500 Hz
500Hz is ideal for motor speed control.

You will need to change the PWM ratio to implement different power levels.
However keep in mind that the one and off cycles must add up to 2mS otherwise the frequency will change.

How to calculate the delay time using the delay routine.

At 4MHz osc the machine cycle in side the PIC is 1/4 of this ie 4/4 = 1 MHz or 1uS in time.
If you use a different frequency you'll have to recalculate the time period of the machine cycle thus:

Time period = 1 / (Osc freq / 4)


Thus each instruction will execute in 1uS except for branch instructions eg. goto = 2uS
Let's keep it simple, large values for the inner delay loop (delay1) mean we can use this simple formula to calculate the overall delay time in uS (microSeconds).

delay time uS = delay2 x delay1 x 3 x (time period in uS)

delay1 = 111 : delay2 = 3 : time period = 1uS Thus:

delay time = 3 x 111 x 3 x 1 = 999 uS or approx 1mS

 

THE CODE:

#include 	p16f84.inc

		list	p=16f84

#define		PWMout	PORTA,0		;define a constant PWM output on pin RA0 
		cblock	0c		;define a variable block  starting @ 0C hex- variables follow
		delay1
		delay2
		endc			;end variable block
		org 0			;assemble code starting at memory location 0
Start		movlw	b'11111110'	;for input bit = 1 for output bit = 0
		tris	PORTA		;PortA b0 = o/p
mainloop
		bsf	PWMout		;set output RA0 = 1
		call	delay1mS	;wait for 1mS
		bcf	PWMout		;set output RA0 = 0
		call	delay1mS	;wait for 1mS
		goto	mainloop	;goto mainloop
;***************** 1mS Delay subroutine ********************
delay1mS
		movlw	.3		;note .3 means decimal 3
		movwf	delay2		;delay2 = 3
outerloop	movlw	.111		;note .111 means decimal 111
		movwf	delay1		;delay1 = 111
innerloop	decfsz	delay1,1	;delay1 = delay1 - 1 : skip next instruction if result = 0
		goto	innerloop	;else goto innerloop
		decfsz	delay2,1	;delay2 = delay2 - 1 : skip next instruction if result = 0
		goto	outerloop	;else goto outerloop
		return			;return from subroutine
		end			;end of assembly code
THE TEST RESULTS:
Each horizontal square is equal to 0.5 mS
As the width of the on pulse and also the off pulse  is 2 squares it then follows that the waveform is on for 2 x 0.5mS = 1mS and off for the same. Exactly as per the design.