View previous topic :: View next topic |
Author |
Message |
deonvds
Joined: 08 Sep 2003 Posts: 6
|
pgen |
Posted: Wed Jul 28, 2004 12:53 pm |
|
|
I am struggling to use the pwm for frequencies under 100hz. By reading the description of the example I see there is a new example ex_pgen.c that may do what I want. Can someone supply me with the example. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jul 29, 2004 12:38 pm |
|
|
Quote: | I am struggling to use the pwm for frequencies under 100Hz.
|
Look near the end of this thread. Ttelmah and Mark have posted
a routine for software PWM which uses the RTCC (also called Timer0).
http://www.ccsinfo.com/forum/viewtopic.php?t=17993&highlight=pwm
They didn't show the setup code for the RTCC, so I've taken the liberty
of making a test program. For a PIC with a 4 MHz crystal, this demo
program creates a PWM signal on Pin B1, with a frequency of 100 Hz,
and a 25% duty cycle.
Code: | #include <16F877.H>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 4000000)
#define PWM_PIN PIN_B1
#define LOOPCNT 39
int8 width;
//-------------------------------
#INT_RTCC
void tick_interrupt(void);
//====================================
main()
{
width = 10;
setup_counters(RTCC_INTERNAL, RTCC_DIV_1);
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
while(1);
}
//====================================
#INT_RTCC
void tick_interrupt(void)
{
static int8 loop = LOOPCNT;
static int8 pulse;
if(--loop == 0)
{
loop = LOOPCNT;
pulse = width;
}
if(pulse)
{
output_high(PWM_PIN);
pulse--;
}
else
{
output_low(PWM_PIN);
}
} |
Remember, this is for low frequency PWM, which requires a software
method. For higher frequencies, you can use the built-in hardware
PWM module which is present on many PICs. CCS has an example
of hardware PWM in their example file, EX_PWM.C. |
|
|
andys
Joined: 23 Oct 2006 Posts: 175
|
pgen |
Posted: Thu Jan 25, 2007 6:48 pm |
|
|
What is LOOPCNT?
and int8 is taken from header file and is
#define BYTE int??? |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Thu Jan 25, 2007 9:16 pm |
|
|
Did you look at the other post? It is a #define which equates to 30. int8 is a CCS variable type, 8 bit integer. |
|
|
umka
Joined: 28 Aug 2007 Posts: 99 Location: New Zealand
|
|
Posted: Sat Apr 19, 2008 4:04 am |
|
|
I am trying to implement this PWM but am having problems compiling. when i compile with the code below it gives errors:
Error 51 a numeric expression must appear here
Error 12 unidentified identifier pulse
Error 12 unidentified identifier pulse
Error 12 unidentified identifier pulse
Error 51 a numeric expression must appear here
Code: | #INT_RTCC
void tick_interrupt(void)
{
static int8 loop = LOOPCNT;
static int8 pulse;
if(--loop == 0)
{
loop = LOOPCNT;
pulse = width;
}
if(pulse)
{
output_high(PWM_PIN);
pulse--;
}
else
{
output_low(PWM_PIN);
}
} |
so i have changed the code to below
Code: | #INT_RTCC
void tick_interrupt(void)
{
static int8 loop, pulse;
loop = LOOPCNT; // if width=loopcnt then duty=100%
if (--loop == 0)
{
loop = LOOPCNT;
pulse = PWM_Width;
}
if (pulse)
{
output_high(PWM_Pin);
--pulse;
}
else output_low(PWM_Pin);
} |
Is the code the same? i think it is but just want confirmation. also how does the if (pulse) statement work? |
|
|
Ttelmah Guest
|
|
Posted: Sat Apr 19, 2008 4:48 am |
|
|
Major change.
The original, only initialised 'loop', _the first time the routine is called_, and resets it, only when loop == 0. The new code, re-initialises it _every time through the loop_. This prevents loop from actually counting on successive calls, and will stop it working....
The original as posted will compile. I'd suggest that you actually have a fault a few lines earlier in the code, which is preventing 'pulse' from being defined properly.
Best Wishes |
|
|
umka
Joined: 28 Aug 2007 Posts: 99 Location: New Zealand
|
|
Posted: Sat Apr 19, 2008 4:53 am |
|
|
Here is my complete code. It is unfinished hence some stuff missing or not making sense. it will receive a speed reference for a PID motor controller over the rs232. trying to compile this but i get the errors. Compiler is pcwh 4.038
Code: | #include <16F628a.h>
#device icd=true
#fuses HS,NOLVP,NOWDT
#use delay(clock=4000000)
#use rs232(baud=19200, xmit=PIN_B2, rcv=PIN_B1, ERRORS, LONG_DATA)
#define PWM_Pin Pin_B5
#define Wait_LED Pin_A0
#define Run_LED Pin_A1
#define LOOPCNT (30); // define PWM period for approx 50Hz
int16 Speed_Value; // Long value recieved over serial comm
int16 Speed_Reference; // Long value used in main routine
int8 PWM_Width; // PWM pulse width
int1 SI_Flag; // Serial interupt flag
int1 CCP1_Flag; // Speed update
#INT_RDA
void serial_isr() // Get serial data
{
Speed_Value = getc();
SI_Flag == 1;
}
#INT_RTCC
void tick_interrupt(void)
{
static int8 loop = LOOPCNT;
static int8 pulse;
if(--loop == 0)
{
loop = LOOPCNT;
pulse = width;
}
if(pulse)
{
output_high(PWM_PIN);
pulse--;
}
else
output_low(PWM_PIN);
}
void Set_PID ()
{
}
void main()
{
setup_counters(RTCC_INTERNAL, RTCC_DIV_1);
clear_interrupt(INT_RDA);
enable_interrupts(INT_RDA);
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
while (SI_Flag == 0)
{
Output_toggle(Wait_LED); // Waiting for speed_ref LED
Delay_ms(100);
}
Output_low(Wait_LED); // Ensure waiting LED off
PWM_Width = 10; // temperary
while (1);
{
if (SI_Flag == 1)
{
disable_interrupts(GLOBAL);
Speed_Reference = Speed_Value;
enable_interrupts(GLOBAL);
Output_High(Run_LED); // Running LED on
SI_Flag = 0;
}
if (CCP1_Flag == 1) // New speed ref recieved
{ Set_PID(); } // Set PWM_Width in here PWM_Width<LOOPCNT
// Output_toggle(Pin_A2); // to test it is cycling
// delay_ms(Speed_Reference / 100); // test it is getting speed_ref
}
} |
|
|
|
Ttelmah Guest
|
|
Posted: Sat Apr 19, 2008 9:37 am |
|
|
The main fault, is a few lines above the error.
You must not have a ';' at the end of the 'LOOPCNT' definition. This is what is causing the problems.
Some other minor comments.
You need to read out of the serial receive buffer, before you can clear 'INT_RD'. You _cannot_ clear this, unless the buffer is empty. If it has become set, it implies that data is there, and must be read first.
Code: |
#INT_RDA
void serial_isr() // Get serial data
{
Speed_Value = getc();
SI_Flag == 1;
}
|
The line 'SI_Flag==1', compares SI_Flag with '1', and then does nothing with the result. You only want a single '=' here.
Your use of 'long' for the serial receive does nothing. You are receiving 8bit data, so there is nothing 'long' for you to receive....
You haven't got a definition for 'width'. This needs to be a global variable defined before the interrupt handler, into which you put the 'width' count required.
Best Wishes |
|
|
umka
Joined: 28 Aug 2007 Posts: 99 Location: New Zealand
|
|
Posted: Sat Apr 19, 2008 1:55 pm |
|
|
thanks ttelmah it compiles now. the set flag was a typo supposed to be single = and the width was supposed to be PWM_Width but forgot to change when changing to original code.
what does having a ; after a #define do?
in the #use rs232 i have defined lond_data so i thought this would allow 16bit data to be sent. i need to send a speed reference of 0 to 35000 so need a long.
I do not understand how to implement the problem you say i will have with the recieve buffer. surely the buffer will be empty appon startup of the micro or do i need to clear the interupt only after i have enabled it?
thanks for the help |
|
|
Guest
|
|
Posted: Sat Apr 19, 2008 4:36 pm |
|
|
it means that anytime the compiler sees LOOPCNT is will replace it with "(30);" In an assignment that is not a problem:
x = LOOPCNT; which is
x = (30);;
But what happens if you
if (x == LOOPCNT) which is
if (x == (30);)
You will surely get an error. |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Sat Apr 19, 2008 4:37 pm |
|
|
it means that anytime the compiler sees LOOPCNT is will replace it with "(30);" In an assignment that is not a problem:
x = LOOPCNT; which is
x = (30);;
But what happens if you
if (x == LOOPCNT) which is
if (x == (30);)
You will surely get an error. |
|
|
Mechanical Engineer Guest
|
|
Posted: Tue May 19, 2009 6:23 am |
|
|
Hello ,
I am working on a project with 3 servo motors and each has a different duty cycle. I am working with 16F877A pic .Since all the programming world is very strange for me ,I am trying to understand how to use software pwm using the PCM programmer's code above. Is there any way I can use such a code for 3 different duty cycles same time?
Thank you for the help. |
|
|
bungee-
Joined: 27 Jun 2007 Posts: 206
|
|
Posted: Tue May 19, 2009 7:03 am |
|
|
Mechanical Engineer wrote: | Hello ,
I am working on a project with 3 servo motors and each has a different duty cycle. I am working with 16F877A pic .Since all the programming world is very strange for me ,I am trying to understand how to use software pwm using the PCM programmer's code above. Is there any way I can use such a code for 3 different duty cycles same time?
Thank you for the help. |
I have posted an servo routine (8 servos) for the 18F4550, but it should not be hard to rewrite it to 16F877A ....
The code is HERE |
|
|
Mechanical Engineer Guest
|
|
Posted: Tue May 19, 2009 9:31 am |
|
|
Thank u,but I am not sure how it helps me.
Another question , is there a calculation that i need to make for the right LOOPCNT? |
|
|
matheuslps
Joined: 29 Sep 2010 Posts: 73 Location: Brazil
|
|
Posted: Thu Dec 05, 2013 5:39 pm |
|
|
Why the LOOPCNT = 39?
How did you get that number? I debugged and understand the code. But this 39 I can not understand.
I am trying to make a soft pwm 1 to 30 hz....
bye |
|
|
|