Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

to generate 4 pwm signals with fixed frrequency and varying duty cycle using a pic

Status
Not open for further replies.

scooby99

Newbie level 6
Joined
Mar 7, 2011
Messages
12
Helped
1
Reputation
2
Reaction score
1
Trophy points
1,283
Activity points
1,368
hi.. can anyone help me in generating 4 pwm signals of fixed frequency say [1khz] and varying duty cycle using a microcontroller. i need the C code too..

say i have a voltage source from 0 -5 V.. when the voltage is varied from 0 to 5 V the duty cycle needs to vary from 0 to 100 %. with fixed frequency 1 Khz. can anyone help me with this.
 

have a look at the PIC24HJ64GP502
PIC24HJ64GP502

it has 4 PWM outputs and comes in a 28 pin SDIP package so easy to build a PCB

if you are looking for a development kit Microchip's microstick comes with a PIC24HJ64GP502
**broken link removed**

it has an onboard programmer and a header to attach to a breadboard so you can build your own circuits
 

    V

    Points: 2
    Helpful Answer Positive Rating
but how do i work on the code... i have no idea how to create the registers.. let me know if anyone has a code used for fixed frequency and varying duty cycle.

else let me know where i can c code for pic24 .
 

some initialisation code for a PIC24FJ256GB110
Code:
void PWMinit(void)
{
       OC1CON2bits.SYNCSEL=0x1F;			// set trigger/sync source is this OCM module
       OC1RS=(int)(401L); 			 		// set PWM duty cycle
       OC1R =(int)(400L*(dutyCycle)/100L);  
       OC1CON1bits.OCM=7;					// set Center-aligned PWM mode
       OC1CON1bits.OCTSEL=7;	    		// setect System Clock
}
and then to alter the duty cycle
Code:
// set mPWM - PWMinit must have aleady been called
void PWM(int dutyCycle)
{
       OC1R =(int)(400L*(100-dutyCycle)/100L);  
}
have a look at 15.0 OUTPUT COMPARE the section on PWM
PIC24HJ64GP502
 

PHP:
/////////////////////////////////////////////////////////////////////////
////                           EX_PWM.C                              ////
////                                                                 ////
////  This program will show how to use the built in PIC PWM.        ////
////  The program takes an analog input and uses the digital         ////
////  value to set the duty cycle.  The frequency is set by          ////
////  the user over the RS-232.                                      ////
////                                                                 ////
////  Configure the CCS prototype card as follows:                   ////
////      Connect a scope to pin C2                                  ////
////      Connect pin A0 to output of the POT                        ////
////                                                                 ////
////  Configure the CCS PCD 30F2010 development board as follows:    ////
////      Connect a scope to pin D0                                  ////
////                                                                 ////
////  Jumpers:                                                       ////
////     PCM,PCH    pin C7 to RS232 RX, pin C6 to RS232 TX           ////
////     PCD        none                                             ////
////                                                                 ////
////  This example will work with the PCM, PCH, and PCD compilers.   ////
////  The following conditional compilation lines are used to        ////
////  include a  valid device for each compiler.  Change the device, ////
////  clock and RS232 pins for your hardware if needed.              ////
/////////////////////////////////////////////////////////////////////////
////        (C) Copyright 1996,2007 Custom Computer Services         ////
//// This source code may only be used by licensed users of the CCS  ////
//// C compiler.  This source code may only be distributed to other  ////
//// licensed users of the CCS C compiler.  No other use,            ////
//// reproduction or distribution is permitted without written       ////
//// permission.  Derivative programs created using this software    ////
//// in object code form are not restricted in any way.              ////
/////////////////////////////////////////////////////////////////////////


#if defined(__PCM__)
#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=10000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, BRGH1OK)

#elif defined(__PCH__)
#include <18F452.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=10000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, BRGH1OK)

#elif defined(__PCD__)
#include <30F2010.h>
#fuses HS,NOWDT
#device ADC=10
#use delay(clock=20000000)
#use rs232(baud=9600, UART1A)
#endif

#if !defined(__PCD__)

