__10 Bit HPWM by Les Johnson__

__Explanation____Code attached: -__10BITHPWM.zip

Using the hardware PWM on the 16F8XX range of PICŪ

There are two PWM outputs on the PICŪ 16F8XX range of PICŪ.

We are Demonstrating PWM on CCP1 otherwise known as PortC.2

__Step 1__In order to use the Hardware PWM. A certain sequence of registers have to be set

Firstly the Pin CCP1, has to be set as an output, ( TRISC.2 = 0 ).

__Step 2__Then the Timer 2 prescaler has to be initialised, this register is called T2CON.

The prescaler is set by the first two bits of register T2CON

00 will give a prescaler ratio of 1:1 (timer2 will tick on every instruction cycle).

01 will give a prescaler ratio of 1:4 (timer2 will tick on every 4th instruction cycle).

10 will give a prescaler ratio of 1:16 (timer2 will tick on every 16th instruction cycle).

Remember the instruction timer is (Fosc/4).

And bit-2 is set to 1, this turns on timer2, resetting the bit will turn timer2 off.

__Step 3__The period for timer2 is placed in the register PR2, see the calculations below for the value to place into it.

__Step 4__The MSB of the 10-bit duty cycle has to be loaded into the CCPRL1 register, and the lowest significant 2-bits (i.e bits-0 and 1) are placed into bits-4 and 5 of the CCP1CON register.

Place bit-0 of the 10-bit duty into the CCP1CON register bit-4

Place bit-1 of the 10-bit duty into the CCP1CON register bit-5

__Step 5__And finally we turn on the PWM by setting bits-2 and 3 of the CCP1CON register to 1's,

resetting these two bits will turn off PWM, but only for CCP1.

__________________________________________________ ____________________

In order to calculate the value that will be placed into PR2 (the period) use:-

Period in us = (PR2+1)* 4 *(1/OSC) * (TMR2 prescaler value)

The '(1/OSC)' will always be a fraction i.e. 0.25, therefore we are actually

dividing each time we multiply by that number i.e 100*0.25 = 25, which is the same as 100/4

Therefore the '* (1/OSC)' can be replaced with '/OSC'. This makes our formula: -

Period = (((PR2+1)* 4) /OSC) * (TMR2 prescaler value)

So, for a 4MHz crystal, prescaler set to 1 and PR2 = 255

((256 * 4) /4) * 1 == a period of 256us

__________________________________________________ ____________________

To calculate the Frequency (in KHz), use: -

1000/Period (in microseconds)

This means our frequency is 1/256 which equals 3.90625KHz

__________________________________________________ ____________________

As the frequency of the PWM increases the resolution decreases.

To calculate the resolution for a given frequency use: -

(log( Fosc/Fpwm )) / log(2)

Where Fosc is the crystal frequency, and Fpwm is the frequency of the PWM, see above calculations.

The log of 2 is a constant, with a value of 0.301

Therefore our formula now looks like this: -

(log( Fosc/Fpwm )) / 0.301

So, for a frequency of 3.9kHz, and a 4MHz crystal our formula is now: -

(log( 4000000/3900)) / 0.301 == 10.003

Which means that we have a resolution of 10-bits. PHEEEEEEWWWWWW!!!!!!!!

__________________________________________________ ____________________

__Example code__**Include**"proton_4.inc"

**Device 16F877**

**Remarks On**

**All_Digital**= TRUE

**PortB_Pullups**=

**On**

*' Enable PORTB pull-ups*

**Cls**

*' ** Setup the Crystal Frequency in MHz ***

*' ** Declare Variables ***

**Dim**X

**As Word**

**Dim**Duty

**As Word**

**Dim**Vout

**As Word**

**Dim**Duty_R

**As Byte**

**Symbol**Quanta = 49

'--------------------------------------------------------------------------------------------------

*' ** The main program starts here! ***

TRISC.2 = 0

*' Enable PORTC.2 (CCP1) as output for PWM*

T2CON = %00000100

*' Set the Prescaler for 1:1, and turn on TMR2*

PR2 = 255

*' See above calculation in notes for the output period*

Vout = 2500

*' We require 2.5Volts PWM output*

**GoSub**Make_pwm

**Print At**1 , 1 , #vout , 32 , 32

**Stop**

Make_pwm:

Duty = (Vout*10) / Quanta

Duty_R = (Vout) // Quanta

Duty = Duty + Duty_R

X=Duty

CCP1CON.4 = X.0

*' Place bit-0 of the duty in the LSB register(bit-4)*

CCP1CON.5 = X.1

*' Place bit-1 of the duty in the LSB register(bit-5)*

X = X >> 2

*' Shift the duty value down 2 places*

CCPR1L = X

*' MSB of the 10-bit duty value*

CCP1CON.2 = 1

*' Turn on PWM Module one,*

CCP1CON.3 = 1

*' by setting bits 2 and 3 of CCP1CON*

**Return**

**Stop**