Jump to content

PWM duty cycle change with digital input ?

Recommended Posts

Howdy everybody!


I am trying to come up with some ideas....Now that I have FINALLY figured out how to get a pushbutton input to make an output I am playing with the PWM output. 


I am working on ways to increase the DC to max, then return to minimum when the button is pushed.  When you release the button the DC remains at that level.  A quick button push will toggle the output on and off and the long will adjust DC.   This is for a LED dimmer the PWM signal is heading to the LED driver. 


Any ideas on how to approach this ?  I have it working now to turn the output on and off with a set PWM DC, now I just want to get the DC to change with the input. 


Thanks again!



Link to post
Share on other sites

There are a couple of independent elements in your project, so I'd suggest tackling each in isolation before putting it all together.


One part is the button handling: detecting the difference between a "quick push" and holding the button down. To keep things simple you could toggle one LED each time there's a quick press, and flash another LED while the button is held down. I expect you'll want to make sure that the "quick push" LED isn't toggled by the start of a long hold, or the other way round. That'll probably involve polling the button's state every so often, toggling the LED when the button is pressed and then released quickly. If the button isn't released quickly that's a long press, and you could flash the other LED on and off for as long as it's held down.


The other part is varying the PWM duty cycle. You can work on this without needing the input code: just pretend the button is always pressed, and make the duty cycle go up and down continuously. For this part you'll have to figure out the timing of how quickly the duty cycle changes, and keep track of whether the ramp is on the way up or down.


Once both are working you can bring them together. The main thing to watch out for there is the two parts interfering with each other. When the button is held down the varying duty cycle code needs to happen inbetween the button checks. If the button check shows that the button is still held the duty cycle variation needs to keep going from where it left off before the check.

Link to post
Share on other sites

OK I will try that approach on it. My output is going to a LM3414 or similar LED driver to drive a string of LEDs. I was thinking for simplicity to have the DC increase until max is reached then return to minimum then continue to increase. So the DC will only be really increasing only. The return to minimum may be the challenge there.


Thanks against for the guidance!

Link to post
Share on other sites

Setup one timer to output PWM signal.

