Need advice on how to read register on Attiny 10

Hey guys and gals.
I have been programming Arduino boards for a while, but I wanted to try to learn how to actually do the more advanced programming by reading and writing to registers and stuff. I decided trying this out on an Attiny 10 would be fun since it is very minimalist, and would be good for really small projects. As a first bit of code to test, I want the Attiny to read a button and if the button is pressed change the state of an LED. I can get the led to turn off or on depending on what I set a variable to, but I cant get it to read the state of the pin which the button is attached to, and then use that to change the LED. My circuit is a LED on PB0, and then a switch connected to PB2 with a pull down resistor attached externally. I have commented the code the best I can.

Here is a screenshot of the Attiny 10 datasheet, showing the register to read pin states

#include <avr/io.h>
#include <stdint.h>

int buttonState = 0;

int main(void) {
  
  DDRB |= (1 << PB0); //write to DDRB to set pb0 as output at start

  for(;;){ //used to make the program loop forever

  //int buttonState = 1; //used to test. If this is uncommented, the led turns on
    int buttonState = PINB & 0b0100; //trying to read the value from bit 2 of the PORT B register, doesnt work
  //int buttonState = PINB & 0x4; //same as above but in hex, doesnt work
  //int buttonState = PINB & 4; //same as above but in decimal, doesnt work
    
    if (buttonState == 1){ //if the button is HIGH, turn led on
      PORTB &= ~(1 << PB3); //write to PORTB register to set pbo to LOW
    }
    else { //else, turn off
      PORTB |= (1 << PB0); //write to PORTB register to set pb0 to HIGH
    }  
  }
}

A schematic would be most helpful (even a hand drawn one) so we can see exactly how your switch is wired up.

Or.... take a look at which pins you are turning on/off. In one case you use PB3, in the other you use PB0. You stated your LED was connected to PB0.

    if (buttonState == 1){ //if the button is HIGH, turn led on

But it's never going to be 1, is it. It will be 0 or 4. Try using it as a boolean:

    if (buttonState){ //if the button is HIGH, turn led on

Any non-zero value is 'true' and zero is 'false'.

You should not use the 'int' type when working with byte registers. Use 'byte' or 'uint8_t'. If you only need 0 or 1 value (true/false, HIGH/LOW) then 'boolean' is a good choice.

Thanks both of you :). @johnwasser That is interesting that it will be 0 or 4, I guess I though it would only ever be 0 or 1. I don’t quite get why it would be 4, maybe since I am reading from register 0b0100, which is 4 in binary? Thanks for the tip on boolean, I did think that, but using “boolean” didn’t work so I used “int”. I have found out though that “bool” does work, so that’s what i’ll be using.

@blh64 Good spot on the pins. I must of made a mistake when I was re arranging the code, I have changed it to be correct on PB0 now, thanks.

Now that that super simple program is working time for more complex stuff!

(working code if anyone wants to see it)

#include <avr/io.h>
#include <stdint.h>

int main(void) {
  
  DDRB |= (1 << PB0); //write to DDRB to set pb0 as output at start

  for(;;){ //used to make the program loop forever
  
  //bool buttonState = PINB & 0b0100; //reads the value from bit 2 of the PORT B register
  bool buttonState = PINB & 4; //same as above but in decimal
    
    if (buttonState){ //if the button is HIGH, turn led on
      PORTB &= ~(1 << PB0); //write to PORTB register to set pbo to LOW
    }
    else { //else, turn off
      PORTB |= (1 << PB0); //write to PORTB register to set pb0 to HIGH
    }  
  }
}

EmanEric:
That is interesting that it will be 0 or 4, I guess I though it would only ever be 0 or 1. I don’t quite get why it would be 4, maybe since I am reading from register 0b0100, which is 4 in binary?

buttonState = PINB & 4;

You are reading an 8-bit register and masking out the bits that are not of interest. This particular register is the PIN (Port INput?) register of Port B. The port also has DDR (Data Direction Register) and PORT (Output) registers. The masking is done using the bitwise AND operator ‘&’. The bitwise AND will force to zero any bits that are zero in the mask and keep the value of any bits that ate one in the mask.

Your mask is 4 == 0x04 == 0b00000100 == (1<<PB2). If PINB contains 0bxxxxx1xx the result of the AND will be 0b00000100 (4). If PINB contains 0bxxxxx0xx the result of the AND will be 0b00000000 (0). The ‘x’ indicates a bit we don’t care about.

There is a defined constant for each bit of each port. This allow you to be more clear about which pin you are trying to manipulate. You use one for PB0 but not for PB2. In the future you should write:

buttonState = PINB & (1<<PB2);

If you are reading more than one pin at a time (using a mask with more than one bit set), the result will be 0 only if all of those pins are LOW.

Wow, thanks for that awesome explanation! I understand most of that now, but I think I will be doing some reading of this article to help learn more about this whole new word of programming i've never seen much before. Many thanks