Read port doesnt return any value when PCINT fired

hi

I enable in sketch PCINT for interrupts and/or for wakeup MC from sleep.
interrupts are working but I want to determine which pin trigger this interrupt
and I facing with two issues on Micro

  1. only PB5 and PB6 are return correct value. PB7 always return zero. why?

  2. when interrupt fire when MC in sleep mode (need uncomment the following string ) then all pins PB5..PB7 return zero. why?

#include "deepSleep.h"
#ifdef USBCON
#define LED  (1 << PC7)
#define led_hi()  PORTC |= LED
#define led_lo()  PORTC &= ~LED
#else
#define LED  (1 << PB5)
#define led_hi()  PORTB |= LED
#define led_lo()  PORTB &= ~LED
#endif
#define PIR  (1 << INT0)
int flag = 0;
int KEYVAL = 0;
int PBLAST = 0;
int PBNOW = 0;

void setup() {

  DDRB = 0; PORTB = 0;
  cli();
  PCICR |= (1 << PCIE0); // Enables Ports B as Pin Change Interrupts
  PCMSK0 |= (1 << PCINT7) | (1 << PCINT6) | (1 << PCINT5); // PCINT0
  sei();

  DDRD |= LED; PORTD &= ~LED;
  Serial.begin(19200);
}
void loop() {

  if (flag) {

    flag = 0;
    Serial.println(millis());
    led_hi();  // turn LED ON
    delay(4000);
    led_lo(); // turn LED OFF if we have no motion
    Serial.println(KEYVAL);
    KEYVAL = 0;

    PBLAST = PINB;
    PCMSK0 |= (1 << PCINT7) | (1 << PCINT6) | (1 << PCINT5);
  }

  //gotoSleep();
  delay(2000);
  Serial.println(F("Up"));

}

ISR(PCINT0_vect)
{
  PCMSK0 = 0;
  ++flag;
  PBNOW = PINB ^ PBLAST;
  switch (PBNOW) {
    case (1 << PB7):
      KEYVAL = 11;
      break;
    case (1 << PB6):
      KEYVAL = 10;
      break;
    case (1 << PB5):
      KEYVAL = 9;
      break;
    default:
      break;
  }
}

inline void gotoSleep() {
  Serial.println(F("goto"));
  delay(2000);
  Serial.println(F("s"));
  delay(200);
  Serial.println(F("l"));
  delay(200);
  Serial.println(F("e"));
  delay(200);
  Serial.println(F("e"));
  delay(200);
  Serial.println(F("p"));
  delay(200);
  deepSleep();
}

inline void wakeupMode() {
  PORTD &= ~PIR;
  EIFR = bit(INTF0);
  attachInterrupt(0, wakeup, RISING );
}

void wakeup() {
  sleep_disable();
  detachInterrupt(0);
  flag++;
}

I note one obvious issue. The following should be declared with the volatile keyword:

int flag = 0;
int KEYVAL = 0;
int PBLAST = 0;
1 Like

Also, variables that are more than 1 byte shared with an interrupt require that interrupts be disabled when reading or writing the variable in loop().

1 Like

Um. Which chip are you using?
Atmega328 doesn’t have PB6 or PB7…

1 Like

Where would I find this library?

That's odd since you take the trouble to set up macros to use PB5 or PC7 for LED.

Similarly, what is this trying to do?!?

This version seems to work fine on all three input pins when coming back from power-down sleep:

#include <avr/sleep.h>
#include <avr/power.h>

#ifdef USBCON
// ATmega32u4: Arduino Leonardo/Micro
const byte Mask11 = _BV(PB7);
const byte Mask10 = _BV(PB6);
const byte Mask9 = _BV(PB5);
#else
// ATmega328p: Ardiuno UNO/Nano
const byte Mask11 = _BV(PB3);
const byte Mask10 = _BV(PB2);
const byte Mask9 = _BV(PB1);
#endif

