Attiny13A PWM Button Dimmer

Go To Last Post
23 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

 

I'm currently trying to write a code that allows ONE momentary BUTTON to control the Attiny13A PWM, one click ON ( 0 - 255, Full Brightness), one click OFF (255 - 0) has to cycle through PWM when it turns off and on.  On falling edge detection...

If button is held for more than 2 seconds the PWM decreases.

PWM has to be saved when you turn off the control and turns on to the last memory PWM. 

 

I started the setup, i need help.. Once the code is working properly and finished. i will pay whoever helps me.

 

Thanks

 

#define F_CPU 4800000UL			// Define software reference clock 

#define BUTTON	PB2
#define BUTTONpressed !(PINB & (1 << PINB2));
#define LED		PB1			

boolean fadingLED = false;

void pwm_setup (void)
{
	// Set Timer 0 prescaler to clock/n
	// At 9.6 MHz
	// See ATtiny13 datasheet, Table 11.9, page 74

	//TCCR0B |= (0 << CS02) | (0 << CS01) | (1 << CS00); // no prescaler = (~ KHz)
	TCCR0B |= (0 << CS02) | (1 << CS01) | (0 << CS00); // clock /8 = (~ KHz)
	//TCCR0B |= (0 << CS02) | (1 << CS01) | (1 << CS00); // clock /64 = (~ KHz)
	//TCCR0B |= (1 << CS02) | (0 << CS01) | (0 << CS00); // clock /256 = (~ Hz)
	//TCCR0B |= (1 << CS02) | (0 << CS01) | (1 << CS00); // clock /1024 = (~ Hz)

	// Set to 'Fast PWM Mode' mode
	TCCR0A |= ((1 << WGM01) | (1 << WGM00) | (1 << COM0B1));
}

int main (void)
{
	OCR0B = 255; //initial brightness 

	// Enable Pull-Up Resistors on Unused Pins & Button PIN
	PORTB = ((1 << PINB0) | (1 << PINB2) | (1 << PINB3) | (1 << PINB4) | (1 << PINB5));

	uint8_t brightness;

	DDRB |= ( 1 << LED );				// LED is an output (PB1)

	pwm_setup();

	while(1)
	{
		if (BUTTONpressed)
		{

          if (fadingLED == false) // turn on the LED
           {
              for (int PWM = 0; PWM <= 255; PWM++)
                {
                    OCROB = PWM;
                    delay(10);
                }
            }

          else                    // turn off the LED
            {
              for (int PWM = 255; PWM >= 0; PWM--)
                {
                    OCR0B = PWM;
                }
            }
          fadingLED = !fadingLED;
        }
	}

	return(0);
}

 

Last Edited: Thu. May 21, 2020 - 09:38 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Use a state machine (ex:  lamp_off, lamp_fullon, button_held, ramping_up , ramping_down, saving_settings, restoring_settings) 

Then as you press the button it can move through the various states (also move due to a timer driving the ramp states).

 

Draw a diagram of how you want the states to connect.  Button held detection could be a state, or an independent flag used by certain states to take action.

 

Probably worry first about on/off/ramping.

 

Add the storing & setting restoration later, by adding more states.

 

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:
Use a state machine

+10

 

https://www.avrfreaks.net/forum/sequentialmultiple-control-push-button

 

and remember that buttons bounce !

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There is not enough information in the application's specification (the description of what the code should do) to write the code:

 

  Are you saving the duty cycle of the PWM when the Tiny13 is powered off, and then restoring the duty cycle of the PWM when the Tiny13 is powered back on?

 

  What does   delay(10); mean?   10 microseconds, 10 milliseconds, 10 seconds?

 

  If a long press on the button decreases the PWM duty cycle,  how do you restore the PWM when repeated long presses move the duty-cycle to zero?

 

  How long does it take the LED to go from full brightness to complete ly off when there is a short button press?  And vice-versa?   Is this a linear sweep?

 

  Since the Tiny13 has only one timer, how do you use this one timer to create both a PWM signal and a two-second interval?

 

  How much money are you going to pay us?  Is it in a convertible currency like US dollars or Euros?  How are you going to transfer the money to us?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

Draw a diagram of how you want the states to connect.  Button held detection could be a state, or an independent flag used by certain states to take action.

First checking if the LED is on or off...

 - if button is held under 2 seconds, it registers as singleclick.

 - if button is held for more than 2 seconds, it registers as buttonHeld.

 

singleclick is either going to turn off or on the LED depending on the state of the LED.

 

buttonHeld is either going to increment or decrement... Only while button is being pressed.

 - if at full brightness & buttonHeld is detected, PWM decrements to 1. (not completely turned off)

 - if LED is off & buttonHeld is detected, PWM increments to 255. (fully ON)

 

