CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

soft PWM code with LED glow trouble

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Tim Bobbins
Guest







soft PWM code with LED glow trouble
PostPosted: Thu Sep 06, 2007 1:05 am     Reply with quote

Hi all.

I hope you can help me with this problem. I have used abit of the code found in a previous post to implement software PWM.

I added a loop that will 'glow' a LED connected to pin B5. The desired action is to gradually increase the brightness from 0% to 100%, then back down to 0% and repeat. The following code does this just fine... but on the way from 100% to 0% most of the time a very short bright 'pop' will occur thus eliminating the smooth downward transition. And the odd thing is this does not happen from 0-100% - only as the LED darkens.

Anyone know why this might be happening, and how to fix?
Thanks for looking.

Code:

#include <16F877A.h>
#device ADC=10
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20M,oscillator)
#define timer1Preload 65200 //65458
#use rs232 (STREAM=RS485_PORT, BAUD=57600, XMIT=PIN_C6, RCV=PIN_C7, BRGH1OK, PARITY=N, BITS=8)
   
INT8 Intcount;

unsigned int portDuty[16]=
{
   0
};

#int_TIMER1

// NOCLEAR
void duty_irq()
{
   //   clear_interrupt (int_TIMER1);

   if (Intcount < 255)
   {
      if (Intcount == portDuty[0]) output_low (PIN_B0); //select REAL pin here
      if (Intcount == portDuty[1]) output_low (PIN_B1); //select REAL pin here
      if (Intcount == portDuty[2]) output_low (PIN_B2); //select REAL pin here
      if (Intcount == portDuty[3]) output_low (PIN_B3); //select REAL pin here
      if (Intcount == portDuty[4]) output_low (PIN_B4); //select REAL pin here
      if (Intcount == portDuty[5]) output_low (PIN_B5); //select REAL pin here
      if (Intcount == portDuty[6]) output_low (PIN_B6); //select REAL pin here
      if (Intcount == portDuty[7]) output_low (PIN_B7); //select REAL pin here
      if (Intcount == portDuty[8]) output_low (PIN_D0); //select REAL pin here
      if (Intcount == portDuty[9]) output_low (PIN_D1); //select REAL pin here
      if (Intcount == portDuty[10]) output_low (PIN_D2); //select REAL pin here
      if (Intcount == portDuty[11]) output_low (PIN_D3); //select REAL pin here
      if (Intcount == portDuty[12]) output_low (PIN_D4); //select REAL pin here
      if (Intcount == portDuty[13]) output_low (PIN_D5); //select REAL pin here
      if (Intcount == portDuty[14]) output_low (PIN_D6); //select REAL pin here
      if (Intcount == portDuty[15]) output_low (PIN_D7); //select REAL pin here
      Intcount++;
}

   else
   {
      output_high (PIN_B0);
      output_high (PIN_B1);
      output_high (PIN_B2);
      output_high (PIN_B3);
      output_high (PIN_B4);
      output_high (PIN_B5);
      output_high (PIN_B6);
      output_high (PIN_B7);
      output_high (PIN_D0);
      output_high (PIN_D1);
      output_high (PIN_D2);
      output_high (PIN_D3);
      output_high (PIN_D4);
      output_high (PIN_D5);
      output_high (PIN_D6);
      output_high (PIN_D7);
      Intcount = 0;
}

   //clear_interrupt (int_TIMER1);
   set_timer1 (timer1Preload);
}

   void main ()
   {
      int i;
      setup_timer_1 (T1_INTERNAL|T1_DIV_BY_1);
      enable_interrupts (int_TIMER1);
      enable_interrupts (GLOBAL);
     
      while (true)
      {
         //glow from dark to full brightness
         for (i = 0; i <255> 0; i--)
         {
            portDuty[5] = i;
            delay_ms (10);
   }

}
}

   
Tim Bobbins
Guest







help
PostPosted: Thu Sep 06, 2007 5:03 pm     Reply with quote

Anyone?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Sep 06, 2007 5:13 pm     Reply with quote

The problem is this:

Look near the end of your program in the for() loop. It's messed up.
That's because you made the post with HTML enabled. There's a tick box
below the posting window to disable it.

It's apparently impossible to get Admin to fix this problem (globally
disable HTML by default). I have tried.

So, you need to re-post your code and disable HTML this time.

Also, if possible, remove the "select REAL pin here" comments so
the code doesn't wrap. (At least, it wraps on my monitor).

If you register, you can turn off HTML in your profile. You can also
set the forum to "log you in automatically" each time you visit the forum.
Then HTML will always be disabled for you.
Tim Bobbins



Joined: 06 Sep 2007
Posts: 2

