+ Reply to Thread
Page 2 of 3
First 1 2 3 Last
Results 16 to 30 of 34

Thread: 3 LED PWM Outputs

  1. #16
    Mike, K8LH Excellent Mike, K8LH Excellent Mike, K8LH Excellent Mike, K8LH Excellent Mike, K8LH Excellent Mike, K8LH Excellent Mike, K8LH Excellent
    Join Date
    Jan 2005
    Location
    Michigan, USA
    Posts
    2,521

    Default

    Actually, that method in the previous post is much more complex than what you need. Just rename the 'index' variable to 'duty' and compare that to each Ledx variable in the interrupt routine. Use duty cycle values of 0..3 for your three Ledx variables.

    Mike

    Code:
    ;
            movf    duty,W          ; 0..3
            xorwf   Led0,W          ; same as Led0 duty cycle?
            skpnz                   ; no, skip, else
            bcf     shadow,0        ; turn off Led0 bit in shadow
            movf    duty,W          ; 0..3
            xorwf   Led1,W          ; same as Led1 duty cycle?
            skpnz                   ; no, skip, else
            bcf     shadow,1        ; turn off Led1 bit in shadow
            movf    duty,W          ; 0..3
            xorwf   Led2,W          ; same as Led2 duty cycle?
            skpnz                   ; no, skip, else
            bcf     shadow,2        ; turn off Led2 bit in shadow
            movf    shadow,W        ;
            movwf   PORTB           ;
            incf    duty,F          ; bump duty cycle counter
            btfss   duty,2          ; duty == 4?  yes, skip, else
            goto    isr.exit        ; exit
            clrf    duty            ; reset duty cycle counter
            movlw   b'00000111'     ;
            movwf   shadow          ; reset shadow
    isr.exit
    


  2. #17
    philba Good philba Good philba Good
    Join Date
    Mar 2006
    Location
    Seattle
    Posts
    1,887

    Default

    I think he wanted 256 levels.

    Yes, he doesn't need to sort the led times - I gave that as a way to make it easier to understand. The simplest way to do this is have 4 counts one for each LED count plus the PWM period count. At each timer tick decrement each count. When a count gets to 0, turn off the LED. When the PWM period count gets to zero, reset the counts, turn on the LEDs and restart the process. That way he can generalize it to any PWM period - i.e. to an arbitrary number of intensity levels.

    The technique I gave is a standard multi event delay line that is used in operating systems. In the generalized case, each timer event is a node in a linked list. It's easy to insert a new timer event and allows effectively unlimited events. Definitely overkill but the technique is a good one to know.

  3. #18
    Mike, K8LH Excellent Mike, K8LH Excellent Mike, K8LH Excellent Mike, K8LH Excellent Mike, K8LH Excellent Mike, K8LH Excellent Mike, K8LH Excellent
    Join Date
    Jan 2005
    Location
    Michigan, USA
    Posts
    2,521

    Default

    Here's the OP's first sentence;
    Hi I need to light up three LEDs with three brightness levels.
    Later he says he's using 256 steps as an example... I thought he meant just three distinct brightness levels per LED... Oops!!!
    Last edited by Mike, K8LH; 6th August 2008 at 03:42 AM.

  4. #19
    Suraj143 Newbie
    Join Date
    Jan 2007
    Location
    South Mald Isld
    Posts
    921

    Default

    Hi Mike, K8LH thanks for your excellent codings.The first code you post was really tough to understand.So I gave that.After the next code you post it looks good & I'll try to do that.

    Thanks for your support.

    @ philba

    Thanks for your explanation that I can understand so i'm going to write my own code using that method.

  5. #20
    Suraj143 Newbie
    Join Date
    Jan 2007
    Location
    South Mald Isld
    Posts
    921

    Default

    Hi all now I’m ready to dim a single LED via timer interrupt. I’m gathering some basic information. So please be with me to understand this.

    I can generate an interrupt on every 40uS.That is 25 KHz rate. Is this called the PWM period? Or is this called the Timer frequency?

    Then what is PWM frequency?

  6. #21
    Suraj143 Newbie
    Join Date
    Jan 2007
    Location
    South Mald Isld
    Posts
    921

    Default

    Hi Mike can you tell me in the beginning what values to move to Led0,Led1 & Led2?
    Can I use any values ex:50,128,200 etc...

    Every time you checking the bit 2 of "duty" register I don't know why.

    What Timer frequency do I need to use? Can I use 40uS interrupt?

  7. #22
    bananasiong Excellent bananasiong Excellent bananasiong Excellent bananasiong Excellent bananasiong Excellent
    Join Date
    Mar 2006
    Location
    Malaysia
    Posts
    1,881

    Default

    Quote Originally Posted by Suraj143 View Post
    Hi all now I’m ready to dim a single LED via timer interrupt. I’m gathering some basic information. So please be with me to understand this.

    I can generate an interrupt on every 40uS.That is 25 KHz rate. Is this called the PWM period? Or is this called the Timer frequency?

    Then what is PWM frequency?
    Hi,
    If the interrupt rate is 25 kHz with 256 steps, the PWM frequency is 97.65625 Hz, while the timer interrupt frequency is still 25 kHz.
    I think this frequency is suitable as human won't notice the flicker at 50 Hz and above.
    bananasiong

  8. #23
    Mike, K8LH Excellent Mike, K8LH Excellent Mike, K8LH Excellent Mike, K8LH Excellent Mike, K8LH Excellent Mike, K8LH Excellent Mike, K8LH Excellent
    Join Date
    Jan 2005
    Location
    Michigan, USA
    Posts
    2,521

    Default

    Quote Originally Posted by Suraj143 View Post
    Hi Mike can you tell me in the beginning what values to move to Led0,Led1 & Led2?
    Can I use any values ex:50,128,200 etc...

    Every time you checking the bit 2 of "duty" register I don't know why.

    What Timer frequency do I need to use? Can I use 40uS interrupt?
    Please disregard my code examples. They are not for 256 steps.

    I think Philba should provide an example. His description sounds like one of Gramo's examples where he decrements a master duty cycle counter and all three LED duty cycle variables.

  9. #24
    Suraj143 Newbie
    Join Date
    Jan 2007
    Location
    South Mald Isld
    Posts
    921

    Default

    Quote Originally Posted by Mike, K8LH View Post
    Please disregard my code examples. They are not for 256 steps.
    Thanks Mike.

    @ Bananasiong

    The interrupt rate is 25 kHz with 256 steps, the PWM frequency is 97.65625 Hz

    That I understood.

    The problem is the code goes to the ISR routine on every 40uS (25 KHz).

    So How can I generate 256 steps.Then it must go 256 times to the ISR.

    That is 40uS X 256

    This is the place I got stucked.

  10. #25
    philba Good philba Good philba Good
    Join Date
    Mar 2006
    Location
    Seattle
    Posts
    1,887

    Default

    Ok, I'll do a pseudoC example

    Code:
    uchar r,g,b,T;
    uchar rVal, gVal, bVal;
    init() {
        r = rVal;
        g = gVal;
        b = bVal;
        set up timer so PWMTICK gives you the right interval
        timer = PWMTICK;
        T = MAXPWMCOUNT;
        LED_R = LED_B = LED_G = 1;
        turn on interrupts (timer and general)
    }
    
    InterruptServiceRoutine(){
        timer = PWMTICK; 
        if(--r == 0) LED_R = 0;     
        if(--g == 0) LED_G = 0;
        if(--b == 0) LED_B = 0;
        if(--T == 0) {
            // reset PWM period and rgb counts
            T = MAXPWMCOUNT;
            r = rVal;
            g = gVal;
            b = bVal;
            LED_R = LED_G = LED_B = 1
        }
        clear timer int flag
    }
    
    main() {
    
        init PIC HW
        set rVal, gVal, bVal
    
        init()
    
        while(1);  // or what ever you want here like change rVal, bVal, gVal
    }
    
    For 255 levels, I'd set MAXPWMCOUNT to 255. Also be careful that your ISR takes less time than the timer interrupt period. Definition of the I/O pins for the LEDs, PWMTICK, timer initialization left as an exercise for the reader. Generalizing to greater than 8 bit values is up to you.

    I probably missed something but that's the basic idea. edit: bug when led value is 0.
    Last edited by philba; 6th August 2008 at 04:53 AM.

  11. #26
    futz Excellent futz Excellent futz Excellent futz Excellent futz Excellent futz Excellent futz Excellent
    Join Date
    Sep 2007
    Location
    Vancouver, B.C.
    Posts
    1,980

    Default

    Hey Suraj. Just for fun I was tinkering with this thing and came up with this in C. It's very simple. Uses this algorithm:
    Quote Originally Posted by Sceadwian
    Create three variables (or use three registers) and set them to the duty cycle you want.

    Also create and clear a master PWM variable.
    Set the timer up to simply free run and enable the timer overflow interrupt. If your timer is running at clock speed you'll get an interrupt routine every 256 clock cycles on an 8bit timer with no prescaler.
    When the ISR triggers compare the master PWM, if it's zero turn on all of your PWM I/O lines and immediatly return from the ISR after increasing the master PWM variable 1. If it's not 0 compare it with each in turn of the LED registers. If it's equal, turn that particular I/O line off and go to the next LED compare line, the last line should increase the master PWM variable..
    That's about it. You just have to make sure that worst case scenario your ISR routine executes in less than 256 cycles.
    Since 4MHz is too slow to do that without flickering, I preload TMR0 to 0xd0 every time it interrupts, to make it interrupt often enough to prevent flicker.

    The ISR (void interrupt(void) ) does all the work. The FOR loops inside the WHILE loop just change the PWM duty cycles so it does something vaguely interesting instead of just sitting there. Here's the source and hex in a zip file: suraj_pwm.zip

    Here's the source:
    Code:
    #include <system.h>
    #pragma CLOCK_FREQ 4000000
    #pragma DATA _CONFIG, _INTOSC_OSC_NOCLKOUT & _WDT_OFF & _LVP_OFF & _MCLRE_ON
    
    unsigned char led1,led2,led3,pwm,out;
    
    void main(void)
    {
    	unsigned char x,y,z;
    	trisb=0;
    	portb=0;
    	led1=led2=led3=pwm=0;
    	option_reg=0b10001000;
    	intcon=0b10100000;
    	while(1){
    		y=255;
    		for(x=0;x<255;x++){
    			led1=x;
    			led2=y--;
    			led3=x;
    			delay_ms(3);
    		}
    		y=0;
    		for(x=255;x>0;x--){
    			led1=x;
    			led2=y++;
    			led3=x;
    			delay_ms(3);
    		}
    	}
    }	
    
    void interrupt(void)
    {
    	tmr0=0xd0;
    	intcon.T0IF=0;
    	pwm=pwm+1;
    	if(pwm==0)
    		out=0b00000111;
    	if(pwm==led1)
    		out.0=0;
    	if(pwm==led2)
    		out.1=0;
    	if(pwm==led3)
    		out.2=0;
    	portb=out;
    }
    
    Last edited by futz; 6th August 2008 at 10:14 PM.
    =========================
    Futz's Microcontrollers & Robotics
    =========================

  12. #27
    Mike, K8LH Excellent Mike, K8LH Excellent Mike, K8LH Excellent Mike, K8LH Excellent Mike, K8LH Excellent Mike, K8LH Excellent Mike, K8LH Excellent
    Join Date
    Jan 2005
    Location
    Michigan, USA
    Posts
    2,521

    Default

    Philba,

    That code is very much like Gramo's old BASIC RGB example. Why decrement four counters and waste precious cycles resetting r, g, and b at the end-of-period? You're also not properley handling duty cycle values of 0.

    Here's my revised example for 256 steps (40 usec interrupts) with just a single operation at end-of-period.

    Mike

    Code:
    ;
    ;  uchar duty = 0;              // duty cycle counter, 0..255
    ;  uchar Led0,Led1,Led2 = 0;    // R/G/B Led duty cycle, 0..255
    ;  uchar shadow = 0;            // gpio shadow register
    ;
    ;  void interrupt()             // 40 usec timer 2 interrupts
    ;  { pir1.TMR2IF = 0;           // clear timer 2 interrupt flag
    ;    if(Led0 = duty)            //
    ;      shadow.0 = 0;            // turn off Led0 bit in shadow
    ;    if(Led1 = duty)            //
    ;      shadow.1 = 0;            // turn off Led1 bit in shadow
    ;    if(Led2 = duty)            //
    ;      shadow.2 = 0;            // turn off Led2 bit in shadow
    ;    gpio = shadow;             // update gpio from shadow
    ;    duty++;                    // bump duty cycle counter
    ;    if(duty == 0)              // if end of period
    ;      shadow = 0b00000111;     // reset shadow
    ;  }
    ;
            movf    duty,W          ; 0..255
            xorwf   Led0,W          ; same as Led0 duty cycle?
            skpnz                   ; no, skip, else
            bcf     shadow,0        ; turn off Led0 bit in shadow
            movf    duty,W          ; 0..255
            xorwf   Led1,W          ; same as Led1 duty cycle?
            skpnz                   ; no, skip, else
            bcf     shadow,1        ; turn off Led1 bit in shadow
            movf    duty,W          ; 0..255
            xorwf   Led2,W          ; same as Led2 duty cycle?
            skpnz                   ; no, skip, else
            bcf     shadow,2        ; turn off Led2 bit in shadow
            movf    shadow,W        ;
            movwf   PORTB           ; update port from shadow
            movlw   b'00000111'     ; 
            incf    duty,F          ; end of period?
            skpnz                   ; no, branch, else
            movwf   shadow          ; reset shadow
    isr.exit
    
    Last edited by Mike, K8LH; 6th August 2008 at 05:20 AM.

  13. #28
    bananasiong Excellent bananasiong Excellent bananasiong Excellent bananasiong Excellent bananasiong Excellent
    Join Date
    Mar 2006
    Location
    Malaysia
    Posts
    1,881

    Default

    Quote Originally Posted by Suraj143 View Post

    @ Bananasiong

    The interrupt rate is 25 kHz with 256 steps, the PWM frequency is 97.65625 Hz

    That I understood.

    The problem is the code goes to the ISR routine on every 40uS (25 KHz).

    So How can I generate 256 steps.Then it must go 256 times to the ISR.

    That is 40uS X 256

    This is the place I got stucked.
    Why did you get stucked? 40 µs x 256 is 0.01024 second, which is 97.65625, as you understood.
    bananasiong

  14. #29
    Suraj143 Newbie
    Join Date
    Jan 2007
    Location
    South Mald Isld
    Posts
    921

    Default

    Excellent thanks for the new codes.Now I got an idea & going to write them with ASM never used C before.

  15. #30
    Suraj143 Newbie
    Join Date
    Jan 2007
    Location
    South Mald Isld
    Posts
    921

    Default

    Hi Mike your new ASM code is very familiar to my knowledge.Thanks for that.

    I just calculate some technical informations from your code.

    Can you tell me whether they are correct?

    Timer frequency = 25Khz = 40uS
    PWM period = 0.01024 S = 97.65625 Hz
    Duty cycle range for LED variables = 0-255

+ Reply to Thread
Page 2 of 3
First 1 2 3 Last

Similar Threads

  1. PIC PWM outputs?
    By Andy1845c in forum Micro Controllers
    Replies: 34
    Latest: 14th March 2010, 05:51 PM
  2. Using 2 PWM outputs
    By raj_ps in forum Micro Controllers
    Replies: 1
    Latest: 12th February 2008, 02:16 AM
  3. 56 outputs
    By SterlingY in forum General Electronics Chat
    Replies: 27
    Latest: 19th March 2007, 06:31 AM
  4. RCA Outputs
    By rollinstonedj in forum General Electronics Chat
    Replies: 11
    Latest: 14th July 2004, 02:39 PM
  5. Outputs
    By cbesenzi@norgren.com in forum General Electronics Chat
    Replies: 2
    Latest: 18th August 2003, 10:31 PM

Tags for this Thread