Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

16f628a Software PWM of led

Status
Not open for further replies.
Ah, you've got one of Pete's kits (forum member 'Gecko').

Attempting to modify his code will be difficult because it's so tightly integrated. While he has 5-bit (32 level) software PWM (using vertical counters), I believe he's only storing two bits of information for each LED in the data tables and I suspect that's why you only get four brightness levels; 'off', 'dim', 'bright', and 'very bright'.

Eight LEDs spread across two ports in that circuit will require a little bit more work in your new software (I wonder why he did that?).

Some considerations... If you need smooth fade and/or animation capabilities, you need (A) as small a PWM 'step' as possible (1-us, 500-ns, 250-ns, etc.), (B) a large number of PWM steps (256 or 512 minimum), and, (C) a gamma or brightness correction method to reduce the 256 or 512 non-linear PWM brightness levels to something like 32, 64, or 100 linear brightness levels. You also want to have a very high refresh rate because you only want to change the brightness level of any LED at the end of each PWM period or 'frame' in order to avoid visual artifacts. For example, if you have a 100-Hz refresh rate or 'frame' rate you can only change the brightness level of any LED 100 times per second. Now if you have 100 linear brightness levels, for example, and you want to fade an LED up and down as quickly as possible, it will take 200 'frames' or approximately 2.0 seconds. If you increase the refresh rate or frame rate to 200-Hz or 400-Hz, you can fade an LED up and down in 1.0 second and 0.5 seconds, respectively.

I'll continue to look for some examples for you, Sir.

Good luck on you project. Cheerful regards, Mike
 
Ah, you've got one of Pete's kits (forum member 'Gecko').

Eight LEDs spread across two ports in that circuit will require a little bit more work in your new software (I wonder why he did that?).

When you say 2 ports, is that an internal thing, because they are connected to 8 individual pins
 
Simple C code (Its what I mainly work with!!!)

C:
#include<XC.h>
__PROG_CONFIG(1,0x3F0A);
volatile unsigned char ledPwm[8]; // * different values
volatile unsigned char PWM;

void delayUs(int x) 
   {
   x>>= 2;
   while(x--);
   }

void delayMs(int x)     // Millisecond ish
   {
   while(x--)
     delayUs(1000);
   }

void interrupt ISR()
   {
   if(TMR0IF)
     {
     PWM++;               // Check each level!!
     if(ledPwm[0] < PWM)RB0 = 0;
     if(ledPwm[1] < PWM)RB1 = 0;
     if(ledPwm[2] < PWM)RB2 = 0;
     if(ledPwm[3] < PWM)RB3 = 0;
     if(ledPwm[4] < PWM)RB4 = 0;
     if(ledPwm[5] < PWM)RB5 = 0;
     if(ledPwm[6] < PWM)RB6 = 0;
     if(ledPwm[7] < PWM)RB7 = 0;
     if(PWM > 64)
       {
       PWM = 0;           // Frequency start
       PORTB = 0xFF;
       }
     TMR0 = 200;             // Adjust frequency here..
     TMR0IF = 0;
     }
   }

void main()
   {
   unsigned char x,LED;
   TRISA0 = 0;
   TRISB = 0x0;
   OPTION_REG = 0;         // no pre scale
   TMR0IE = 1;
   TMR0 = 200;           // frequency
   GIE = 1;           // interrupts on
   LED = 64;
   PORTB = 0x55;         // start pattern
   while(1)
     {
     for(x=0;x<8;x+=2)       // fill with arbitury values
       ledPwm[x] = LED;      //
     for(x=1;x<8;x+=2)
       ledPwm[x] = 64 - LED--;  
     if(LED <  1)
       LED = 64;
     delayMs(50);       // Visualise time...
     }
   }
Running.....
What clock speed are you running for this demo, Ian?

If I'm simulating the demo correctly, there's about ~160 instructions cycles per PWM step and about ~10240 instructions cycles per PWM period. If you're running the demo at 20-MHz that would translate to a rather coarse ~32-uS per PWM 'step' but at a quite decent ~2048-uS (488-Hz) period.
 
20Mhz.... The interrupt latencey is @ 8.4uS and is called every 25uS.. There is 33.6uS per step @ 2.15mS time base...

If I went to a rather (Coarser ) frequency ie.. 32 steps then I would get the 1khz I quoted...

