• AVR Freaks

Hot!PWM LED Dimming in a specific time pic12f752

Author
PIC_fann
Junior Member
  • Total Posts : 95
  • Reward points : 0
  • Joined: 2018/04/09 08:11:15
  • Location: 0
  • Status: offline
2019/06/25 08:38:45 (permalink)
0

PWM LED Dimming in a specific time pic12f752

Hi everybody,
 
I generated a hardware pwm usibg CPP module on RA2 pin, so it works fine.
Now i am trying to have have a dimming effect with a timing of 1.5 second.
Example : when i press button first time, the duty value is increased from 0% to 100% in 1.5s and if the button is pressed again, the duty cycle has to be from 100% to 0% also in 1.5s.
 
Have you any idea how to do it? i have to use interrupts? 
 
Thank you in advance
#1

15 Replies Related Threads

    NKurzman
    A Guy on the Net
    • Total Posts : 17625
    • Reward points : 0
    • Joined: 2008/01/16 19:33:48
    • Location: 0
    • Status: offline
    Re: PWM LED Dimming in a specific time pic12f752 2019/06/25 09:25:41 (permalink)
    0
    No you do not have to use interrupts.  How many counts is 100%
    One way to do it is:
    you need to calculate the time you need to change it by 1 count.  
    example for 100.  1500 ms / 100 = 1.5 millisec per step.
    Note the change will not appear linear to your eyes.
    Looking linear is a different problem.
    #2
    mbrowning
    Just a Member
    • Total Posts : 1470
    • Reward points : 0
    • Joined: 2005/03/16 14:32:56
    • Location: Melbourne, FL
    • Status: offline
    Re: PWM LED Dimming in a specific time pic12f752 2019/06/25 10:57:08 (permalink)
    0
    1500 ms / 100 = 1.5 millisec per step.

    Well, maybe more like 15ms :)
     
    Set up a timer with the appropriate overflow (15ms or whatever your situation requires.)
    A simple state machine that's called every timer overflow (polled is easiest, but interrupt if you must):
      if state = 1 : if button down state = 2
      if state = 2 : if duty cycle = 100 (or whatever), state = 3 else increment duty cycle
      if state = 3 : if button up state = 4
      if state = 4 : if duty cycle = 0 state = 5 else decrement duty cycle
      if state = 5 : if button up state = 1

    Oh well - there's always next year
    #3
    mpgmike
    Super Member
    • Total Posts : 220
    • Reward points : 0
    • Joined: 2014/01/23 17:27:06
    • Location: NJ
    • Status: online
    Re: PWM LED Dimming in a specific time pic12f752 2019/06/25 12:08:49 (permalink)
    0
    Depending on how you set up your PWM, chances are quite slim your resolution will be 0 >> 100; more likely 0 >> 255 or 0 >> 1023 (or even 0 >> 63...).  I doubt you're 1.5 seconds is critical down to the millisecond, so try to make the math easy and get "close enough".  

    I don't need the world to know my name, but I want to live a life so all my great-grandchildren proudly remember me.
    #4
    NKurzman
    A Guy on the Net
    • Total Posts : 17625
    • Reward points : 0
    • Joined: 2008/01/16 19:33:48
    • Location: 0
    • Status: offline
    Re: PWM LED Dimming in a specific time pic12f752 2019/06/25 12:21:14 (permalink)
    0
    mbrowning
    1500 ms / 100 = 1.5 millisec per step.

    Well, maybe more like 15ms :) 



    And always check your Math.
    #5
    PIC_fann
    Junior Member
    • Total Posts : 95
    • Reward points : 0
    • Joined: 2018/04/09 08:11:15
    • Location: 0
    • Status: offline
    Re: PWM LED Dimming in a specific time pic12f752 2019/07/03 05:50:10 (permalink)
    0
    Hi everyone,
     
    Thank you a lot for your comments, 
    i am sorry for the response delayed, i was sick the last week.
     
    I am trying to configure Timer0 with 15 ms overflow: please see code below
     
    void Init_Timer0(void)
    {
    OPTION_REGbits.T0CS = 0;
    OPTION_REGbits.PSA = 0;
    OPTION_REGbits.PS = 0b111;
    TMR0 = 255;
    }
    My working out is as follows
    Fosc        =4MHz
    INTCLK    =Fosc/4    =1MHz
    Timer0CLK=1MHz/Prescaler    =1MHz/256=3907
     
    Timer0 Tcyc time =1/Timer0CLK    =1/3907 = 255us
    if I load timer0 with 255 count, it will take 65.025ms (255usx255) to interrupt once.
     
    I want a 1.5 second timer so
    1.5s/65.025ms= 23 interrupt counts to indicate 1.5 second has been counted.
     
    am i wrong ?
     
    I have to increment a variable in ISR routine to reach 1.5s ?
     
    Please any help.
     
     
    #6
    mbrowning
    Just a Member
    • Total Posts : 1470
    • Reward points : 0
    • Joined: 2005/03/16 14:32:56
    • Location: Melbourne, FL
    • Status: offline
    Re: PWM LED Dimming in a specific time pic12f752 2019/07/03 06:09:40 (permalink)
    0
    Any reason you aren't using T2 which is specifically designed to generate precise periodic interrupts without software reloading?
     
    You want 15000 clocks for 15ms rollover.
    T2 - prescale by 4, postscale by 15, set PR = 249
    T2 interrupt = (4 * 15 * (249+1))/1e6 = 15.00ms
     
    With T1
    prescale by 64 and reload for count of 234
    64 * 234 / 1e6 = 14.98ms
    To get 234 rollover, reload T0 every interrupt with 256 - 234 - (interrupt overhead)
    Since interrupt overhead can be somewhat random, this is jittery and imprecise (but good enough for LEDs)
     
     

    Oh well - there's always next year
    #7
    PIC_fann
    Junior Member
    • Total Posts : 95
    • Reward points : 0
    • Joined: 2018/04/09 08:11:15
    • Location: 0
    • Status: offline
    Re: PWM LED Dimming in a specific time pic12f752 2019/07/03 06:45:36 (permalink)
    0
    I am using T2 to generate pwm.
    my application is that i want to have a fade in (dimming effect) in 1.5s.
    So what i did :
     
    using timer2 i generated a pwm with 240 Hz--> it works so i can set diffetent value of duty cycle.
    Now i have to set up a timer to have the dimming effect in 1.5s up and 1.5s down (fade in/fade out).
     
    this is my timer 0 initialization update:
     
    void Init_Timer0(void)
    {
    OPTION_REGbits.T0CS = 0;
    OPTION_REGbits.PSA = 0;
    OPTION_REGbits.PS = 0b101;
    TMR0 = 234;
    }
     
    void interrupt ISR()
    {


    if( INTCONbits.T0IE && INTCONbits.T0IF )
    {
    INTCONbits.T0IF = 0; // clear flag
    counter ++;

    }
    }
     
    Now i do not have how to implement the state machine. can you help me please?
    Your remarks/comments are very helpful, thank you a lot
     
     
     
     
    #8
    NorthGuy
    Super Member
    • Total Posts : 5548
    • Reward points : 0
    • Joined: 2014/02/23 14:23:23
    • Location: Northern Canada
    • Status: online
    Re: PWM LED Dimming in a specific time pic12f752 2019/07/03 06:58:03 (permalink)
    0
    I always try to use free-running timers. This provides a stable base.
     
    You create a timer which roughly interrupts every 10 to 20 ms, and then adjust your PWM every interrupt. Let's assume 20 ms for simplicity.
     
    Then you create a range of values - say, from 0 to 65535 (65536 values).
     
    You want 1.5 seconds, so on your way you will have 1500 ms/20 ms = 75 interrupts.
     
    Now you divide your range into 75 intervals - 65536/75 = 874.
     
    Then you create an accumulator. It'll go over your range - from 0 to 65536. You initialize it to 0, and you increment it by 874 every interrupt, so it'll go 874, 1748, 2622 etc. After 75 interrupts it'll be 65550 - roughly what you want.
     
    Now you need to transform your counter value into the PWM value. This is a little bit tricky because you do not want it to be linear. But for simplicity, let's make it linear. If your PWM values are from 0 to 1023 (1024 values) then to get from your counter (65536 values) to PWM you simply divide by 65536/1024 = 64.
     
    Coincidentally, division by 64 is the same as shift right by 6, so division will be easy. Even more coincidentally, PWM registers are built a funny way - you need to shift your value left by 6 before loading. These shifts kill each other, and thus you do not need any division at all - simply load your counter into PWM registers - the high byte goes to CCPR1L, and 2 bits from the low byte go into DC1B. With LED, you probably can ignore DC1B.
     
    Now, what timer is the best to use - the same as the one used for PWM of course. This is because you want to synchronize the manipulation of your PWM registers with your PWM cycle.
     
    #9
    PIC_fann
    Junior Member
    • Total Posts : 95
    • Reward points : 0
    • Joined: 2018/04/09 08:11:15
    • Location: 0
    • Status: offline
    Re: PWM LED Dimming in a specific time pic12f752 2019/07/03 07:57:13 (permalink)
    0
    You mean i can use timer2 for generating pwm and at the same time as a basetime?
     
    All that you have explained is very hepful, but i can't get it:
    when you see create an accumulator: where? in the ISR function or in a separate one?
    Timer 0  is 8 bits timer : 0--<255 so why you use 65535 value?
     
    it is not clear enough for me, so please can you give me an example with all steps described above?
     
    Thank you very mush
    #10
    ric
    Super Member
    • Total Posts : 23269
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: offline
    Re: PWM LED Dimming in a specific time pic12f752 2019/07/03 15:49:57 (permalink)
    +1 (1)
    PIC_fann
    You mean i can use timer2 for generating pwm and at the same time as a basetime?

    Yes.
    You get the added bonus that your changes are synchronised to the PWM because it's using the same timer.
     

    All that you have explained is very hepful, but i can't get it:
    when you see create an accumulator: where? in the ISR function or in a separate one?

    He means a global variable that you update in the ISR.
     

    Timer 0  is 8 bits timer : 0--<255 so why you use 65535 value?

    He's talking about the value in the variable, not the timer count.
     

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #11
    ric
    Super Member
    • Total Posts : 23269
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: offline
    Re: PWM LED Dimming in a specific time pic12f752 2019/07/03 15:50:23 (permalink)
    0
    (remove double post)
    post edited by ric - 2019/07/03 15:54:03

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #12
    NorthGuy
    Super Member
    • Total Posts : 5548
    • Reward points : 0
    • Joined: 2014/02/23 14:23:23
    • Location: Northern Canada
    • Status: online
    Re: PWM LED Dimming in a specific time pic12f752 2019/07/03 16:03:56 (permalink)
    0
    PIC_fann
    Timer 0  is 8 bits timer : 0--<255 so why you use 65535 value?

     
    You only use timer to generate interrupts at fixed intervals. It doesn't matter if it's 8-bit. If you wish can use 1:16 post-scaler on TMR2, so you get an interrupt every 16-th PWM cycle.
     
    As to 65535, it's 2^16 - 1, the maximum which can fit into a 16-bit integer. The longer it is, the more precision you get. If 65536 wouldn't be enough precision, the next value is 16777216 - which fits into 3 bytes. Dealing with powers of 2 is always easier - CPUs are binary creatures :)
     
    NCO works in a similar way. It has a long counter, and it is incremented by a fixed number every tick. As soon as it overflows. an edge is generated. This way you get frequency with great precision, even though it is derived from a relatively slow clock.
     
    ric has already answered the rest.
     
    #13
    PIC_fann
    Junior Member
    • Total Posts : 95
    • Reward points : 0
    • Joined: 2018/04/09 08:11:15
    • Location: 0
    • Status: offline
    Re: PWM LED Dimming in a specific time pic12f752 2019/07/04 00:23:32 (permalink)
    0
    Tkank you all for your support,
     
    i modified my code based on your comments, so i get a dimming which not linear: the pwm increases with a steps that we can see.
     
    please correct my code, i know there are some mistakes:
     
    #include <xc.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdbool.h>
    // CONFIGURATION WORD Settings
    #pragma config FOSC0 = INT // FOSC: Oscillator Selection bit (Internal oscillator mode. I/O function on RA5/CLKIN)
    #pragma config WDTE = OFF // Watchdog Timer Enable bit (Watchdog Timer disabled)
    #pragma config PWRTE = OFF // Power-up Timer Enable bit (Power-up Timer disabled)
    #pragma config MCLRE = OFF // MCLR/VPP Pin Function Select bit (MCLR pin is alternate function)
    #pragma config CP = OFF // Code Protection bit (Program memory code protection is disabled)
    #pragma config BOREN = DIS // Brown-out Reset Enable bits (BOR enabled)
    #pragma config WRT = OFF // Flash Program Memory Self Write Enable bit (Flash self-write protection off)
    #pragma config CLKOUTEN = OFF // Clock Out Enable bit (CLKOUT function disabled. CLKOUT pin acts as I/O)
     
    /*===================================Set up===================================*/
    #define _XTAL_FREQ 4000000
    unsigned int accumulator =0;
    void Init_Timer2(void);
    void PWM_Set_Duty(unsigned int DC);

    void Init_Timer2(void)
    {
    CCP1CONbits.CCP1M2 = 1; // set PWM configuration : PWM mode 11xx
    CCP1CONbits.CCP1M3 = 1; // set PWM configuration : PWM mode 11xx
    TRISAbits.TRISA2=0; //set pin as a digital pin
    ANSELAbits.ANSA2=0; //set pin as an output
    PR2 = 255; //timer2 period will be Oscillator frequency / 4 / prescaler / (PR2+1) = OSC / 100
    T2CONbits.T2CKPS1 = 1; //prescaler 1:16 1x
    T2CONbits.T2OUTPS = 0b1111; //postscalet 1:16
    TMR2ON = 1; //enable timer2
    PIE1bits.TMR2IE = 1; //enable interrupt
    PIR1bits.TMR2IF = 0; //clear flag
    }
     
    void PWM_Set_Duty(unsigned int DC)
    {
    // Check The DC Value To Make Sure it's Within 10-Bit Range
    if(DC<1024)
    {
    CCP1CONbits.DC1B0 = DC & 1;
    CCP1CONbits.DC1B1 = DC & 2;
    CCPR1L = DC >> 2;
    }
    }

    void interrupt ISR()
    {


    if( PIE1bits.TMR2IE && PIR1bits.TMR2IF )
    {

    PIR1bits.TMR2IF = 0; // clear flag
    accumulator+= 175;
    }
    }

    void main(void) {
    OSCCON = 0b00100000; //4MHz HFINTOSC

    Init_Timer2();



    INTCONbits.GIE = 1;
    INTCONbits.PEIE = 1;



    while (1)
    {


    PWM_Set_Duty(accumulator);

    }
    }
    #14
    NKurzman
    A Guy on the Net
    • Total Posts : 17625
    • Reward points : 0
    • Joined: 2008/01/16 19:33:48
    • Location: 0
    • Status: offline
    Re: PWM LED Dimming in a specific time pic12f752 2019/07/04 00:42:22 (permalink)
    0
    If you can see the steps that means your steps are to big. You need to configure your PWM to at least 10 bits, or as many as you can set. You can go as low as 70 Hz but higher is better.
    As far as the non linearity, I already explained that will happen. The problem is not the electronics the problem is your eyes. Human eyes are not linear.

    A simple Square or even better a cube function will appear much better.
    #15
    PStechPaul
    Super Member
    • Total Posts : 2354
    • Reward points : 0
    • Joined: 2006/06/27 16:11:32
    • Location: Cockeysville, MD, USA
    • Status: offline
    Re: PWM LED Dimming in a specific time pic12f752 2019/07/04 12:38:46 (permalink)
    0
    You are incrementing the accumulator by 175 on each timer tick, and the maximum allowed by the PWM_Set_Duty() is 1024, so you will get only 5 or 6 steps. And the accumulator will keep incrementing until it overflows, which will give another set of duty cycles.
     
    As mentioned above, perception of brightness is non-linear, so you should implement some way to achieve a visually smooth dimming. Probably a logarithmic function, which might be done with an array of values, perhaps with linear or cubic spline interpolation between values. You can get more specific guidance by searching the internet.

     
    #16
    Jump to:
    © 2019 APG vNext Commercial Version 4.5