How to Generate Sound using PWM with PIC Microcontroller

Pulse Width Modulation (PWM) is a technique in which the width of a pulse is modulated keeping the time period of the wave constant. The ON time and OFF time can have any different values in the wave cycles, but the sum of the ON time and OFF time remains same for the entire cycles. PWM is a digital wave that can be generated using digital circuits which are not capable of generating analog voltages. With the help of the modulation of the width of a pulse in a period of the wave, they can generate any required voltage with the help of a proper filter circuits. The filter circuits are used for generating the voltage corresponding to a modulated wave

This feature of the PWM wave is making use in so many digital systems like DC motor control, audio devices, simple decoration light controls etc. The PIC18F4550 has an inbuilt PWM module which can generate continuous PWM waves. This project explores the PWM module of the PIC18F4550 and tries generating a sine wave with frequency in the audible range and then produce that sound in a Loud Speaker with the help of a filter circuit and Loud Speaker driver circuits.

How to Generate Sound using PWM with PIC MicrocontrollerGenerating a sine wave has a great deal of significance since the sine wave is the most natural waveform and all other kind of waves can be generated as a combination of sine waves with different frequencies and amplitude. Generating an audible sine wave and producing its sound in a Loud Speaker is the first step towards using the microcontroller in audio applications like media player, announcement system, record and playback etc.

The PIC18F4550 has four PWM output channels and they are P1A, P1B, P1C and P1D. All of them are capable of generating PWM waves at a time. In this project only one of the PWM channels are using. The P1A is the PWM channel in this particular project. This channel is used to generate the PWM waves which are then applied to a filter circuit to generate the sine wave which is described in a previous project on PIC Sine Wave Generation. In this project a driver circuit is designed to generate the sound of that audible sine wave in a Loud Speaker.

The period of the wave is the sum of the ‘ON time + OFF time’. Duty-cycle is the percentage of time period for which the logic1 voltage exists in a cycle (ON time), starting from the beginning of the cycle.

The PWM is that kind of a wave in which the ON time and OFF time can vary in a cycle but the sum of ‘ON time + OFF time’ remains constant for every cycle.

Period = ON time + OFF time

Duty-cycle = ON time / (ON time + OFF time) = ON time / Period

Increasing the Duty-cycle will increase the voltage at the filter device’s output and decreasing the Duty-cycle will decrease the voltage as well.

In this particular project the sine wave samples are generated periodically by re-writing the value of the CCPR1 register to vary the Duty-cycle. It is done by generating interrupts periodically with another timer module timer0 and changing the CCPR1 value when the code is inside the timer0’s ISR.

The voltage generated by the PWM wave in the interval between two interrupts will be a constant value and this time period can be called ‘sampling period’.

The values of voltage that appears at each sampling period are simply called ‘samples’. The more the number of PWM cycles in a Sampling time, more stable the output voltage will be an example of the sine wave samples is shown following figure in which 10 samples are used to resemble a sine wave. These values when applied to a filter circuit can generate the sine wave at its output by smoothing the step size. The brown line shows the actual sine wave constructed by the filter circuit

The values that should be assigned to the CCPR1 register to generate such consecutive samples are actually taken from a look-up table. The look-up table with 50 samples which is used in this particular project to generate the sine wave is shown in the following;

Sample no. Value Sample no. Value Sample no. Value Sample no. Value Sample no. value
1 52 11 85 21 69 31 28 41 16
2 57 12 86 22 65 32 25 42 18
3 62 13 86 23 61 33 22 43 20
4 66 14 86 24 56 34 19 44 23
5 70 15 85 25 52 35 17 45 26
6 74 16 83 26 48 36 15 46 39
7 77 17 81 27 44 37 14 47 34
8 80 18 78 28 39 38 14 48 38
9 82 19 75 29 35 39 14 49 43
10 84 20 72 30 31 40 15 50 48


Time period calculations:

In this section the calculations for the sampling time, PWM Period, PWM Duty-Cycle, frequency of the sine-wave etc. are calculated and the details of the calculations are available in a previous project on PIC Sine Wave Generation

Sampling time:

In this project the TMR0 is set to zero and the timer0 is configured as an 8 bit timer with pre-scale value 1:2 which gives a sampling time;

Sampling time = 40us

PWM period:

In this particular project the PR2 is written to a very small value so as to generate small time periods and hence to get more number of PWM cycles per sampling period.