This was only an example... I have used this before just to dim a control panel....
 
When you say 2 ports, is that an internal thing, because they are connected to 8 individual pins
Yeah, four pins on PORTA and four pins on PORTB. It will require a pair of write operations to update the LEDs during each PWM 'step' which increases the PWM 'step' time.
 
20Mhz.... The interrupt latencey is @ 8.4uS and is called every 25uS.. There is 33.6uS per step @ 2.15mS time base...

If I went to a rather (Coarser ) frequency ie.. 32 steps then I would get the 1khz I quoted...

This was only an example... I have used this before just to dim a control panel....
It actually looks pretty good. You can see some "stair stepping" but that's to be expected during fade operations since linear PWM steps produce non-linear brightness levels. It's certainly better than the three coarse brightness levels the OP started out with...
 
It actually looks pretty good. You can see some "stair stepping" but that's to be expected during fade operations since linear PWM steps produce non-linear brightness levels. It's certainly better than the three coarse brightness levels the OP started out with...
When I first ran it, I thought I'd programmed it incorrectly as it seemed to only have 16 steps.... But it was an optical error to the eye.... After I slowed the PWM refresh to 500mS I could see the difference..

And after all that we are told he will only ever use one at a time.... 8:1 multiplexing and one hardware PWM would have done the job!!!.....

The point here is that he can offer PWM on any generic IO pin...
 
And after all that we are told he will only ever use one at a time.... 8:1 multiplexing and one hardware PWM would have done the job!!!.....
.

Sorry if you misunderstood, however I did say this in my very first post
Plus the circuit is already built, I dont have the freedom to move components
 
Here are a couple more posts on the Microchip forum with "gamma correction" or "linear brightness correction" information, including a JustBASIC program for generating gamma correction tables;

Gamma Correction Table
Driving RGB LED using PWM

download.axd

On a related note... I simulated a "toggle table" method PWM driver in Ian's program (excerpt below). It's faster and it fixes the 0% duty cycle bug in Ian's code but the XC8 assembler output is ghastly (as usual). The toggle table method is interesting because it takes the same amount of time to insert eight toggle bits into the toggle table (refresh the table) at the end of each PWM period whether the table is 64, 256, or 1024 bytes (steps) long. Unfortunately, it simply uses too much RAM.

Code:
void interrupt ISR()
{ static unsigned char step = 0;
  static unsigned char toggle[64] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                                      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                                      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                                      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
  PORTB ^= toggle[step];            // update channel outputs
  toggle[step] = 0;                 // clear element for next period
  step++;                           //
  if(step == 64)                    // if end-of-period
  { step = 0;                       //
    toggle[led[0]] |= 1;            // insert LED 0 toggle bit
    toggle[led[1]] |= 2;            // insert LED 1 toggle bit
    toggle[led[2]] |= 4;            // insert LED 2 toggle bit
    toggle[led[3]] |= 8;            // insert LED 3 toggle bit
    toggle[led[4]] |= 16;           // insert LED 4 toggle bit
    toggle[led[5]] |= 32;           // insert LED 5 toggle bit
    toggle[led[6]] |= 64;           // insert LED 6 toggle bit
    toggle[led[7]] |=128;           // insert LED 7 toggle bit
    toggle[0] ^= ~PORTB;            // initialize first toggle element
  }                                 //
  TMR0 = 210;                       // adjusts step size & frame rate
  TMR0IF = 0;                       //
}                                   //
 
Last edited:
I'm impressed!!
Interrupt time 3.4uS!!!! Because the ISR latency is more than halved, The frequency can be a lot faster...

Your low level ASM knowledge is quite something... I must admit that I will "make do" a little too often... ( I should go work for Microsoft... JOKE... ) I do like to see alternative answers...
 
netmgr,

Is the 16F628A socketed on that board?

It is yes - however ive decided to just leave things as they are, its ended up being far more complex than I assumed it would be to simply fade in an LED, plus fitting of an external crystal would involve me removing the circuit from the case and all associated connections - I also was put off by having the LED possibly not have a uniform fade step - so ive just left it with obvious 4 step switch on, it will do
thanks for the suggestions, im sure it will assist others
 
I'm sorry we couldn't help and that there wasn't an "easy fix" for that particular hardware and software.

I'm curious if you were looking for a smooth fade similar to the one shown in the following video?

 
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top