Need more interrupts

Arduino forum,
I'm just learning the Nano and have my I2C LCD and HC-SR04 sensor working.

Reading about the pin functions it looks like only ports 2/3 have interrupts and is seems that is uses interrupts to capture the echo wavelength of the HC-SR04.

I am used to using a counter to measure this and I will eventually need more interrupts.

I read about port expanders but they doesn't supply much in the way of interrupts.

Is there a way to get around this without going to larger device.

jerdon

  • Interrupts are almost never necessary.

  • What makes you think you need to use interrupts ?

2 Likes

When they designed the ATmega328 chip, they decided that it should have more interrupts than the ATmega8, while keeping most things the same. So they added a Pin Change Interrupt (PCINT) to each pin.

The EnableInterrupt library makes using them easy: https://github.com/GreyGnome/EnableInterrupt
It is in the Library Manager of the Arduino IDE.

There is a better way for ultrasonic distance sensors, the NewPing library: https://bitbucket.org/teckel12/arduino-new-ping/wiki/Home
This library is also in the Library Manager of the Arduino IDE.

In the Arduino world, an interrupt is almost never necessary, as LarryD wrote. The more you use interrupts and timers, the less compatible the code is.
Reading buttons in a interrupt is normal in a embedded system, but not in the Arduino world. The Arduino Nano has only 2kbyte of SRAM, but it is still possible to do many thing "at the same time" with a sketch that has no delay and uses millis() for timing.

If you are used to embedded systems with a multitasking system and interrupts and queues and semaphores, then you can use the ESP32 (or a newer variant) or the Raspberry Pi Pico.
The ESP32 runs FreeRTOS and the Raspberry Pi Pico runs Mbed. The Arduino layer is build upon that.

Koepel,
Thanks for a very informative response.

As you suspect I have been using embedded micro controllers and this is my first attempt at anything Arduino.

There isn't a rev number on my Nano but the chip is an ATMEL M32P U-TH.

I read about the NewPing library and it may address all my issues.

Would it have any pin restrictions on my Nano device?

jerdon

I think that any pin can be used.
The NewPing library uses Timer2 with an interrupt. Since the Arduino Nano has only three timers, and Timer0 is in use by Arduino, you might run out of timers if you add another library that uses a timer (tone, Servo, and many other libraries).

The maker of the NewPing library has an alternative for the tone() function that uses Timer1: https://bitbucket.org/teckel12/arduino-toneac/wiki/Home

The label "ATMEL M32P" indicates the ATmega328P. I can not find when the microcontroller was introduced, but it is still amazing what a simple microcontroller can do. It is/was the perfect companion for Arduino, because at power up everything is guaranteed to be turned off. The boot section is therefor very simple. The code only needs to initialize what is used inside the microcontroller.

One doesn't need any interrupts at all. Here's a simulation that shows that an Arduino/Nano can be fast enough to read an HC-SR04 with plain old state machine and state change detection coding:

/*
  HC-SR04 Ultrasonic sensor with plain, non-blocking state-machine coding
  https://wokwi.com/projects/404439179947636737

  This code blinks the trigger pin periodically,
  records the time of the falling edge of the trigger, and the flight time of the echo.

*/
/*
  Uno with Scope https://github.com/Dlloydev/Wokwi-Chip-Scope
        and https://github.com/Dlloydev/Wokwi-Chip-PWM


  Wokwi Uno https://wokwi.com/projects/390819301187622913
  Wokwi Mega: https://wokwi.com/projects/390819455604080641

  See also https://wokwi.com/projects/359331973918199809

*/

const byte TriggerPin = 13;
const byte EchoPin = 12;

// timing variables
uint32_t nowMs = 0, triggerUs = 0, echoUs = 0;
uint32_t echoRiseUs = 0, echoFallUs = 0;
const uint32_t PingInterval = 100;

float distance = 0;

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(TriggerPin, OUTPUT);
  pinMode(EchoPin, INPUT);
  Serial.begin(115200);
}

// the loop function runs over and over again forever
void loop() {
  nowMs = millis();
  doPings();
  if (watchEchoFall()) {
    calculateDistance();
  }
  report();
}

float calculateDistance() {
  echoUs = echoFallUs - echoRiseUs;
  // could print on pulses, or calculate distance
  distance = echoUs * 34320.0 / 1000000 / 2; // cm/sec for round trip 
  return distance;
}

void doPings(void) {
  static uint32_t lastPingMs = 0;
  static bool triggerState;
  if (nowMs - lastPingMs >= PingInterval) {
    triggerState = triggerState == HIGH ? LOW : HIGH;
    digitalWrite(TriggerPin, triggerState);
    if (triggerState == LOW) {
      triggerUs = micros();
      //   Serial.print('*');
    }
    lastPingMs += PingInterval;
  }
}

bool watchEchoFall() {
  bool echoFell = false;
  static byte lastEcho = LOW;
  uint32_t nowUs = micros();
  byte echoState = digitalRead(EchoPin);
  if (echoState != lastEcho) {
    if (echoState == HIGH) {
      echoRiseUs = nowUs;
    } else {
      echoFallUs = nowUs;
      echoFell = true;
    }
    lastEcho = echoState;
  }
  return echoFell;
}
void report() {
  static uint32_t lastEchoUs = -1;
  if (echoUs != lastEchoUs) {
    lastEchoUs = echoUs;
    Serial.print(echoUs);
    Serial.print("us ");
    Serial.print(distance);
    Serial.println("cm ");
  }
}
1 Like