Button is registered on falling edge detection.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Simonetta wrote:

  Are you saving the duty cycle of the PWM when the Tiny13 is powered off, and then restoring the duty cycle of the PWM when the Tiny13 is powered back on? yes, i want to implement it to the code.

 

  What does   delay(10); mean?   10 microseconds, 10 milliseconds, 10 seconds? _delay_ms (milliseconds)

 

  If a long press on the button decreases the PWM duty cycle,  how do you restore the PWM when repeated long presses move the duty-cycle to zero? If decremented, the next long press will be incremented.

 

  How long does it take the LED to go from full brightness to completely off when there is a short button press? can be anywhere from 10 ms to 50ms  And vice-versa? yes Is this a linear sweep? a for loop will execute that

 

  Since the Tiny13 has only one timer, how do you use this one timer to create both a PWM signal and a two-second interval? if button is held for 2000ms it is registered as long press

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

; Device: ATtiny13A, Package: 8-pin-PDIP_SOIC
;
;             _________
;         1 /          |8
;        o--|RESET  VCC|--o
;   button--|PB3    PB2|--o
;        o--|PB4    PB1|--o
;        o--|GND    PB0|--LED
;         4 |__________|5

 


#define setplus PCINT3
#define ledlight PB0

const unsigned long longbuttonpress = 2000;
byte debouncetime = 20;
byte ramptime = 5;

volatile boolean pushplus = false;
volatile boolean longpress = false;

boolean fadestatus = false;
byte fadesize = 0;

void setup() {

    pinMode(setplus, INPUT_PULLUP);

    TCCR0A = 0b10000011;
    TCCR0B = 0b00000001;    // rising edge
    GIMSK = 0b00100000;    // turns on pin change interrupts
    PCMSK = 0b00001000;    // turn on interrupts on pins PB3

    sei();

}

void riseup() {
    pinMode(ledlight, OUTPUT);
    for (byte counter = fadesize; counter < 255; counter++) {
        OCR0A = counter;
        fadesize = counter;
        delay(ramptime);
        fadestatus = true;
    }
}

void falldown() {
    for (byte counter = fadesize; counter > 0; counter--) {
        OCR0A = counter;
        fadesize = counter;
        delay(ramptime);
        fadestatus = false;
    }
        pinMode(ledlight, INPUT);
}

ISR(PCINT0_vect) {
    cli();
    delay(debouncetime);
    if (digitalRead(setplus)) {
        pushplus = true;
    }
    else {
        pushplus = false;
        sei();
    }
}

void loop() {

    while (!pushplus) {
        OCR0A = fadesize;
    }

    unsigned long startpush = millis();

    while (digitalRead(setplus)) {

        if ((millis() - startpush) < longbuttonpress) {
            longpress = false;

        }
        else {
            while (digitalRead(PCINT3)) {
                OCR0A = fadesize;
                delay(ramptime);
                fadesize = fadesize - 1;
            }
            longpress = true;
            fadestatus = false;
        }
        pushplus = false;
    }

    if (!longpress) {
        if (fadestatus == true) {
            falldown();
            pushplus = false;
        }
        else {
            riseup();
            pushplus = false;
        }
    }
}

 

Always remember you're unique, just like everyone else.
www.onecircuit.blogspot.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 - if at full brightness & buttonHeld is detected, PWM decrements to 1. (not completely turned off)

 - if LED is off & buttonHeld is detected, PWM increments to 255. (fully ON)

 

A suggestion to modify slightly:

 

If button held, it will continue in the same direction as it was heading previously...if it reaches zero or max it will stop moving (even while held) for a short dwell (say 2 sec), then reverse direction &  as long as the button is held. 

It can also accelerate so a short (not fast) tap gives a small step, but holding it down picks up speed. 

Upon any reversal the speed will be reset to slow & will accelerate thereafter.  If entering button held while already at zero or max, it will reverse directions & move that way immediately (no dwell)  

The dwell time helps keep you from accidentally zooming though the peak.

 

if the button is "double tapped", the direction will reverse, regardless of the position.   A double tap is faster than two single step tap adjustments (similar to a mouse double click). 

 

A single fast tap turns the unit on/off

 

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
ISR(PCINT0_vect) {
    cli();
    delay(debouncetime);
    if (digitalRead(setplus)) {
        pushplus = true;
    }
    else {
        pushplus = false;
        sei();
    }
}

The above code has a number is red flags.

1. you really don't want to use external interrupts for a pushbutton. Interrupts are for microsecond level response or for waking from sleep.

2. cli()/sei() in an ISR - the AVR hardware does this for you. Adding it into your code is asking for trouble with nested interrupts.

3. the debounce technique of a delay then resample - sort of works.

 

My suggested solution is to have a loop execute at a given rate, let's say 100 times per second. You can do this with a timer or with a delay.

The input/s can be sampled each loop and debounced

the ramping of the pwm value can be paced.

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Agreed - I quick copied this from another project which sleeps and the interrupt button wakes the little fella. I used cli/sei in the ISR to be explicit in this case for the OP. The debounce I normally do outside the ISR using a timed loop..but...well I was hoping that the code posted might put the OP onto the right track. I don't want/need to do all the work, right?

 

 