View user's profile Send private message

sorry
PostPosted: Thu Sep 06, 2007 5:53 pm     Reply with quote

Sorry, I wasnt aware of the HTML issues. I have registered now as well.
[The code within the else block may look inefficient, but the non-scaled down code contains decision blocks for each of the pins so I kept the same structure.]

Here's the correct code. i hope this works:

Code:

#include <16F877A.h>
#device ADC=10
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20M,oscillator)
#define timer1Preload 65200 //65458
#use rs232 (STREAM=RS485_PORT, BAUD=57600, XMIT=PIN_C6, RCV=PIN_C7, BRGH1OK, PARITY=N, BITS=8)
   
INT8 Intcount;

unsigned int portDuty[16]=
{
   0
};

#int_TIMER1

// NOCLEAR
void duty_irq()
{
   //   clear_interrupt (int_TIMER1);

   if (Intcount < 255)
   {
      if (Intcount == portDuty[0]) output_low (PIN_B0);
      if (Intcount == portDuty[1]) output_low (PIN_B1);
      if (Intcount == portDuty[2]) output_low (PIN_B2);
      if (Intcount == portDuty[3]) output_low (PIN_B3);
      if (Intcount == portDuty[4]) output_low (PIN_B4);
      if (Intcount == portDuty[5]) output_low (PIN_B5);
      if (Intcount == portDuty[6]) output_low (PIN_B6);
      if (Intcount == portDuty[7]) output_low (PIN_B7);
      if (Intcount == portDuty[8]) output_low (PIN_D0);
      if (Intcount == portDuty[9]) output_low (PIN_D1);
      if (Intcount == portDuty[10]) output_low (PIN_D2);
      if (Intcount == portDuty[11]) output_low (PIN_D3);
      if (Intcount == portDuty[12]) output_low (PIN_D4);
      if (Intcount == portDuty[13]) output_low (PIN_D5);
      if (Intcount == portDuty[14]) output_low (PIN_D6);
      if (Intcount == portDuty[15]) output_low (PIN_D7);
      Intcount++;
}

   else
   {
      output_high (PIN_B0);
      output_high (PIN_B1);
      output_high (PIN_B2);
      output_high (PIN_B3);
      output_high (PIN_B4);
      output_high (PIN_B5);
      output_high (PIN_B6);
      output_high (PIN_B7);
      output_high (PIN_D0);
      output_high (PIN_D1);
      output_high (PIN_D2);
      output_high (PIN_D3);
      output_high (PIN_D4);
      output_high (PIN_D5);
      output_high (PIN_D6);
      output_high (PIN_D7);
      Intcount = 0;
}

   //clear_interrupt (int_TIMER1);
   set_timer1 (timer1Preload);
}

   void main ()
   {
      int i;
      setup_timer_1 (T1_INTERNAL|T1_DIV_BY_1);
      enable_interrupts (int_TIMER1);
      enable_interrupts (GLOBAL);
     
      while (true)
      {
         //glow from dark to full brightness
         for (i = 0; i < 255; i++)
         {
            portDuty[5] = i;
            delay_ms (10);
    }
         //glow from dark to full brightness
         for (i = 255; i <1; i--)
         {
            portDuty[5] = i;
            delay_ms (10);
    }

   }
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Sep 07, 2007 1:07 am     Reply with quote

Quote:
//glow from dark to full brightness
for (i = 255; i <1; i--)
{
portDuty[5] = i;
delay_ms (10);
}

Is that hand-typed code ? Shouldn't it be:
Code:
 for (i = 255; i > 0; i--)


Quote:
INT8 Intcount;

This variable is never initialized. The code assumes it's initialized to 0.

Quote:
... but on the way from 100% to 0% most of the time a very short bright 'pop' will occur thus eliminating the smooth downward transition. And the odd thing is this does not happen from 0-100% - only as the LED darkens.

The problem is that the 10 ms delay in your for() loops is not long
enough for your PWM generator to finish a full cycle. I think it can
only count up to about 160 or so. So, when it's doing the brightening
ramp, it gets up to 160, but then on the dimming ramp, you start it
at 255, so it starts at a much brighter level. This accounts for the
"blip". As a short term fix, or just as a test, you could increase the
delay to 16 ms in the for() loops.

I don't want to do this project for you, but I don't like the idea of the
proper functioning of the PWM to be tied to some asynchronous delay
in main(). I would find a way to clean that up.
Tim Bobbins



Joined: 06 Sep 2007
Posts: 2

View user's profile Send private message

restless sleeps till its fixed
PostPosted: Mon Sep 10, 2007 9:09 pm     Reply with quote

Yes, I did hand code some of the above, as I was at work when I 'fixed' it.
The PWM is not dependant on the code in the main method. It is possible to set the PWM between 1-255 and the LED will happily glow dim or bright. It was just the code in the main method that simply changed the PWM value.

I did try varying the delays which did not work. Also tried to rework, and include ALL code needed in the interrupt routine. I still get that 'popping' only on the downward cycle.
Next I got rid of the interrupt altogether, and stuck the aforementioned code in the main body. I STILL get the popping on the way down. Usually in the same spot (~25% bright).

Any thoughts????

Code:

#include <16F877A.h>
#device ADC=10
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20M,oscillator)
#use rs232 (STREAM=RS485_PORT, BAUD=57600, XMIT=PIN_C6, RCV=PIN_C7, BRGH1OK, PARITY=N, BITS=8)

