Attiny10 button input wired with external pull-down

Hello folks!

I have desiged a custom PCB where an Attiny10 controls 2 LED with a single button. It works great, thanks to the help of some fantastic forum members that had a crack at my novice code!

The Circuit and Code is designed for a button that pulls down to ground. On the breadboard the momentary button successfully toggles through the different LED on/off options with long presses and/or double- and triple-clicks. I used the internal pull-up resistor to get the input pin to HIGH when the button is not connected to prevent a floating pin.

It was planned to wire the PCB with the LEDs attached into an old Tamagotchi (Yes, those little eggs still exist and i might have a collection problem :rofl:) to serve as a multicolor LCD-Display backlight, so you can play with the digital egg in the evening or low-light conditions.

I wanted to use one of the more seldom used buttons on the Tamagotchi to double as a switch which is detected by the attiny10, thus controlling the LED Backlight.

But when i wired it in, it did not work as intended: Both LED's came on upon inserting the battery for example. Through probing around, i found out that one side of the Tamagotchis Button is connected to VCC/3.3V. The other side of the button does not connect directly to ground as far as i can probe.

So i assume the Tamagotchis Button and the IC listening to it is wired to be HIGH when pressed and LOW when not, the opposite of my inital design. My Code would need to reflect this.

I revised my code and testing breadboard setup to work with the button connecting the input pin to VCC/3.3V when pressed. Of course i added a pull-down resistor to get the floating input pin to LOW when the button is not pressed.

I (most likely wrongly) wired it and it does not work, still kinda behaving like the input is floating; randomly turning on/off the LED, not really registering the button presses and so on.

I hope some of you more talented folks can spot an error in my approach!

Here is my code:

/*
Test setup:
Button Side 1 --> 4.7k Resistor --> PB1 --> Ground
Button Side 2 --> VCC (3,3V or 5V)

LED (+) Color 1 --> 1K resistor --> Pin 1 (PB0)
LED (+) Color 2 --> 1K resistor --> Pin 1 (PB2)
LED (-) --> (GND)
*/



#define F_CPU 1000000UL //defines CPU frequency, here 1MHZ
#define LED_toggle_0 PINB |= (1 << PINB0) // toggle PB0 (datasheet: 11.2.2)
#define LED_toggle_1 PINB |= (1 << PINB2); //toggle PB2

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>



void setup() {
  DDRB |= (1 << PB2) | (1 << PB0);    // PB2 and PB0 as output
  DDRB &= ~(1 << PB1);                    // PB1 as input
  //PUEB |= (1 << PUEB1);               // activate internal pull-up -> disabled for external pull-down
  TCCR0B |= (1 << CS02) | (1 << CS00) // prescaler clk/1024 and turns on timer0
            | (1 << ICNC0);                     // input capture noise canceler
}

void loop() {
  bool toggledB1 = 0; // flag to avoid more than one toggle
  bool toggledB0 = 0; // flag to avoid more than one toggle
  bool armclick = 0;
  static uint8_t multiclick = 0;
  while ((PINB & (1 << PINB1))) { // stay in while as long as PINB1 remains HIGH -> Button pressed
    if (TCNT0 - ICR0 > 25 && !armclick) { // 25ms have passed
      multiclick++;
      armclick = 1; // to avoid having more multiclick increments after one click
    }
    if ((TCNT0 - ICR0 > 1000) && (!toggledB1) && (!toggledB0)) { // one second has passed
      PINB |= (1 << PINB2); // toggle PB2
      PINB |= (1 << PINB0); // toggle PB0
      toggledB0 = 1; // so the led will not toggle again
      toggledB1 = 1; // so the led will not toggle again
    }
  }
  if (TCNT0 - ICR0 > 500) {
    switch (multiclick){
    case 1: // it was a single long click
      multiclick = 0; 
      break;
    case 2: // doubleclick
      PINB |= (1 << PINB0); // toggle PB0
      multiclick = 0;
      break;
    case 3: // tripleclick
      PINB |= (1 << PINB2); // toggle PB2
      multiclick = 0;
      break;
    default:
      multiclick = 0; // undefined # of clicks
      break;
    }
  }
}

:gear: Here is a picture of my breadboard setup controlling two LEDs of a RGB one with an attiny10:

:paintbrush: And here my quick doodle of the schematics as far is i understood:

I appreaciate you all reading through this wall of text and thank you for your help in advance!

All the Best and have a nice day/night/whatever :grin:

That's a whole lot of capitalized words, bits shifting and or'ing..
Makes me dizzy, cute little Attiny10 couldn't be programmed more readable??

Attiny button press count..

/*
  https://forum.arduino.cc/t/attiny10-button-input-wired-with-external-pull-down/1264601
  Test setup:
  Button Side 1 --> 4.7k Resistor --> PB1 --> Ground
  Button Side 2 --> VCC (3,3V or 5V)

  LED (+) Color 1 --> 1K resistor --> Pin 1 (PB0)
  LED (+) Color 2 --> 1K resistor --> Pin 1 (PB2)
  LED (-) --> (GND)
*/


#define LED1_PIN PB0
#define LED2_PIN PB2
#define BTN_PIN  PB1


unsigned long lastCheck;
//needs a bit more time than 500 ms
unsigned long intervalCheck = 1000;// 1000 ms to press buttons..
unsigned long lastPress;
unsigned long intervalDebounce = 20;
byte lastState = 0;
bool timerStarted = false;

void setup() {
  pinMode(LED1_PIN, OUTPUT);
  pinMode(LED2_PIN, OUTPUT);
  pinMode(BTN_PIN, INPUT);
}

void loop() {

  unsigned long now = millis();
  static uint8_t multiclick = 0;

  if (now - lastPress >= intervalDebounce) {
    byte state = digitalRead(BTN_PIN);
    if (state != lastState) {
      lastPress = now;
      lastState = state;
      //start timer to count press..
      if (!timerStarted) {
        timerStarted = true;
        lastCheck = now;
      }
      if (state == HIGH) multiclick++;
    }
  }


  if (timerStarted) {
    if (now - lastCheck >= intervalCheck) {
      lastCheck = now;
      switch (multiclick) {
        case 1: // it was a single long click
          digitalWrite(LED1_PIN, !digitalRead(LED1_PIN));
          digitalWrite(LED2_PIN, !digitalRead(LED2_PIN));
          multiclick = 0;
          break;
        case 2: // doubleclick
          digitalWrite(LED1_PIN, !digitalRead(LED1_PIN)); // toggle PB0
          multiclick = 0;
          break;
        case 3: // tripleclick
          digitalWrite(LED2_PIN, !digitalRead(LED2_PIN)); // toggle PB2
          multiclick = 0;
          break;
        default:
          multiclick = 0; // undefined # of clicks
          break;
      }
      //reset for next shot
      timerStarted = false;
      multiclick = 0;
    }
  }
}

seems to work..
but maybe the 10 can't handle it??
lol, that thing is soOo small.. :slight_smile:

good luck.. ~q

1 Like

You may have wired the button incorrectly.

What you may not realise is that some of the pins of this type of 4 pin button are permanently connected to other pins, even when the button is not pressed. Only when the button is pressed are all 4 pins connected.

But which pins are permanently connected? It's not easy to tell by looking at the button. You may have wired it so that pressing the button makes no difference.

The easy way to avoid that problem is to place the button across the central channel of the breadboard, and use only 2 diagonally opposite pins. Leave the other 2 pins unconnected.

1 Like

The ATTinyCore sadly doesn’t support the Attiny10, so I’m using the Attiny10Core by technoblogy.

It’s a rather minimal Arduino core for programming the Attiny10/9/5/4. It doesn't come with Arduino functions like pinMode(), millis(), etc. You have to use alternatives to those core functions, like those listed here.

And yes, all this bit shifting made me dizzy as well at the beginning :laughing:

I checked again with a multimeter to confirm and sadly this is not the issue :smiling_face_with_tear:

The two top row pins are connected when the button is not pressed, as are the bottom two! When pressed, those two rows are connected.

Gonna make extra sure all the other connections are solid as well.

Hey, that’s a pretty nifty tip! Thanks for that, gonna add that to my toolbox :+1:

Any other ideas? :melting_face:

Thank you all for your input so far! :smile:

Yeah, sorry for all the bit shifting, that's on me and you need even one more.

You forgot that when you want to use a rising edge instead of a falling edge, you have to tell the input capture unit to use the other edge.

From datasheet

So for you that means

change this

TCCR0B |= (1 << CS02) | (1 << CS00) // prescaler clk/1024 and turns on timer0
       | (1 << ICNC0);         // input capture noise canceler

into this

TCCR0B |= (1 << CS02) | (1 << CS00) // prescaler clk/1024 and turns on timer0
       | (1 << ICNC0)            // input capture noise canceler
       | (1 << ICES0);           // Select input capture on rising edge
1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.