Writing to Pinx register

Is there any way to write to Pinx register to set values of bits?

As per Attiny13 datasheet Pinx register is R/W but it seems I can only read from that register but not write.

I`m checking PINB register for value then executing this or that function. But then need to clear PINB register for logic to work.


Writing PINx toggles all bits written with a one.
So if you write the content of PINx to PINx it should clear the data register.

Three I/O memory address locations are allocated for each port, one each for the Data Register (Portx),
Data Direction Register (DDRx), and the Port Input Pins (PINx). The port input pins I/O location is readonly,
while the data register and the data direction register are read/write. However, writing ‘1’ to a bit in
the PINx register will result in a toggle in the corresponding bit in the data register.

In attiny13 datasheet pinx register bits are read and write. And you are right toggling the bit in pinx register will clear the bit. But it will clear the bit in portx register too. Thats as per atmel studio in simulation mode. But as i see there its not clearing pinx bit.

Assembly file generated at toggling the bit line is copying 0x00 to menory location 0x16 which is pinx register so it should clear whole register but it doesnt.

Logic of the code depends on checking pinx register bits and if some bit is set then do something if another bit then another thing so on.

Will post the code later.


#define F_CPU 8000000UL
#include <avr/eeprom.h>
#include <avr/io.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <SoftwareServo.h>
#include <util/delay.h>

#define motor_signal 0

#define motor_switch 1

#define limiter_button 2

#define open_signal 3 // to rotate motor forward

#define close_signal 4 // to rotate motor backwards

#define saved_position 1 //eeprom address to save

#define open_position 60

#define closed_position 150

#define forward 1

#define reverse 0

#define PINB_forward 8

#define PINB_reverse 16

void turn_motor(bool _direction);

void sleep(void);

SoftwareServo myservo;

volatile byte interrupted_signal = 0;

void setup()


  DDRB |= _BV(DDB0) | _BV(DDB1); // pins 0 and 1 output

  PORTB |= _BV(DDB2) | _BV(DDB3) | _BV(DDB4); // pins 3,4,5 input pullup enable

  ADCSRA &= ~(_BV(ADEN)); // switch off ADC



void loop()

  if (interrupted_signal & PINB_forward) turn_motor(forward); // read PINB register to variable

  else if (interrupted_signal & PINB_reverse) turn_motor(reverse);

  else sleep();

ISR(PCINT0_vect) {

  interrupted_signal = PINB;


//sleep mode
void sleep(void) {


  sleep_enable();                         // Sets the Sleep Enable bit in the MCUCR Register (SE BIT)


  sei();                                  // Enable interrupts

  sleep_cpu();                            // sleep

  cli();                                  // Disable interrupts

  sleep_disable();                        // Clear SE bit

  sei();                                  // Enable interrupts
} // sleep
void turn_motor(bool _direction) {

  DDRB |= _BV(DDB0) | _BV(DDB1); // pin 0 and 1 output
  PORTB |= _BV(motor_switch); // turn motor switch HIGH


  unsigned long current_time = 0;

  unsigned char i = 0;

  current_time = millis();

  i = eeprom_read_byte((unsigned char *)saved_position);

  if (i > closed_position) i = closed_position;

  if (i < open_position) i = open_position;

  switch (_direction) {

    case forward:

      for (; i < closed_position && (millis() - current_time) <= 300 && _direction /*&& digitalRead(limiter_button)*/; myservo.write(i++)) // goes from 60 degrees to 120 degrees

        _delay_ms(15);                              // waits 15 milliseconds for the servo to reach the position

        SoftwareServo::refresh();               // required by SoftwareServo Library to sweep correctly



    case reverse:

      for (; i > open_position && millis() - current_time <= 300 && !_direction; myservo.write(i--)) // goes from 120 degrees to 60 degrees

        _delay_ms(15);                              // waits 15 milliseconds for the servo to reach the position

        SoftwareServo::refresh();               // required by SoftwareServo Library to sweep correctly




  eeprom_update_byte((unsigned char *)saved_position, i);


  PORTB &= ~(_BV(motor_switch)); // turn motor_switch LOW PORTB^=(1<<1);

  DDRB &= ~(_BV(DDB0) | _BV(DDB1)); // pins 0 and 1 input DDRB^=3;

  interrupted_signal = 0;

  if (PINB & PINB_forward) PINB |= _BV(PINB3); // if PINB3 is active switch it off 
  if (PINB & PINB_reverse) PINB |= _BV(PINB4); //should toggle the PINx register as per datasheet



There is no real PINx bit, if read it's just the latched pin value,
if written it toggles the PORTx bit, if the pin is OUTPUT, PINx will follow.

But if you already know better, why do you ask?

Can you please read my code? Lets assume pin3 was latched it trigggers pin change interrupt. In isr pinb register is copied into variable for checking via bitmask. At the end of turn_motor function im toggling the bit to clear it. But in avr studio simulator in io port section pinb register pin is still high. Which means when pin4 will trigger interrupt my if statement will compare first if pin3 is set if no will continue to else if block where it will check pin4. But because pinb pin3 is not being cleared as per simulator it will never go i to else if section.

Is it suppose to be like that in simulator (atmel studio 7) i.e. its actually clearing the bit but atmel studio is not refreshing pinb register?

Im confused.

I have no idea how correct some emulator is.

Run some code to see who is wrong.

Don't worry about trying to reset the PINB bits. Just act on the ones that have changed since the previous interrupt:

ISR(PCINT0_vect) {
  static uint8_t lastPinb = 0;
  uint8_t currentPinb = PINB;
  uint8_t changedBits = currentPinb ^ lastPinb;
  interrupted_signal = changedBits & currentPinb;
  lastPinb = currentPinb;

Thanks gfvalvo that seems to be good workaround.