Simple PWM

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Anonymous
Not applicable

Guys,

   

 

   

Anyone know how to create a pulse for PWM, on a simple way ?

   

thanks

0 Likes
1 Solution
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

In the parameters window of PWM8 user module, set the "compare out" as Row0_Output0. Then, click on LUT on that row and click on the buffer which connects to GlobalOutEven4 (GOE 4). Then click on globalOutEven4 line and select the "pin" as P0[4].

   

Please see attached PDF file for example. 

   

 

   

-Rajiv Badiger 

View solution in original post

0 Likes
84 Replies
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

I tried to change with some values but I didn't see any change on the angle of the rotation, am I putting the wrong setting or a wrong code, can somebody explain ?

   

I'll attach the project with it

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Since you are a beginner, it will be very helpful for you not to try out everything, but focus on understanding what you are doing.

   

We are talking about a PWM which has several parameters that affect its performance.

   

Dana was talking about "Period" which as we suggested should be fixed at 20ms giving a frequency of 50Hz.

   

The PWM period for your application should be fixed and not cjhanged within the program. It is calculated by dividing the input-frequency of your PWM by (preiod-value +1) givint the output frequency. 1/frewquency is period , you hopefully know.

   

 

   

Next parameter in a PWM is the "pulse width" which is often referred to as "Duty-cycle". In your appllication the Pulse width has to be between 1 ms and 2 ms and must vary between thos values to move the servo.

   

A simple calculation which I would like to leave in your hands will relieve the valid range of values which you can send to the PWM by using the API PWM8_1_WritePulseWidth().

   

The delay you used to watch motor movement is just a thenth of a second which might be too short for the device to reach its wanted position, I would suggest to use a much longer delay at first Do not stop the PWM! some servos are diving into a fixed position when the pulses are not updated every 20ms.

   

So putting it all together I would suggest you to read and understand the datasheets, understand the APIs, understand the math behind and use it accordingly.

   

 

   

Happy coding

   

Bob

0 Likes
Anonymous
Not applicable

How to use this function then, for example I want to have 1ms ?

   

void GenerateZeroCycle(void)
{
    /* set period to eight clocks */
    PWM8_1_WritePeriod();

    /* set pulse width to generate a 33% duty cycle */
    PWM8_1_WritePulseWidth();

    /* ensure interrupt is disabled */
    PWM8_1_DisableInt();

    /* start the PWM8! */
    PWM8_1_Start();
}
 

0 Likes
Anonymous
Not applicable

The video:

   

http://www.youtube.com/watch?v=Oi3joZJq0Yc&feature=youtu.be

   

 

   

The code :

   

void GenerateHalfDutyCycle(void)
{
    /* set period to eight clocks */
    PWM8_1_WritePeriod(199);

    /* set pulse width to generate a 33% duty cycle */
    PWM8_1_WritePulseWidth(200);

    /* ensure interrupt is disabled */
    PWM8_1_DisableInt();

    /* start the PWM8! */
    PWM8_1_Start();
}

/* Divide by eight function */
void GenerateZeroCycle(void)
{
    /* set period to eight clocks */
    PWM8_1_WritePeriod(19);

    /* set pulse width to generate a 33% duty cycle */
    PWM8_1_WritePulseWidth(20);

    /* ensure interrupt is disabled */
    PWM8_1_DisableInt();

    /* start the PWM8! */
    PWM8_1_Start();
}

.

   

.

   

.

   

.

   

.GenerateHalfDutyCycle();
    Delay10msTimes(90);
    GenerateZeroCycle();
    Delay10msTimes(90);

   

 

   

Is there anything I can do to make the angle bigger, I've done all the suggestions above but it doesn't work properly,

   

any idea ?

   

Please find the project attached in a previous post to check it..

   

 

   

Thanks a lot

0 Likes
lock attach
Attachments are accessible only for community members.
MeenakshiR_71
Employee
Employee
100 likes received 50 likes received 25 likes received

Hello Bianchi,

   

 

   

In the case that there are no timing diagrams provided, we can try 1.5 ms for center position and any position less than 1.5 ms is going to move the rotor angel to a position less than 90 and above 1.5 ms it will be more than 90 degrees. Since we do not know the exact values we need to figure the limits by experiments.

   

 

   

Please try the below -

   

 

   

Global settings -

   

Power setting = 5.0 V/24MHz; VC1 = 6, VC2 = 4, VC3 source = VC2 and VC3 = 100; ==> VC3 = 10 KHz or 100 uS signal

   

 

   