#define UP 1
#define DOWN 2
#define WAITUP 3
#define WAITDOWN 4

INT8 Intcount = 0;

long rampUpTimer=500;
long rampDownTimer=500;
long rampStayLowTimer=500;
long rampStayHighTimer=500;

unsigned int portDuty[16]=
{
   0
};

int8 mode=UP;
int i,globalPortDuty=0;
int16 longTimer=0;

   void main ()
   {
      int i;


   printf("STARTED");
   while(1){
   
   //increment global timer
   longTimer++;
 
   if(globalPortDuty>254 && mode==UP) {mode=WAITUP; longTimer=0;}
   else if(mode==WAITDOWN && longTimer>rampStayLowTimer) {mode = UP; longTimer=0;}
   else if(mode==WAITUP && longTimer>rampStayHighTimer) {mode = DOWN; longTimer=0;}
   else if(mode==DOWN && globalPortDuty<3) {mode=WAITDOWN; longTimer=0;}
   

   if ((mode==UP) && (longTimer>rampUpTimer))
   {
      portDuty[5] = ++globalPortDuty;
      longTimer=0;
   }
   else if ((mode==DOWN) && longTimer>rampDownTimer)
   {
      portDuty[5] = --globalPortDuty;
      longTimer=0;
   }

   if (Intcount < 255)
   {
      if (Intcount == portDuty[0]) output_low (PIN_B0); //select REAL pin here
      if (Intcount == portDuty[1]) output_low (PIN_B1); //select REAL pin here
      if (Intcount == portDuty[2]) output_low (PIN_B2); //select REAL pin here
      if (Intcount == portDuty[3]) output_low (PIN_B3); //select REAL pin here
      if (Intcount == portDuty[4]) output_low (PIN_B4); //select REAL pin here
      if (Intcount == portDuty[5]) output_low (PIN_B5); //select REAL pin here
      if (Intcount == portDuty[6]) output_low (PIN_B6); //select REAL pin here
      if (Intcount == portDuty[7]) output_low (PIN_B7); //select REAL pin here
      if (Intcount == portDuty[8]) output_low (PIN_D0); //select REAL pin here
      if (Intcount == portDuty[9]) output_low (PIN_D1); //select REAL pin here
      if (Intcount == portDuty[10]) output_low (PIN_D2); //select REAL pin here
      if (Intcount == portDuty[11]) output_low (PIN_D3); //select REAL pin here
      if (Intcount == portDuty[12]) output_low (PIN_D4); //select REAL pin here
      if (Intcount == portDuty[13]) output_low (PIN_D5); //select REAL pin here
      if (Intcount == portDuty[14]) output_low (PIN_D6); //select REAL pin here
      if (Intcount == portDuty[15]) output_low (PIN_D7); //select REAL pin here
      Intcount++;
}

   else
   {
      output_high (PIN_B0);
      output_high (PIN_B1);
      output_high (PIN_B2);
      output_high (PIN_B3);
      output_high (PIN_B4);
      output_high (PIN_B5);
      output_high (PIN_B6);
      output_high (PIN_B7);
      output_high (PIN_D0);
      output_high (PIN_D1);
      output_high (PIN_D2);
      output_high (PIN_D3);
      output_high (PIN_D4);
      output_high (PIN_D5);
      output_high (PIN_D6);
      output_high (PIN_D7);
      Intcount = 1;
}
}

}

PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Sep 11, 2007 1:06 pm     Reply with quote

My advice is:

1. Strip down your code so it uses just one PWM channel.
Delete the code for all the other channels.

2. Use printf() to display intermediate values from your PWM
generator code.

3. Give the code some duty cycle values that you believe cause
the problem. Watch the intermediate values when you do this.
Do any of them have unexpected values ?

4. Study the particular line of code that causes the problem.
Look for a problem in that line of code.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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