![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
Laus
Joined: 16 Jan 2016 Posts: 17 Location: Brazil
|
Pwm getc slow code |
Posted: Sat Jan 16, 2016 10:10 am |
|
|
Good morning, I'm doing a PWM controlled via RS232 to control a servo motor, however when using the getc () command the code is slow and generates pulses with more than 1sec. If you assign a fixed value to control variable, it can pulse in microseconds. I used RDA interrupt Timer and nothing. PWM is slow with getc command, which can be made precise pulse with 1 to 2 ms and 50 Hz.
Thank you for your help
Here is the code.
Code: | //PWM over rs232 RF433
#include <16F877A.h>
#fuses HS, NOWDT, NOPROTECT, NOLVP, NOPUT
#fuses NOBROWNOUT, CPD, NODEBUG, NOWRT
#use delay(clock=20MHz)
#use rs232(baud=9600, rcv=PIN_C7, bits=8, parity=N)
void main()
{
int32 x = 0;
// int8 c = 0; //code slow
int8 c = 20; // code fast
while (true)
{
for (x = 0; x < 100; x++)
{
if (x > c)
{
output_low (pin_b1);
}
if (x < c)
{
output_high (pin_b1);
}
if (x == 100)
{
x = 0;
}
// c= getc (); //make code slow, I need this to work fast PWM
}
}
} |
|
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Jan 16, 2016 10:44 am |
|
|
Laus wrote: |
// c= getc (); //make code slow, I need this to work fast PWM |
Add the parameters shown in bold below:
Quote: | #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, bits=8, parity=N, ERRORS) |
This will make the compiler use the hardware UART.
And also call kbhit() to see if a character is ready:
Code: |
if(kbhit())
c=getc();
|
|
|
![](templates/subSilver/images/spacer.gif) |
Laus
Joined: 16 Jan 2016 Posts: 17 Location: Brazil
|
|
Posted: Sat Jan 16, 2016 11:03 am |
|
|
Ok perfect PCM programmer thank you! So one more thing the pulse is a bit unstable it increases and decreases few microseconds alone there is something that can be done to stabilize? |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19359
|
|
Posted: Sat Jan 16, 2016 2:48 pm |
|
|
Obvious answer. Use the hardware PWM.
Functions all take time. It takes a few instructions to read a value if it is available, so 'of course' the PWM will change.
The way to do a 'slow' PWM (for servos etc.), is to use the CCP, rather than the PWM itself. Remember the CCP, in 'compare' mode, is a programmable timer, that allows you to select to change a pins state, or just to trigger an interrupt at a precisely defined interval. You can if you want just trigger the interrupt (and if you want, just 'poll' this, rather than calling a interrupt handler), to give times that are hardware determined, rather than dependant on instruction counts. Alternatively, you can use a similar approach, but just setting a timer to a value, and wait for the timer to wrap (again polling the interrupt bit for the timer), to give hardware determined times. Other thing to remember is that most servos don't actually 'care' how long the gap is between pulses. It is the pulse width that determines position. So do things that involve indeterminate times, in the 'gap'. |
|
![](templates/subSilver/images/spacer.gif) |
Laus
Joined: 16 Jan 2016 Posts: 17 Location: Brazil
|
|
Posted: Sun Jan 17, 2016 1:53 pm |
|
|
Almost going to the dark side of the force, AVR. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19359
|
|
Posted: Sun Jan 17, 2016 3:14 pm |
|
|
Which would do the same unless you use the hardware.... |
|
![](templates/subSilver/images/spacer.gif) |
Laus
Joined: 16 Jan 2016 Posts: 17 Location: Brazil
|
|
Posted: Sun Jan 17, 2016 3:39 pm |
|
|
Exactly avr has 6 PWM hardware for the same price for a pic with 1, but I still insist on the pic already made investment. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19359
|
|
Posted: Mon Jan 18, 2016 4:20 am |
|
|
Start at the beginning. Why use such an old chip?. The 877A, is about 15 years old. Many of the modern replacements have four or six PWM's.
Second the 877A, has two PWM's not one. However for the slow times needed for the servo, the CCP itself is the 'better' peripheral. To just do this in software/hardware using the CCP:
Code: |
//PWM over rs232 RF433
#include <16F877A.h>
#fuses HS, NOWDT, NOPROTECT, NOLVP, PUT
#fuses NOBROWNOUT, CPD, NODEBUG, NOWRT
//You should always use PUT when the crystal is used
#use delay(clock=20MHz)
#use rs232(BAUD=9600, UART1, ERRORS, BITS=8, PARITY=N) //ensure hardware UART used
#inline
int16 times_fifty(int8 val)
{
//efficient multiply by 50 from an int8 0 to 100
int16 result;
result=(int16)val*32;
result+=(int16)val*16;
result+=val*2;
return result;
}
void main()
{
int8 c = 20;
int1 flag=FALSE; //loop flag
//Now generating a 50Hz master loop, with pin b1 having controlled
//width in 100 steps from 1 to 2mSec at the start of this loop
setup_timer_1(T1_DIV_BY_1 | T1_INTERNAL);
//Timer1 now running from 5MHz. So 100000 counts/1/50th second
setup_CCP1(CCP_COMPARE_INT); //CCP1 will now set it's interrupt when the
//count is reached
while (true)
{
set_timer1(0);
output_high(PIN_B1); //turn pulse on
//Now need to program how long I want the pulse to be. At 100000 counts
//per 50th second, 1mSec = 5000 counts
//Using 'c' as the width, based on 0-100 = 1 to 2mSec
CCP_1=times_fifty(c)+5000; //now 5000 to 10000
clear_interrupt(INT_TIMER1);
clear_interrupt(INT_CCP1);
while (!interrupt_active(INT_CCP1))
; //wait for 'CCP_1' counts
output_low(PIN_B1); //and turn pulse off
//Now need to wait for the residue of 100000 counts
//also check serial while waiting
flag=FALSE; //For the first 65536 counts
while (TRUE)
{
if (flag && interrupt_active(INT_CCP1)) //Now have 65536+34464 counts
break; //exit loop
if (interrupt_active(INT_TIMER1))
{
//timer has reached 65536
flag=TRUE;
CCP_1=34463;
//100000 = 65536+34464
clear_interrupt(INT_TIMER1);
clear_interrupt(INT_CCP1);
}
if (kbhit())
{
c=getc();
if (c>100)
c=100; //in case character>100 arrives
}
}
}
}
|
Last edited by Ttelmah on Mon Jan 18, 2016 2:26 pm; edited 1 time in total |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19359
|
|
Posted: Mon Jan 18, 2016 10:02 am |
|
|
As a further comment, since it needs 5000 counts for 1mSec as setup here, if 'c' could be ASCII 0 to 156, then *32 could be used instead of *50.
Code: |
CCP_1=t(int16))c*32+5000;
//and when getting the character
if (c>156)
c=156; //in case character>156 arrives
|
Finer resolution, and more efficient. |
|
![](templates/subSilver/images/spacer.gif) |
Laus
Joined: 16 Jan 2016 Posts: 17 Location: Brazil
|
|
Posted: Mon Jan 18, 2016 5:49 pm |
|
|
Really 877 is an old pic but it is cheap and has no use for professional purposes it serves well. I have done many projects with him and set as a base, not yet had the need to use a more sophisticated pic. I am still learning to program, I have over 20 years experience in electronics but just over 3 in programming and the time and very short to dedicate. With a simple pic I learn more because I have to make up for the lack of hardware with software. Your code is very nice I will study it and extends it to my project.
Thank you for your help. |
|
![](templates/subSilver/images/spacer.gif) |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|