Setup second timer to start counting when switch interrupt is detected (you could also use WDT, but it's less flexible than Timer.)

When timer interrupts, check the state of the button.

If not pressed anymore, it means short press, toggle PWM output on/off (only when hold flag is false,) stop the timer, set the hold flag.

If still pressed, increase CCRx, start counting again, set the hold flag to true.

Second timer could also be used for de-bouncing, you could adjust CCR1 after first Timer interrupt.

Disable switch's interrupt when pressed, enable when Timer detects switch release.

Link to post
Share on other sites

I just noticed your post re 3414 PCBs. I have few if you want, I just didn't have time to test them (they are based on another board I made, so they should be fine.)

Yeah I'll take them. I'll put them to use, especially since I can't seem to get to finishing the ones I've started on. Altium is a whole new screwed up world. It has some quirks that leave you head scratching. I wish I could build the PCBs on Inventor. Shoot me an email or pm on the details for them.
Link to post
Share on other sites

BTW, here's the code for what you are trying to do.

1 PWM channel, 1 switch, press & release to toggle on/off, press & hold to dim up & down.

To test it, remove one of the LED's shorting blocks and connect it to P2.2.

#include "msp430g2553.h"
 * main.c
typedef unsigned char u_char;

#define LED_PIN            BIT2 // P2.2 TA1.1
#define SWITCH_PIN        BIT3 // P1.3 LaunchPsd's S2 switch
#define TOGGLE_DELAY    37500 // time after we test for press & release 250ms @ 1MHz & /8
#define FIRST_DELAY        37500 // time after we start dimming (after press & release test) 250ms
#define STEP_DELAY        1500 // dimmer step interval 10ms
u_char hold = 0;            // when 1, it means we are holding the button
u_char direction = 1;        // dimmer direction, 1 is up

int main(void) {

    WDTCTL = WDTPW | WDTHOLD;            // stop watchdog timer

    BCSCTL1 = CALBC1_1MHZ;                // 1MHz clock

    // setup PWM output
    P2DIR |= LED_PIN;
    P2SEL |= LED_PIN;
    P2OUT &= ~LED_PIN;
    // input pin
    P1OUT |= SWITCH_PIN;    // pull up
    P1REN |= SWITCH_PIN;    // enable resistors
    P1IES |= SWITCH_PIN;    // trigger hi -> low
    P1IFG &= ~SWITCH_PIN;    // clear flags
    P1IE |= SWITCH_PIN;        // enable interrupts

    // timer TA0, used to monitor the switch
    TA0CCR0 = 0;                        // full cycle
    TA0CTL = TASSEL_2 + MC_1 + ID_3;    // SMCLK/8, upmode

    // timer TA1, PWM timer
    TA1CCR0 = 255;                        // full cycle
    TA1CCTL1 = OUTMOD_7;                // CCR1 set/reset
    TA1CCR1 = 0;                        // CCR1 default 0
    TA1CTL = TASSEL_2 + MC_1 + ID_3;    // SMCLK/8, upmode

    _bis_SR_register(LPM0_bits + GIE);    // LPM0 with interrupt

    while (1)

// Timer A0 interrupt service routine
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A0(void) {
    if (hold) {
        if (P1IN & SWITCH_PIN) { // switch is up, end of press & hold
            TA0CCTL0 &= ~CCIE; // disable timer
            TA0CCR0 = 0;
            P1IFG = 0; // enable switch interrupt
            P1IE |= SWITCH_PIN;
        } else { // still holding
            TA0CCR0 = STEP_DELAY;
            if (P2DIR & LED_PIN) { // PWNM output is on, we can update PWM
                if (direction) { // change PWM according to direction
                    if (TA1CCR1 == TA1CCR0) { // all the way up, change direction
                        direction = 0;
                } else {
                    if (TA1CCR1 == 0) { // all the way down, change direction
                        direction = 1;
    } else {
        if (P1IN & SWITCH_PIN) { // switch is up, press & hold, toggle output
            P2DIR ^= LED_PIN; // toggle output on/off
            TA0CCTL0 &= ~CCIE; // stop timer
            TA0CCR0 = 0;
            P1IFG = 0; // enable switch interrupt
            P1IE |= SWITCH_PIN;
        } else {
            TA0CCR0 = FIRST_DELAY; // looks like press & hold
            hold = 1;

// Port 1 interrupt service routine
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void) {
    P1IE = 0; // disable switch interrupt
    TA0CCR0 = TOGGLE_DELAY; // set time & enable timer
    TA0CCTL0 = CCIE;
    hold = 0;
Link to post
Share on other sites

I tried it out, with the analog discovery hooked up you can see the DC change and it works great, for some reason the LM3414HV is being somewhat pissy about signals it seems.  I should have some time this weekend to pull the IC out of the launchpad and put it in a breadboard, get it powered up from the same voltage source as the lights through a voltage divider.  Hopefully that will take care of it.  Upon initial startup it works great then after playing with it, the LED will not turn all the way off.  So I think the output pin may not be going below the 0.9V to shut things off.  The code works great!  I got the rest of my back plates and bezel rings cut today, that just took flood coolant with the pressure cranked up high enough to wash all the chips out.  Flood coolant on a knee mill sucks.

Link to post
Share on other sites
  • 2 months later...



Rob, can you think of what would cause the chip output to stay high after it is turned on?  Once I get it on and have dimmed the lights the output stays high and will not turn the light back off unless you power cycle it.  I had tried a couple of things without success.  


I have 10 out of 20 of the fixtures built and installed.  Just need to paint, and assemble the last 10 and put them in.  Of course I ran out of ArticSilver....


Thanks again for the help on it!

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Create New...