volatile byte Rising = 0;
volatile byte Falling = 0;
volatile byte Changed = 0;

ISR(PCINT0_vect)
{
  static byte oldState = 0;
  byte newState = PINB;
  byte changed = oldState ^ newState;
  Rising |= newState & changed;
  Falling |= (~newState) & changed;
  Changed |= changed;
  oldState = newState;
}

void setup()
{
  Serial.begin(115200);
  delay(200);

  pinMode(9, INPUT);
  pinMode(10, INPUT);
  pinMode(11, INPUT);

  // disable ADC
  ADCSRA = 0;

  noInterrupts();
  PCICR |= _BV(PCIE0); // Enables PORTB Pin Change Interrupt
  PCMSK0 = Mask11 | Mask10 | Mask9;  // Assumes pin masks and PC masks are the same
  PCIFR = _BV(PCIF0);
  interrupts();
}

void loop()
{
  noInterrupts();
  // byte changed = Changed;
  byte rising  = Rising;
  byte falling = Falling;
  Changed = 0;
  Rising  = 0;
  Falling = 0;
  interrupts();

  if (rising & Mask9) // Pin 9
  {
    Serial.print(millis());
    Serial.println(" Pin 9 RISING");
  }
  if (falling & Mask9) // Pin 9
  {
    Serial.print(millis());
    Serial.println(" Pin 9 FALLING");
  }

  if (rising & Mask10) // Pin 10
  {
    Serial.print(millis());
    Serial.println(" Pin 10 RISING");
  }
  if (falling & Mask10) // Pin 10
  {
    Serial.print(millis());
    Serial.println(" Pin 10 FALLING");
  }

  if (rising & Mask11) // Pin 11
  {
    Serial.print(millis());
    Serial.println(" Pin 11 RISING");
  }
  if (falling & Mask11) // Pin 11
  {
    Serial.print(millis());
    Serial.println(" Pin 11 FALLING");
  }

  Serial.flush(); // make sure all bytes are sent before sleeping
  //  Enter power-down sleep
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);

  sleep_enable();

  // turn off brown-out detection to save power
  noInterrupts ();           // timed sequence follows
  MCUCR = bit (BODS) | bit (BODSE);  // turn on brown-out enable select
  MCUCR = bit (BODS);        // this must be done within 4 clock cycles of above
  interrupts ();

  // turn off various modules
  power_all_disable();

  sleep_cpu ();

  // turn on various modules
  power_all_enable();
}

Micro

it can be replaced with arduino sleep.h
in deepsleep I have added few my stuff for ISR

this is pinMode(9, INPUT); not digitalRead or DigitalWrite. even if I have macros as I know I should configure port before using it. or Im wrong ?

just digitalWrite(LOW).... but I know PIR is not using in this particular case it can be removed , this peace of code from my big sketch

will try now your sleep code...

No. It looks like you were trying to set the LED pin as an output and set it to LOW but you are using PORTD instead of PORTC for Micro or PORTB for UNO. You are setting Pin 6 on Micro and Pin 5 on UNO.

I think that is a digitalWrite(0, LOW);. Why would you set Pin 0 to LOW?

Oh, got you. you are right. just typo. sorry

to be correct, here digitalWrite(3, LOW) seence INT0 == PD0 == pin3 (micro), BUT
you open my eyes :slight_smile: because I use this code also for Nano , is need for me to correct this logic. thank you!

I have your latest example tried....
on micro is not working because you have not used USBDevice.attach detach , plus need add time for upload USBDevice attach... I tried to add this my self (MCU is goes to sleep and wakeup) but not get anything on serial... need to brainstorm more

on Nano is working but PB1 is triggering only once after each restart, cannt understand why

johnwasser
could you try on your end

On my UNO I can get multiple pin change reports for all three pins after a reset.

after small fixes I can see printing after sleep on micro

for using switch/case is need to add more if/mask/etc
much easier as johnwasser using combo of if. thank you for help

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