| 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 | 
			 
		  | 
	
	
		  | 
	
	
		 |