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.

netmgr

Member
Ive built a circuit with the intention of fading in several leds, however Im now realising that hardware PWM is only available on 1 port, which is no good for me.
Is there a direct pin replacement for the 16f628a that has 8 pwm ports?
My other thought is to do software pwm, however everything I found on the net for this chip relates to hardware pwm and not software
Essentially I want to fade in each led at a time separately, which I believe makes things easier?
any code anyone could share?
 
I think to use 8 hardware PWM's you would need 8 timers... Not many micros do this...

You are faced with software..
If its only LED's..... Set a timer interrupt and compare a settable value for each led and monitor the LED's within the interrupt, switching each off in turn..
 
Gosh, I'm not sure if there's an 18-pin PIC in a '628A compatible pinout with 8 hardware PWM channels but there are lots of different methods for doing "software PWM" for LEDs.

I created a thread long ago for a 32 level (and 64 level) Charlieplexed display of twenty LEDs using five pins of a PIC12F683 but it's probably not a good example of "software PWM" because of the added complexity for Charlieplexing.

Let me see if I can dig up some other "soft PWM" examples for you... You should mention which language you're using (assembler, BASIC, C, etc.), clock speed, how many LEDs, how many PWM levels per LED and the refresh rate you're trying to achieve.

Good luck on your project... Cheerful regards, Mike

 
Last edited:
If you go with the 18F series, I believe the 18F1330 has 6 PWM channels. You could always use two of these for a total of 12 PWM outputs. Link them together using the on-chip serial UART so they can communicate between each other and work together as one.
 
You could do this with the hardware by using RB3 to drive an npn transistor to drive the cathodes of all the LEDs and port A to drive the anodes. Using the 4MHz internal clock would enable you to have 8 bit PWM at 10KHz. By setting the timer 2 postscaller to 10 you will get a timer 2 interrupt every millisecond. Use this interrupt to stop the PWM, change it to the next value, scroll port A and restart the PWM. This would mean your LEDs are being switched at 125Hz and will be flicker free.

Possibly a little complex for a beginner but if you try, we're here to help.

Mike.
 
Can you fit an external 20Mhz crystal?

This way you will achieve a 64 level Software PWM on 8 individual channels using a 1mS time base ( 1Khz )..

Circuit is already built, however it may be possible, ill need to have a look at how its connected up to see if I have space
 
Circuit is already built, however it may be possible, ill need to have a look at how its connected up to see if I have space

UPDATE: yes looks like I can add a crystal and 2 caps

As I say, its only necessary to fade in to full brightness 1 channel at a time
basically all channels off, then fade in each one at a time to full brightness, then do the next fade in etc

Do i need to change the chip> apparently i need the 20mhz version - I have the A version?
 
Last edited:
Some additional info' might help. [] current clock speed?, [] how many LEDs?, [] how many PWM steps do you need? And... what language?
 
Last edited:
Well as I was just looking for some examples to get me going, but I could narrow it down:
ASM code
there are 8 leds but only 1 ever needs PWM at a time
ideally go from off to on in as many steps as possible over about 4-5 seconds per led
ill go with a 20mhz xtal
 
You could do this with the hardware by using RB3 to drive an npn transistor to drive the cathodes of all the LEDs and port A to drive the anodes. Using the 4MHz internal clock would enable you to have 8 bit PWM at 10KHz. By setting the timer 2 postscaller to 10 you will get a timer 2 interrupt every millisecond. Use this interrupt to stop the PWM, change it to the next value, scroll port A and restart the PWM. This would mean your LEDs are being switched at 125Hz and will be flicker free.

Possibly a little complex for a beginner but if you try, we're here to help.
I used this method in 2005 to control the brightness of an 8-digit 7-segment display on a 16F648A (4-MHz INTOSC). While I used the same PWM brightness setting for the entire display, I could have had different PWM brightness settings for individual digits. Keep in mind that RA4 is open drain and RA5 is MCLR...
 
Last edited:
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.....
 
You shouldn't need a 20-MHz crystal unless there's something else goin' on besides controlling the LEDs...
Not really, just the leds - its part of an led lamp ive made where i want each of the 8 segments to start up 1 by 1

Im using this kit:
http://picprojects.org.uk/projects/480/pro483/#Firmware

whilst it has a dimming ability its either dim, bright or very bright, I cant figure out how to get more steps on this arrangement
I think this is where the magic happens:

Code:
; PWM Function


_pwm          movfw         vc0           ; AND all 5 bits of vertical counter
              andwf         vc1,W
              andwf         vc2,W
              andwf         vc3,W
              andwf         vc4,W
              iorwf         copyPORTB,F   ; then OR bits with copyPORTB working variable
              movfw         copyPORTB     ; load in W
              movwf         PORTB         ; and write to physical PORTB
                                          ; when 5 bits in vertical count reach 11111
                                          ; corresponding Port bit is turned on and then
                                          ; remains on until counter is reset

    movwf    PORTA
             
; ---------------------------------------
; 2^5 bit x 8 vertical counter
; generates the pwm for the 8 channel LED output
; More info on how this works can be found here
;  http://everything2.com/e2node/vertical counter
;  http://www.dattalo.com/technical/software/pic/vertcnt.html

_vc32         movf          vc3,W
              andwf         vc2,W
              andwf         vc1,W
              andwf         vc0,W
              xorwf         vc4,F

              movf          vc2,W
              andwf         vc1,W
              andwf         vc0,W
              xorwf         vc3,F

              movf          vc1,W
              andwf         vc0,W
              xorwf         vc2,F

              movf          vc0,W
              xorwf         vc1,F

              comf          vc0,F

; ---------------------------------------

              decfsz        pwm,F         ; decrement PWM counter
              return                      ; return if count != 0

              ; reset and reload PWM output / counter
              movlw         .31           ; reload PWM counter
              movwf         pwm
             
              clrf          copyPORTB     ; reset output port working variable
              ; vertical counter is 8 channels by 5 bits
              ; rvc1 rvc0  vc4-0  PWM ratio
              ;    0 0     00000  0/31   off
              ;    0 1     00001  1/31   dim
              ;    1 0     00100  8/31   bright
              ;    1 1     11111  31/31  very bright
              ;
              movfw         loReload      ; reload the  vertical counter
              movwf         vc0          
              movfw         hiReload
              movwf         vc3
              andwf         loReload,W
              movwf         vc1
              movwf         vc2
              movwf         vc4
              return
 
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top