void main(void)
{
   
   /* PWM EXAMPLE FOR 8-BIT PICS */
   
   char selection;
   unsigned int8 value;

   printf("\r\nFrequency:\r\n");
   printf("    1) 19.5 khz\r\n");
   printf("    2) 4.9 khz\r\n");
   printf("    3) 1.2 khz\r\n");

   do {
     selection=getc();
   } while((selection<'1')||(selection>'3'));

   setup_ccp1(CCP_PWM);   // Configure CCP1 as a PWM

          //   The cycle time will be (1/clock)*4*t2div*(period+1)
          //   In this program clock=10000000 and period=127 (below)
          //   For the three possible selections the cycle time is:
          //     (1/10000000)*4*1*128 =  51.2 us or 19.5 khz
          //     (1/10000000)*4*4*128 = 204.8 us or 4.9 khz
          //     (1/10000000)*4*16*128= 819.2 us or 1.2 khz

   switch(selection) {
     case '1' : setup_timer_2(T2_DIV_BY_1, 127, 1);
                break;
     case '2' : setup_timer_2(T2_DIV_BY_4, 127, 1);
                break;
     case '3' : setup_timer_2(T2_DIV_BY_16, 127, 1);
                break;
   }

  setup_port_a(ALL_ANALOG);
  setup_adc(adc_clock_internal);
  set_adc_channel( 0 );
  printf("%c\r\n",selection);

  while( TRUE ) {
    value=read_adc();

    printf("%2X\r",value);

    set_pwm1_duty(value);          // This sets the time the pulse is
                                   // high each cycle.  We use the A/D
                                   // input to make a easy demo.
                                   // the high time will be:
                                   //  if value is LONG INT:
                                   //    value*(1/clock)*t2div
                                   //  if value is INT:
//    value*4*(1/clock)*t2div
                                   // for example a value of 30 and t2div
                                   // of 1 the high time is 12us
                                   // WARNING:  A value too high or low will
                                   //           prevent the output from
                                   //           changing.
  }

}
#else

void main(void) 
{

   /* PWM EXAMPLE FOR 16-BIT PICS */
   
   char selection;
   unsigned int16 value;

   printf("\r\nFrequency:\r\n");
   printf("    1) 76.37 hz\r\n");
   printf("    2) 9.55  hz\r\n");
   printf("    3) 1.19  hz\r\n");
   
   do {
     selection=getc();
   } while((selection<'1')||(selection>'3'));

          //   The cycle time will be (1/clock)*4*t2div*(period+1)
          //   In this program clock=20000000 and period=127 (below)
          //   For the three possible selections the cycle time is:
          //     (1/20000000)*4*1*65473  =  13.1 ms or 76.37 hz
          //     (1/20000000)*4*8*65473  = 104.7 ms or 9.55  hz
          //     (1/20000000)*4*64*65473 = 838.1 ms or 1.19  hz

   switch(selection) {
     case '1' : setup_timer2(TMR_INTERNAL | TMR_DIV_BY_1, 0xFFC0);
                break;
     case '2' : setup_timer2(TMR_INTERNAL | TMR_DIV_BY_8, 0xFFC0);
                break;
     case '3' : setup_timer2(TMR_INTERNAL | TMR_DIV_BY_64, 0xFFC0);
                break;
   }

  setup_adc_ports(ALL_ANALOG);
  setup_adc(adc_clock_internal);
  set_adc_channel(0);
  printf("%c\r\n",selection);
  
  setup_compare(1, COMPARE_PWM | COMPARE_TIMER2);
  
  while(TRUE) 
  {
    value=read_adc();

    printf("%LX\r",value);
    
    /* set the duty cycle using the adc reading.  the adc reading is in 10 bits,
      the duty cylce is in 16 bits, multiplying by 64 brings adc up to 16 bits */
    set_pwm_duty(1,value * (int16)64); // This sets the time the pulse is
                                       // high each cycle.  We use the A/D
                                       // input to make a easy demo.
                                       // the high time will be:
                                       // value is int16, clock = 20MHz, t2div = 1
                                       // This will give period of 13.1 ms
                                       // For example if value = 200, then
                                       //  value*64*4*(1/clock)*t2div = 2.56 ms
                                       // This will give an duty cycle of about 20 %
                                       // WARNING:  A value too high or low will
                                       //           prevent the output from
                                       //           changing.
                                   
  }

}
#endif
 
