|
|
View previous topic :: View next topic |
Author |
Message |
Tim Bobbins Guest
|
soft PWM code with LED glow trouble |
Posted: Thu Sep 06, 2007 1:05 am |
|
|
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 |
Posted: Thu Sep 06, 2007 5:03 pm |
|
|
Anyone? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Sep 06, 2007 5:13 pm |
|
|
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
|
sorry |
Posted: Thu Sep 06, 2007 5:53 pm |
|
|
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
|
|
Posted: Fri Sep 07, 2007 1:07 am |
|
|
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--) |
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
|
restless sleeps till its fixed |
Posted: Mon Sep 10, 2007 9:09 pm |
|
|
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
|
|
Posted: Tue Sep 11, 2007 1:06 pm |
|
|
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. |
|
|
|
|
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
|