Introduction: Generating 50Hz PWM Using PIC16F877A

Hello,

For generating PWM signals using PIC microcontroller, we can use the CCP module in it and everything will be easy. However, it can not generate this very low frequency like 50Hz due to some limitations that I will describe here.

Necessary files for this tutorial (Must download):

MPlab X project file (code): https://mega.nz/#!SMpwEDST!VsT6uPJdYpIUbnEuIXLudG...

PIC timer explanation: https://mega.nz/#!PFpj3B7b!gYgsLv7uuxPZ-ul9BU2HMuV...

PIC16F877A datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/3...

So let's GO!

Step 1: PIC PWM Module and Timers

We will operate this PIC @ 20MHz oscillator. This tutorial is for those who has such very high oscillators which is the standard way of using microcontrollers. However, you can use the straightforward way (CCP as PWM) if you have a very slow oscillator like 32 KHz, because then timer2 can achieve 50 Hz directly without the need of what we will explain here.

PIC MCUs have something called CCP module which is Capture-Compare-PWM module, meaning, you can configure it to work as one of these 3. For the typical application, we always should configure it to be PWM (this is the straightforward way which we must use by default).

When it is configured as PWM, it uses Timer2 as a timing module in order to calculate its Ton and Toff. So how can we determine all necessary values to achieve our own required frequency?

Timer equations:

[1] F_timer = F_crystal / (4 * prescaler * resolution)

[2] Period_timer = 1 / F_timer

[3] N = (t * F_crystal) / (4 * prescaler)

Equation 1 calculates timer frequency. We will use it to determine the lowest possible frequency that the timer can produce. If it is less than 50Hz, then we can generate 50Hz or we will find another way.

Equation 2 is obvious, which is the period of that frequency.

Equation 3 is the number of "ticks" that the timer will tick until it reaches the time "t" that we want, according to the settings we specified like prescaler and crystal frequency.

CCP1 module when operated as PWM uses timer2, and this timer2 is an 8-bit timer. Meaning, its resolution is 2^8=256. It offers prescaler values up to 16 and this prescaler is a feature in timers that allows them to divide input frequency fed into them in order to achieve lower frequencies.

So the lowest ever frequency timer2 can deal with (assuming 20MHz crystal oscillator) = 20000000 / (4 * 16 * 256) = 1220.7 Hz (approx 81.9 us period). Thus we can not get the 50Hz signal that we wanted using this timer with CCP1 as PWM.

What about timer1? it has a maximum prescaler value of 8 and resolution of 16-bits = 65536 because it is a 16-bit timer.

Lowest timer1 frequency = 20000000 / (4 * 8 * 65536) = 9.53 Hz. ( approx 104.9 ms period)

So we conclude that timer1 can be used to generate 50 Hz signal because it can generate low frequencies up to 9.53 Hz and our 50 is just so much achievable!

Q: Ok! connect it to CCP module in its PWM mode!!!

A: No, CCP as PWM only uses timer2 module... you need to find another way.

What is it?!

Step 2: Using Timer1 to Generate 50 Hz Signals

We will use timer1 along with CCP module operated as "Compare, trigger special event". All of this will happen inside the code.

So the idea is to do this forever:

1- load timer1 with required values to generate the longest period it could (104.9 ms).

2- load the "on-time" value inside CCP module's register, put "1" at the output pin (RC2), and start timer1.

3- timer1 will start counting until it reaches the value inside CCP registers (matches the on-time). CCP will set its interrupt flag.

4- inside interrupt service routine, reset CCP interrupt flag, load CCP registers with the "off-time" value, and set "0" at the output pin.

Along all that, we must use a variable that holds the number of ticks that corresponds to 20 ms full period... it is calculated as follows:

Lowest timer1 frequency (as calculated before) = 9.53 Hz.

Highest timer1 period = 104.9 ms.

so 104.9 ms matches the final tick which is 65535 (because it has 16-bit resolution)... so for 20 ms, what is the number of ticks required?

N_20ms = (0.02 * 20000000) / (4 * 8) = 12500.

so when timer1 reaches the tick number 12500, it is 20 ms! this is the reference value we will use in our software... so when we want different duty cycles, what should we do?

for 50% duty the number of counts = 0.5 * 12500 and for 20% = 0.2 * 12500 and so on! the following line is for clarification:

number of ticks: 0__________12500__________65536

corresponding time period: 0__________20ms__________ 104.9ms

We are ready to go! all that is left is the code itself!

Step 3: The Code

NOTE: the code, MPlabX project file, along with other stuff are uploaded and their links are in the first page... you must download them from there.

The full code is here: http://pastebin.com/Ygrp8P5z

I did my best to comment every line in order to make it easy to understand, and I am ready to answer any question about it.


I also went through ALL lines one by one in the video posted in the first post. I totally recommend referring to it.

Final note: you can make a PWM signal by software! yes, it is very easy like making a certain pin = 1, delay 10 ms, make it 0, delay 10 ms.... and loop forever! However, this is via software, meaning the use of the CPU which isn't required, especially when you have hardware modules (CCP, timers,...) in your MCU.

I hope this tutorial was useful... If you have any question please ask me here.

Step 4: Finalizing

Now everything must work fine. In the video tutorial I made a Proteus simulation for the circuit to test it out, you can use any software package or better yet do it practically.