Always remember you're unique, just like everyone else.
www.onecircuit.blogspot.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ZeusCannon wrote:
I started the setup, i need help.. Once the code is working properly and finished. i will pay whoever helps me.

So is this a school project? The description sounds like one!

Since OP is wishing to pay someone for the program, should this not be moved to market place and have the OP say what they are willing to offer.

Jim

 

 

 

 

 

Last Edited: Fri. May 22, 2020 - 01:31 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I recommend using Atmel START to search for examples on how to differentiate between the time of button presses. Also use START to configure your peripherals as leaving pure register assignment in main without separating them into a function makes the code pretty unreadable. 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 2

The_time wrote:
I recommend using Atmel START

good to know that it does have one fan!

 

laugh

 

use START to configure your peripherals as (sic) leaving pure register assignment in main without separating them into a function makes the code pretty unreadable. 

Award-winner for non-sequitur of the month!

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey all,

 

i want it to work exactly like this push button dimmer.

 

https://www.youtube.com/watch?v=tk7-Jq82inw

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bovineck wrote:

..but...well I was hoping that the code posted might put the OP onto the right track. I don't want/need to do all the work, right?

 

I dont want anyone to do all the work. I would also have to understand it & alter it if needed. I just want some help or someone to work with me on this code. 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ki0bk wrote:

So is this a school project? The description sounds like one!

Started as a school project but i used Arduino. But i dont want to use Arduino because i want to implement by own hardware design. So now its merely for my self interest. 

I've worked with the Attiny13A with a few other projects before. so i'm more familiar with Atmel studio c.

 

I'm offering to pay if someone wants to write all the code or piece by piece. but has to put the TIME to walk me through it. so i understand the code also.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ZeusCannon wrote:
I've worked with the Attiny13A

If you have a working Arduino code, it would be easy to port that to a Tiny85, same physical size as T13a, but arduino compatible, just choose a board with T85 and compile!

Jim

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ki0bk wrote:

If you have a working Arduino code, it would be easy to port that to a Tiny85, same physical size as T13a, but arduino compatible, just choose a board with T85 and compile!

The reason why i dont want to use Arduino is because i want to be able to adjust the PWM frequency. the PWM signal will be outputed to an amplifier and mosfet to at least drive up 5 AMPS.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ZeusCannon wrote:
The reason why i dont want to use Arduino is because i want to be able to adjust the PWM frequency

So don't call analogOutput(), set up your own timer settings, nothing in "Arduino" is special, it's just C or C++, you can do anything you like.

The only drawback and it does not matter in your case, is the code is no longer core independent, but who cares! 

If you need help with that, post your sketch, say how you need it changed and a freak may help you modify it to your needs.

Jim

 

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is an excellent project for you to do...make sure to use LED, not 110VAC!

 

First,get debouncing in place so that you can independently (and reliably) know if the switch has been pressed.

Then upgrade that to tell you whether the switch has been 1)  tapped  2) held>1 second ...you will use these results later

...you can update these evaluations , say 5-10 times a second

 

Take some time to think about the states & draw a diagram connect the different states...you should be able to do that without much hassle.

Start simple  ...do an on off control state machine (2 states). 

Use the above mentioned upgrade to tap dance between the states.

Then, for fun, try TAP for ON, HELD for OFF

Now you are on your way...add other states to the mix & soon you will be ramping up and down as well as turning on/off

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For debouncing can i just add a delay?

 

if (BUTTONpressed)
        {
            _delay_ms(1000); // wait one seond 
            
           //code
        }

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can, but that is a very crude method. Switch bounce is usually in the order of 10's of milliseconds, so if you sample the switch input every 10ms and keep a count - they are many ways of achieving this, but one way is to load a variable with, say a value of 5 if the button is not pressed. If it is pressed, decrement the count if it is not zero.

 

When the variable gets to zero, this means there has been 5 consecutive samples where the switch has been pressed - this means no bounce has occurred in that time. Thus the code is not sitting in a loop waiting for something nor stuck in a delay.

 

If you want to measure how long the button has been pressed, you can keep a count of the pressed time. If your main loop happens every 10ms, then you count time in terms of 10ms ticks. Thus 1 second is 100 tick times.

 

 

Last Edited: Fri. May 22, 2020 - 11:12 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

so if you sample the switch input every 10ms and keep a count - they are many ways of achieving this, but one way is to load a variable with, say a value of 5 if the button is not pressed. If it is pressed, decrement the count if it is not zero.

A variation is to sample (say every 2 ms) & count down to zero if the button is not pressed & count up if it is.  Limit the count values to , say, from 0 to 50.  So you can never go higher or lower.  Then, if the count<10 declare a not tapped & if the count >40 declare tapped.  You can adjust all the numbers to suit your fancy.  You can take this to a higher level, so if you've declared tapped for more than , say 200 samples, call it held.

 

This up/down counting somewhat forms a pendulum---you can only swing back and forth at a certain rate.  When you pass by certain positions on the swing you are low/hi

   

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Fri. May 22, 2020 - 11:51 PM