Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

PWM using PIC with out CCP module ???

Status
Not open for further replies.

sahu

Member
how can use PWM using PIC with out CCP module ???
my aim controlling brightness of power led.
want use PIC16F676.but 676 not have built-in hardware, called Capture/Compare/PWM (CCP) module.
 
I use timer0... load TMR with two values A and B adjust A and B to always equal the same total ie..

50%
A = 34... On time
B = 34... Off time

25%
A = 17... On time
B = 51... Off time

75%
A = 51... On time
B = 17... Off time

You can play with the timer prescaler to adjust frequency and the total duration
(These are the values I used )
 
U can create a s'ware PWM via the interrupt handler, or use a PI s'ware control with the ADC to create a constant current supply.
 
Last edited:
thank u both of u . tomorrow i will try it. then sher here
Code:
/*
 Lab 9: Pulse Width Modulation
 Copyright @ Rajendra Bhatt, 2010.
 Description: CCP module generating a PWM signal
 MCU: PIC16F676
 Oscillator: XT, 4.0 MHz, MCLR Enabled
*/
/*                    
                  16F676 Configuration   
          O = Output, I = Input
                    _________
              Vdd   | 1  14 |  Vss
  (I) SW1 --> RA5   | 2  13 |  AN0 <-- Startup_Value (I)
  (I) SW2 --> RA4   | 3  12 |  AN1 <-- Mains_Sense (I)
             MCLR   | 4  11 |  RA2 -->  (O)
  (O)  L1 <-- RC5   | 5  10 |  RC0 -->  (O)
  (O)  L1 <-- RC4   | 6   9 |  RC1 -->  (O)
  (O)  <-- RC3   | 7   8 |  RC2 -->  (O)
                    ---------
*/
 sbit UP at RA5_bit;
 sbit DOWN at RA4_bit;
 unsigned short new_DC, current_DC;

 void debounce(){
  Delay_ms(300);
 }

 void main() {
    ANSEL = 0;                           // All I/O pins are configured as digital
   CMCON = 0x07; // Disable comparators
 PORTA = 0x00;
 PORTC = 0x00;
 TRISA = 0b00110000; // RB0, RB1 input, RB3 (PWM1) output
 PWM1_Init(5000);    // PWM module initialization (5KHz)
 new_DC = 0;         // Initial value of variable Duty Cycle
 current_DC = 0;
 PWM1_Start();       // Start PWM1 module with Zero DC
 PWM1_Set_Duty(current_DC);
 do {
  if (!UP){      // If the button connected to RB0 is pressed
   debounce();
   if (new_DC < 250)      // Don't go above 250
   new_DC = new_DC + 25 ; // increment Duty Cycle by 25
  }
  if (!DOWN) {   // If the button connected to RB1 is pressed
   debounce();
   if (new_DC !=0)        // Don't go below 0
   new_DC= new_DC - 25 ; // Decrement Duty Cycle by 25

  if (current_DC != new_DC) {
   current_DC = new_DC ;
   PWM1_Set_Duty(current_DC); // Change the current DC to new value
  }
  }
 } while(1);
}  // END main()
confuse how ?
 
Last edited:
The thread looks old, but still the solution is not completely dissed yet. I just successfully obtained PWM signals from GPIO using the Timer module on PIC16F877A, so decided to share my solution here...

To begin with, we have to decide the frequency and Ducty Cycle (ON time and Off time) of the PWM signal that we wish to generate. Once decided we can vary either or both of the parameters later in the program. Use these formulas to set the parameters.

T_TOTAL = (1/PWM_Frequency)
T_ON = (Duty_Cycle*T_TOTAL)/100
T_OFF = T_TOTAL – T_ON


The idea is that your Total time (Ton + Toff), should be constant to maintain a constant frequency. Without this the PWM signal will not be of good use.
Now, initialize the timer module on any GPIO pin and keep the pin turned on for T_ON duration and turned off for T_OFF duration. To do this we have to enable timer interrupt and for every overflow we check if the time has exceeded for on time or off time. the ISR code to do that is shown below

C++:
void interrupt timer_isr()
{
    if(TMR0IF==1) // Timer flag has been triggered due to timer overflow -> set to overflow for every 0.1ms
    {
        TMR0 = 248;     //Load the timer Value
        TMR0IF=0;       // Clear timer interrupt flag
        count++; //Count increments for every 0.1ms -> count/10 will give value of count in ms
    }
   
    if (count <= (T_ON) )
        RD1=1;
    else
        RD1=0;
   
    if (count >= (T_TOTAL*10) )
        count=0;
}

Hope you got the idea here. My actual code was to control a servo motor with PWM signal so I fixed the frequency of 50Hz and varied the duty cycle based on the POT connected to my ADC pin as shown documented here

Let me know if you have any doubts
 
Last edited:
You appear to be controlling a servo with a resolution of 0.1mS - this will give you only 10 available positions on your servo. OR, did I miss something?

Mike.
 
Hi mike,

The frequency of servo is 50Hz which is 20 milli sec.

So if we control the motor with resolution of 0.1ms we get (20/0.1) about 200 possible positions.
 
Hi mike,

The frequency of servo is 50Hz which is 20 milli sec.

So if we control the motor with resolution of 0.1ms we get (20/0.1) about 200 possible positions.

You need to rethink your plans, servo pulse range is from 1mS to 2mS - so only 1mS wide (maximum) - and 0.1mS resolution will only give you 10 positions.

The 20mS is the pulse repetition frequency, which isn't at all critical in any case, it's the pulse width which matters.
 
You can use timer1 to get uS accuracy which will give you 1000 poitions. Are you able to use interrupts?

Mike.
 
I found where I was wrong. My Bad. Thanks for letting me know.

I dint notice that the complete range of 20mS is not used and only the 2mS is used to control from 0* to 180*.

Looks like the minimum I could go with Timer0 is only upto 0.01ms with 64 as prescalar which will give me 100 positions.

So I will try with Timer 1 as suggested by Mike.

Will update how it goes

Thanks,
Aswinth
 
If you use the internal 4MHz oscillator and set timer1 prescaler to 1 then you'll get 1us accuracy.

Mike.
 
Sadly I am using the PIC16F877A which does not have an Internal OSC. So I tried it with a low prescalar value of 4 and made Timer 0 to work for 1uS.

I was able to control 1 servo motor through a potentiometer, but faced the following problem when expanding

1. Since the pot and the servo is connected to the same 5V rail of the PIC the POT value changes when servo moves and pulls in current and provides a voltage drop.

2. When I try to control more than 1 servo I get very bad lag.

My intention is to control 5 Servo with 5 POT for a Robotic Arm, So I think this approach is not a good Idea. However everything seems to run smooth on Simulation. I am planing to give another shot with Timer 1 with higher prescalar, If that fails to I am moving to the Idea of using a multiplexer IC
 
The pic16f877a has a ccp module... Your first post said you wanted to use the pic16f676 which HAS got an internal OSC!!

It's easy to set up Timer0 to give these values AND output different Duty cycles I have done at least three! If your 5v rail drops when running a single servo, then the rectifier isn't big enough!

My software PWM gave 64 bits resolution, which was enough for anything I was doing..
 
To control servos with a pic it's best to have a separate 6V supply for the servos and a well smoothed 5V supply for the pic.

To control 5 servos the simplest way is to use a 4mS time slot for each servo so that they get 1 pulse every 20mS.

Can you clarify which pic you're using?

Mike.
 
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top