thanks,are and horace 1.
I want the duty cycle to vary with constant frequency. can anyone help me for pic24fj256da210.

i need to generate 4 pwm signals, which keep varying w.r.t to duty cycle ,but the frequency of all the 4 pwms remain constant.

can u tell me to generate atleast one pwm with varying dutycycle and constant frequency.

i need the code in C language.

the input would be voltage ranging from 0-5v ,and with variation in voltage input,the duty cycle keeps varying accordingly.
 

hi horace1... i am using a pic24fj256da210 development board to generate the pwm, can u explain me more about the code in C programmin... and how can i output it from the development board to see it on the scope. It would be of great help if you can alter the code for me. I am a beginner and need ur help badly.... thanks
 

the code in my previous post should work with the addition of setting the Peripheral Pin Select
Code:
// initialise PWM  - use  System Clock as the timer
void PWMinit(int dutyCycle)
{
       iPPSOutput(OUT_PIN_PPS_RP12, 18); 	        // set OC1 output to pin RP12
       OC1CON2bits.SYNCSEL=0x1F;			// set trigger/sync source is this OCM module
       OC1RS=(int)(401L); 			 		// set PWM duty cycle
       OC1R =(int)(400L*(dutyCycle)/100L);
       OC1CON1bits.OCM=7;					// set Center-aligned PWM mode
       OC1CON1bits.OCTSEL=7;	    		// setect System Clock
in this case the PWM will appear on RP12 - change it to suit your hardware
 
hi, i am using an pic24fj256da210 mother board. how do i check for the pwm outputs i get. can anyone tell me. how do i connect it to scope or how do i connect it to my pc ,to see the pwm signal i generated
 

the pic24fj256da210 has peripheral pin select, see section 10.4 of
https://ww1.microchip.com/downloads/en/DeviceDoc/39969b.pdf

which pin are you using for PWM output ? you have to setup the PPS to output the PWM signal to that pin.
for example, I am using a PIC24FJ256GB110 pin 71 which is RP12 and the PPS setup is
Code:
       iPPSOutput(OUT_PIN_PPS_RP12, 18); 	        // set OC1 output to pin RP12
18 is Output Compare 1 - I can then put an oscilloscope on pin 71 and see the pWM signal

similarly to output OC2 to pin 68 RP2 would be
Code:
       iPPSOutput(OUT_PIN_PPS_RP2, 19); 	        // set OC2 output to pin RP2
 

yeah ... since i am using a 100 pin chip.. which is embedded on pcb,as the pins are close how would i place the the scope on the pin.

can you give me your full code.... and tell me for what purpose did u use that particular code.
 

putting a scope probe on chip pins is tricky and requires a steady hand and good eyesight - I have a collegue who does this
you must have PCB tracks comming from some PPS RP output pins to drive the devices you wish to control - cannot you put an oscilloscope probe on the tracks?

I control a heater temperature (using OC1) and DC motor speed (using OC2) using PWM - the initialisation code is
Code:
       // setup OC1
       iPPSOutput(OUT_PIN_PPS_RP12, OUT_FN_PPS_OC1); // set OC1 output to pin PR12
       OC1CON2bits.SYNCSEL=0x1F;		// set trigger/sync source is this OCM module
       OC1RS=(int)(401L); 			// set PWM duty cycle
       OC1R =(int)(400L*(dutyCycle)/100L);
       OC1CON1bits.OCM=7;			// set Center-aligned PWM mode
       OC1CON1bits.OCTSEL=7;	    		// setect System Clock

       // setup OC2
       iPPSOutput(OUT_PIN_PPS_RP31, OUT_FN_PPS_OC2);  // OC2 to RP31
       OC2CON2bits.SYNCSEL=0x1F;		// set trigger/sync source is this OCM module
       OC2RS=(int)(401L); 			// set PWM duty cycle
       //OC2R =(int)(400L*(100-dutyCycle)/100L);
       OC2R =(int)(400L*(dutyCycle)/100L);
       OC2CON1bits.OCM=7;			// set Center-aligned PWM mode
       OC2CON1bits.OCTSEL=7;	    		// setect System Clock
then to set the heater PWM
Code:
       OC1R =(int)(400L*(100-dutyCycle)/100L);
and motor
Code:
       OC2R =(int)(400L*(dutyCycle)/100L);
for more PWMs copy the code and change to the required OCx - not forgetting to output to the correct PPS pin
 

    V

    Points: 2
    Helpful Answer Positive Rating
OC1RS=(int)(401L); // set PWM duty cycle
OC1R =(int)(400L*(dutyCycle)/100L);
what do you mean by 401L . can you explain these two lines
 

Last edited:

looking at section 13.3 Pulse-Width Modulation (PWM) Mode of the PIC24FJ256GB110 data sheet
PIC24FJ256GB110

the instructions to set it up are
1. Configure the OCx output for one of the available Peripheral Pin Select pins.
2. Calculate the desired duty cycles and load them into the OCxR register.
3. Calculate the desired period and load it into the OCxRS register.
4. Select the current OCx as the trigger/sync source by writing 0x1F to SYNCSEL<4:0> (OCxCON2<4:0>).
5. Select a clock source by writing the OCTSEL2<2:0> (OCxCON<12:10>) bits.

I have updated my code slightly to
Code:
       // setup OC2
       iPPSOutput(OUT_PIN_PPS_RP31, OUT_FN_PPS_OC2);  // OC2 to RP31
       OC2CON1=0;
       OC2CON2=0;
       OC2CON2bits.SYNCSEL=0x1F;			// set trigger/sync source is this OCM module
       // system clock 32MHz - period required 10Khz 
       // period OCxRS = (32000000/2) / 10000 = 1600  
       OC2RS=(int)(1600); 			 		// set PWM period
       OC2R =(int)(1599L*(dutyCycle)/100L); // duty cycle, period - 1 seems to work better
       OC2CON1bits.OCM=7;					// set Center-aligned PWM mode
       OC2CON1bits.OCTSEL=7;	    		// setect System Clock
my clock is 32MHz to I calculate the PWM period to give me a 10KHz PWM signal
OCxRS = (32000000/2) / 10000 = 1600
which I load into the OC2RS register

I then calculate the PWM duty cycle
OC2R =(int)(1599L*(dutyCycle)/100L)
I use long ints as the calculation could well exceed the maximum range of a 16 bit int
 
hi horace,
say if i have a period of 1milli sec, and i need to have varying duty cycle.
how do i fill in the OCxR REGISTER and OCxRS registers.
 
the value of OCxRS would be (clock frequency/2) / 1000
e.g. if system clock is 32MHz - period required 1Khz
OCxRS = (32000000/2) / 1000 = 16000

I would check It with an oscilloscope though!
you then load OCxR with a value between 0 and 15999 (0 to 100% duty cycle)
 

thankyou.... So i divide the system clock by 1000 because.. i need i khz freq rght.

and i also need to calculate PR value.
i have seen in your program u have
OC2R =(int)(1599L*(dutyCycle)/100L); // duty cycle, period - 1 seems to work better

what would it be for my program for duty cycle from 0-15999. how did u get this formula.
and about PPS pin.i need to select an output for each pwm rght.

---------- Post added at 11:47 ---------- Previous post was at 11:46 ----------

can you also post me a link, where i can find writing c code for pic. thanks
 

my code used the system clock ranther than a timer so did not need the PR value setting
duty cycle would be
Code:
OC2R =(int)(15999L*(dutyCycle)/100L);

to set the PPS pin use
Code:
iPPSOutput(OUT_PIN_PPS_RP31, OUT_FN_PPS_OC2);  // OC2 to RP31
repace RP31 with the pin you are using and the OC2 with the OC you are using

the book our students tend to use is "learning to fly the PIC24"
Home - Learning to Fly the PIC24

if you do a web search for "PIC24 tutorial" you will get lots of links, e.g.
**broken link removed**

let us know if you find any good ones
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top