Place a PWM8 UM, and configure the parameters as in attached figure.

   

Route the CompareOut signal to the Servo's control signal pin (most probably the white wire of the servo).

   

 

   

Use the below code to move it to center position -

   

    /* set pulse width to generate a 1.5ms high pulse duty cycle */
    PWM8_1_WritePulseWidth(30);   

    /* start the PWM8! */
    PWM8_1_Start();

   

 

   

Use the below code to move the servo rotor to less than 90 degree -

   

    /* set pulse width to generate a <1.5ms high pulse duty cycle */
    PWM8_1_WritePulseWidth(25);   

    /* start the PWM8! */
    PWM8_1_Start();

   

 

   

Use the below code to move the servo rotor to more than 90 degree -

   

    /* set pulse width to generate a >1.5ms high pulse duty cycle */
    PWM8_1_WritePulseWidth(35);   

    /* start the PWM8! */
    PWM8_1_Start();

   

 

   

You can play around with the pulse width values to see how far the rotor turns and make a note of the limits to use in your final design. Also note that the 1.5 ms center position pulse is arbitrarily chosen as that is the most common width for a center pulse in most servos. You can verify that too by observation.

   

 

   

Let me know if this helps.

   

 

   

Regards,

   

MSUR

0 Likes
Anonymous
Not applicable

It does rotate but can not return to center position even I put in a code :

   

 

   

/* Divide by eight function */
void GenerateCenterPosition(void)
{
    /* set period to eight clocks */
    //PWM8_1_WritePeriod(10);

    /* set pulse width to generate a 33% duty cycle */
    PWM8_1_WritePulseWidth(30);

    /* ensure interrupt is disabled */
    PWM8_1_DisableInt();

    /* start the PWM8! */
    PWM8_1_Start();
}

/* Divide by eight function */
void GenerateLessThan90(void)
{
    /* set period to eight clocks */
    //PWM8_1_WritePeriod(199);

    /* set pulse width to generate a 33% duty cycle */
    PWM8_1_WritePulseWidth(25);

    /* ensure interrupt is disabled */
    PWM8_1_DisableInt();

    /* start the PWM8! */
    PWM8_1_Start();
}

/* Divide by eight function */
void GenerateMoreThan90(void)
{
    /* set period to eight clocks */
    //PWM8_1_WritePeriod(35);

    /* set pulse width to generate a 33% duty cycle */
    PWM8_1_WritePulseWidth(35);

    /* ensure interrupt is disabled */
    PWM8_1_DisableInt();

    /* start the PWM8! */
    PWM8_1_Start();
}
 

   

main :

   

GenerateCenterPosition();
    Delay10msTimes(90);
    GenerateLessThan90();
    Delay10msTimes(90);
    GenerateMoreThan90();
    Delay10msTimes(90);

0 Likes
MeenakshiR_71
Employee
Employee
100 likes received 50 likes received 25 likes received

How much did it rotate? Were the rotation direction for more than and less than 90 degree opposite? Provide a delay more than 200 ms. (as it takes 131 ms to rotate 60 degrees - if the rotation angle is more than 60 degree than provide a higher delay)

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Bianchi, you are a bit relucant against hints we gave you:

   

We told you not to change the period value, since it will be stable at 20ms / 50Hz.

   

The pulse width is the time the output signal is high. So it cannot be more than the period value

   

Your calculation of duty-cycle are darn wrong

   

Your servo is not controlled by a duty-cycle arithmetic, but by a formula similar to

   

    ValueFor1ms + ValueFor1ms * Percentage / 100 (of course this formula can be simplified, I leave that to you)

   

Take care, that your comments in the program do reflect the actual coding.

   

 

   

Something to make life easier:

   

Set the period value in the PWMs properties window and do not change it anymore.

   

For your application you may set the pulse width in the property dialog to 1ms or 1.5ms (both need some calculations) so that at start of the PWM a defined value is already taken.

   

Change (only!!) the pulse-width programatically on-the-fly, that will work for your application.

   

Take enough time to watch your servo moving.

   

 

   

Bob

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

To simplify things more, did you know that the compiler is able to calculate formulas for you?

   

You may write

   

#define ValueFor1ms 20 // Insert your correktly calculated value here

   

#define PulseWidth(Percent) (ValueFor1ms + ValueFor1ms * Percent / 100)

   

 

   

Now you can write in your program

   

PWM8_1_WritePulseWidth(PulseWidth(50)); // Midst position

   

 

   

and so on...

   

 

   

Happy coding

   

Bob

0 Likes
Anonymous
Not applicable

How much did it rotate? Were the rotation direction for more than and less than 90 degree opposite? Provide a delay more than 200 ms. (as it takes 131 ms to rotate 60 degrees - if the rotation angle is more than 60 degree than provide a higher delay)

   

 

   

 

   

It can rotate to 60 degree but can't return to 0 position, I don't know why since I put 900ms delay and ask it to return to 0 position on the code, do you have idea ?

   

Is the code or hardware issue ?

   

thanks

0 Likes
Anonymous
Not applicable

How about do it one step a time

   

1. You need to set the PWM up with 10khz clock (0.1ms clock) - you need to change the VC1, VC2 and VC3 divider accordingly.
2. Set the period in the designer to 199 (period of 20ms)
3. Set the Pulse width value in desiger to 14 which gives you 1.5ms (ie middle position)
4.DONT WRITE any thing in your main.c, just let the PWM started, let it run, the servo should stay in the middle

   

If your driver to your servo is "ON" when the pulse is high, it should work. If it isn't you might have the driver inverted.
Then you change the pulse wide value from 14 to to 185.

   

Come back and tell us what you find and upload your project here as well so people can check.

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

How about do it one step a time

   

1. You need to set the PWM up with 10khz clock (0.1ms clock) - you need to change the VC1, VC2 and VC3 divider accordingly.
2. Set the period in the designer to 199 (period of 20ms)
3. Set the Pulse width value in desiger to 14 which gives you 1.5ms (ie middle position)
4.DONT WRITE any thing in your main.c, just let the PWM started, let it run, the servo should stay in the middle

   

If your driver to your servo is "ON" when the pulse is high, it should work. If it isn't you might have the driver inverted.
Then you change the pulse wide value from 14 to to 185.

   

Come back and tell us what you find and upload your project here as well so people can check.

    I've done your suggestion, nothing is happened,
   

   

Please find my project attached, may be you guys can see what to do...

0 Likes
lock attach
Attachments are accessible only for community members.
ETRO_SSN583
Level 9
Level 9
250 likes received 100 sign-ins 5 likes given

Attached is a project partial re-write to look at with

   

comments in the file main.c.

   

 

   

You had a number of typos, and un-necessary functions. The calculations

   

for duty cycle did not follow the datasheet equations for reference.

   

 

   

Regards, Dana

0 Likes
ETRO_SSN583
Level 9
Level 9
250 likes received 100 sign-ins 5 likes given

If you modify the routine I wrote to -

   

 

   

void DCset( unsigned char dc ) {

   

// Pulsewidth value = Duty Cycle X ( Period value + 1 ) = Duty Cycle X 200
// But Duty Cycle is fractional (% expressed as a fractional, like .35 for 35%),
// so lets convert whole equation to integer by multiplying by 100, so we have
// 100 x Pulsewidth value = Dutycyle (as integer now) X ( Period value + 1 ) or
// Pulsewidth value = ( Dutycyle (as integer now) X ( Period value + 1 ) ) / 100
// Period value = 199, so
// Pulsewidth value = ( Dutycyle (as integer now) X 200 ) / 100 so
// Pulsewidth value = Dutycyle (as integer now) X 2
// So to get a DC of 75 we write "DCset( 75 );" in our code

   

 dc = ( dc > 100 ) ? 100 : dc;     // Make sure if dc typed > 100 it is limited to 100
                                                  // Note a dc of 0 or 100 results in a fixed low or high on output

   

    PWM8_1_WritePulseWidth( dc * 2 );     /* set pulse width to generate a dc% duty cycle */
}

   

 

   

Examples -

   

 

   

 DCset( 0 );        // Produces a DC =   0 %, a constant low on pin, no pulses
 DCset( 1 );        // Produces a DC =   1 % on pin
 DCset( 99 );      // Produces a DC =  99 % pn pin
 DCset( 100 );    // Produces a DC = 100 %, a constant high on pin, no pulses

   

 

   

Regards, Dana.

0 Likes
Anonymous
Not applicable

Hi bianchi,

   

In your project,  you didn't start the PWM.

   

Dana's sugestions is useful and make the firmware more easily understand.

   

Do you have access to a CRO, if may be helpful if you can acually see the output waveform.

0 Likes
ETRO_SSN583
Level 9
Level 9
250 likes received 100 sign-ins 5 likes given

HL, the project I did a partial re-write did start PWM.

   

 

   

Regards, Dana.

0 Likes
Anonymous
Not applicable

Dana,

   

Thanks for the response, I tried your code, I didn't see any movement on my motor,

   

is there something missing here ?

   

Cheers

0 Likes
Anonymous
Not applicable

Hi Dana,

   

Yes, you code has the PWM started. 

   

I think it would be better for him/her to understand why the program not working, rather then give him/her a working code.

0 Likes
Anonymous
Not applicable

Hi bianchi,

   

Use the one you uploaded, change it so the PWM started function is called.

   

( Again, you may need to change the Pulse width if your ouput is inverted).

   

If it works, then change the pulse width in the DESIGNER to be between 10 to 20 (1 to 2 ms). and run the program after compiling.

   

YOu should be able to see the servo moved to a different angle.

   

 

   

 

   

Here is a reference you may be intertested in.

   

http://gekogeek.com/embedded/servo-motor-control/

0 Likes
ETRO_SSN583
Level 9
Level 9
250 likes received 100 sign-ins 5 likes given

You might confirm the wiring to the servo is correct.

   

 

   

Additionally, use a scope, set up a function generator for 20 mS period,

   

1.5 mS high pulse, and see if servo is OK.

   

 

   

Regards, Dana.

0 Likes
Anonymous
Not applicable

You guys mean :

   


void DCset( unsigned char dc ) {

    PWM8_1_WritePulseWidth( dc );                    /* set pulse width to generate a 50% duty cycle */
    PWM8_1_Start();
}

0 Likes
Anonymous
Not applicable

I can see the motor is vibrating but not moving at all...not rotating as I want....

   

is it because of wrong timing ?

0 Likes
Anonymous
Not applicable

If you set it to 50%, your pulse width is 10ms. your servo needs to be in 1-2 ms.

   

Did you try your code as I suggested.

0 Likes
Anonymous
Not applicable

Can you get a CRO? If you can, check the ouput pulse width of your PSOC. the period should be 20mS and pusle width should be between 1 to 2 ms.

   

If you cannot, then try to use a function generator. Set the freqency to 50Hz, and duty cycle should be between 5 to 10%.

0 Likes
ETRO_SSN583
Level 9
Level 9
250 likes received 100 sign-ins 5 likes given

My guess is the reason your servo is "hunting" is you keep restarting

   

PWM in a loop. If you look at the code I sent you its basically this -

   

 

   

main() {

   

 

   

      startup stuff, including PWM

   

      ...

   

      while( 1 ) {

   

 

   

         call write pwm function with a value to set dc in it

   

         .....

   

         .....

   

      }

   

}

   

 

   

When you write a new compare value, the pwm immeadiately updates itself with new

   

PW value, so you could glitch the output. A better way would be to modify the function

   

I gave you to this -

   

 

   

void DCset( unsigned char dc ) {

   

    PWM8_1_Stop( );

    PWM8_1_WritePulseWidth( dc );                    /* set pulse width to generate a 50% duty cycle */

   

    PWM8_1_Start( );
}

   

 

   

But even this will still produce a foreshortened pulse under some circumstances.

   

The way to always have these PWMs always complete current cycle first is to implement

   

an ISR on terminal count, set a flag in ISR, and return to main() where if you find

   

flag set you do the update to PWM puslewidth, and clear the flag.

   

 

   

Lastly in general you do not want to write any HW in a tight loop, ie. keep updating at

   

high speed. That can mean the HW itself never has time to adapt to the changes

   

being rapidly written to it repeatedly, like a servo. Thats why you use a time delay in

   

your while( 1 ) loop to allow servo to respond, which I see you have commented out.

   

 

   

Regards, Dana.

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

Hi Dana,

   

This is the result:

   

http://youtu.be/TDjuHwZ4NYo

   

 

   

I attach the project with it, could it be the timing ?

   

Since it's working fine in MCS51 for rotating but it's not easy for me to transfer to cypress....

   

Should be easy but I don't know exactly...

   

 

   

Thanks for helping

0 Likes
Anonymous
Not applicable

The simple idea :

   

how can I output 0 and 1 to P0.0 in certain of time like this code :

   

In this line of code I don't have PWM module since it's MCS51, so it's pure 1 and 0 and timing....

   

 

   

void delay_us (void) //100us delay on 12Mhz
{
    TH0=0;
    TL0=0;
    TH0 = 0xFF;
    TL0 = 0x37;
    TR0 = 1;
    while(!TF0);
    TR0 = 0;
    TF0 = 0;
    return;
}

void timer(int j)
{
     int i;
      for (i=0;i<j;i++)
        {
          delay_us();
        }
}

   

    while(1)
    {   
        //motor begin
            count=10;
             //rotate left every 45 degree begin
                     for(i=0;i<50;i++)  // 10 equal to 5 degree
                        {
                            output=1;
                            timer(count);         
                            output=0;
                            timer(100);
                            //timer(70);
                        }

   

  }

0 Likes
Anonymous
Not applicable

Dana, from the motor seller :

   

here's the spec :

   


Operating Speed (4.8V no load) : 0.131sec / 60 degrees

   

it means : 131ms for 60 degree....

0 Likes
ETRO_SSN583
Level 9
Level 9
250 likes received 100 sign-ins 5 likes given

Do you have a datasheet for the servo, a link.

   

 

   

Its not a "normal" RC/Toy/Hobby servo, which is the timing we have given

   

you in prior posts. Based on your 131 mS comment.

   

 

   

Regards, Dana.

0 Likes
Anonymous
Not applicable

I used AT89S52, it's allright :

   

youtu.be/Jwvp-Vw5RZs

0 Likes
ETRO_SSN583
Level 9
Level 9
250 likes received 100 sign-ins 5 likes given

All I can tell you is PSOC PWM works fine with Hobby type RC servos,

   

with the timing we posters gave you prior.

   

 

   

Still curious as to what specific servo your are using.

   

 

   

Regards, Dana.

0 Likes
Anonymous
Not applicable

Dana,

   

I use : TowerPro MG996 Hi Torque digi servo

   

Any experience with this one ?

   

thanks

0 Likes
Anonymous
Not applicable

1. YOU NEED TO START the PWM. it will not work if not started

   

2. The 3 function GenerateCenterPosition

   

 

   

 will NOT WORK as the pulse width MUST be between 1ms and 2 ms, 

   

PULSE width(100) will give you 10mS!!!!!

   

 

   

4. If you use the DCset () the value should be between 10 and 20.

   

5.  Update your comments when you change you code.!!!!  Wrong comment is worse then no comment.

   

 Of course you can use the counter time delay function you mention. But you need to make sure that your period is 20ms with pulse width of 1 to 2 ms.

   

 

   

 

   

 

   

 

   

 

   

 

   

 

   

 

   

   

void

   

GenerateLessThan90

   

void

   

 

   

void GenerateMoreThan90

0 Likes
Anonymous
Not applicable
0 Likes
Anonymous
Not applicable

The preiouse post is all corrupted.

   

 

   

Here is it again

   

1. THE PWM must be STARTED, you didn't do it in your main.c

   

2. The pulse width MUST between 1 to 2 ms. The value you use in the DCset MUST be between 10 and 20, same problem with the 3 generate functions.

   

3. UPDATE comments after changing your code. WRONG comment is worse then no comments.

   

4. If you use the delay timer function, Just make sure the period is 20ms with pusle width between 1 to 2 ms

0 Likes
Anonymous
Not applicable

I started already,

   

 

   

Don't worry too much with the comment, it's only a dummy project

   

void GenerateCenterPosition( void ) {                /* Divide by eight function */
    PWM8_1_Stop();
    PWM8_1_WritePulseWidth( 100 );                    /* set pulse width to generate a 50% duty cycle */
    PWM8_1_Start();
}

0 Likes
Anonymous
Not applicable

Sorry, I missed that.

   

Did you try change the DCset() vlaue betwen 10 and 20? for ie 10 is the left, 15 is the middle, and 20 is the right positiom.

0 Likes
Anonymous
Not applicable

Mate,

   

There's no response, servo is stall, just like video I have shown you guys

0 Likes
Anonymous
Not applicable

I tried to imitate the function :

   

 

   

void rotate()
{
     unsigned int i,count;                                 /* Delay10msTimes var */
      unsigned char j;                                   /* LED var */
 
count=10;
             //rotate left every 45 degree begin
                     for(i=0;i<50;i++)  // 10 equal to 5 degree
                        {
                            P0_0(1);
                            Delay10msTimes(count);         
                            P0_0(0);
                            Delay10msTimes(100);
                            //timer(70);
                        }
                    Delay10msTimes(200);   
             for(i=0;i<50;i++)
                        {
                            P0_0(0);
                            Delay10msTimes(count);         
                            P0_0(1);
                            Delay10msTimes(100);
                            //timer(70);
                            //timer(70);
                        }
                          Delay10msTimes(200);   

}

   

 

   

but I can't see my LED blinks, anyone knows why ?

   

thanks

0 Likes
Anonymous
Not applicable

how can I do 90 and -90 degree ?

   

thanks

0 Likes