PR2 = 22

The PWM Period = 2us

Number of PWM cycles per Sample = 20

Thus the timer0 will generate an interrupt after every 20 PWM cycles.

The frequency of the sine wave = 500 Hz

PWM Duty-cycle:

The Duty-cycle in this particular project is varied according to the look-up table whenever a timer0 interrupt occurs. The maximum Duty-cycle (100%) is 2us only since it is the value of the PWM period, hence

#include <p18f4550.h>
#include <timers.h>
//======================= chip config ===================//
#pragma config PLLDIV = 1
#pragma config CPUDIV = OSC1_PLL2
#pragma config FOSC = HSPLL_HS
#pragma config USBDIV = 1
#pragma config IESO = OFF
#pragma config PWRT = OFF
#pragma config BOR = OFF
#pragma config VREGEN = OFF
#pragma config WDT = OFF
#pragma config WDTPS = 32768
#pragma config CCP2MX = ON
#pragma config PBADEN = OFF
#pragma config LPT1OSC = OFF
#pragma config MCLRE = ON
#pragma config STVREN = ON
#pragma config LVP = OFF
#pragma config ICPRT = OFF
#pragma config XINST = OFF
#pragma config DEBUG = OFF
#pragma config WRTD = OFF
//======================= chip config ===================//
 How to Generate Sound using PWM with PIC Microcontroller Schematic
//LCD Control pins
#define rs PORTBbits.RB4
#define rw PORTBbits.RB3
#define en PORTBbits.RB2
//LCD Data pins
#define lcdport PORTD
#define lcd_port_dir TRISD
void lcd_clear ( void );
void lcd_2nd_line ( void );
void lcd_1st_line ( void );
void lcd_ini ( void );
void dis_cmd ( unsigned char cmd_value );
void dis_data ( unsigned char data_value );
void lcdcmd ( unsigned char cmdout );
void lcddata ( unsigned char dataout );
void delay_ms ( int delay );
//=============== SINE WAVE LOOK UP TABLE ================//
const unsigned char sine[50] = {
//=============== SINE WAVE LOOK UP TABLE ================//
//============================ TIMER 0 ISR =================================//
#pragma interrupt tmr0_interrupt
void tmr0_interrupt(void)
{   static unsigned char i = 0;
   i ++;
   // method to write the sample values into the 10bit CCPR1 register //
   CCP1CON |= ( ( sine [ i ] ) << 5 ) & 0x03;
   CCPR1L = ( sine [ i ] ) >> 2;
   // method to write the sample values into the 10bit CCPR1 register //
       if ( i == 49 )
  i = 0;   else;
   INTCONbits.TMR0IF=0;                            // clearing the timer0 overflow bit
//============================ TIMER 0 ISR =================================//
void main ( void )
{unsigned char data1 [] = “EngineersGarage”;
unsigned char data2 [] = ”   Sine Wave   “;
int i = 0;
OSCCON = 0x0C;
lcd_ini (); // LCD initialization
delay_ms ( 200 );
//========================= start up display on LCD ================================//
while ( data1 [i] != ‘\0’ )
{dis_data ( data1 [i] );
delay_ms ( 200 );i++;}i = 0;
lcd_2nd_line ();
while ( data2 [i] != ‘\0’ )
{dis_data ( data2 [i] );
delay_ms ( 200 );
i = 0;
/========================= start up display on LCD ================================//
//============================ PWM SETTINGS ====================================//
TMR2 = 0x0 // setting TMR2 value as 0, start counting from 0
PR2 = 22; // set the PR2 value, to get PWM period of 2us
CCPR1L = 0x00; // setting initial value of CCPR1L as 0
CCP1CON = 0x0C; // select single output with P1A, and mode select bits so as to get
P1A, P1B, P1C and                                    // P1D as active-high
TRISC &= 0xFB; // setting the PWM pin as output
T2CON = 0x04; // both the pre-scalar and post-scalar bits are written for 1:1 with
the timer2 turned on.


For more detail: How to Generate Sound using PWM with PIC Microcontroller

About The Author

Ibrar Ayyub

I am an experienced technical writer with a Master's degree in computer science from BZU Multan University. I have written for various industries, mainly home automation, and engineering. I have a clear and simple writing style and am skilled in using infographics and diagrams. I am a great researcher and is able to present information in a well-organized and logical manner.

Follow Us: