Arduino Due and ultrasonic sensor with timer interrupts

Hi,
I am trying to get my arduino due to run the SR-04 ultrasonic sensor to take distance readings. I made sure to drop the voltage down to 3.3v for the echo pin, and double checked the sensor worked with the due using a basic code with delays. However my code that uses timer interrupts on the Due only gives me the first distance it reads and then keeps printing out that reading. I’m using the DueTimer.h library for the timer interrupts. Everything seems to be working except for the fact that It only prints what ever its first distance reading is instead of updating that distance as it changes. Any help would be great :slight_smile:

#include<DueTimer.h>                                // Header file for DueTimer file library
const byte trigPin = 12;                             // Pin 12 trigger output
const byte echoPin = 8;                              // Pin 8 Echo input                                  
const unsigned long TICK_COUNTS = 4000;               // count down timer           
volatile long echo_start = 0;                         // Records start of echo pulse 
volatile long echo_end = 0;                           // Records end of echo pulse
volatile long echo_duration = 0;                      // Duration - difference between end and start
volatile int trigger_time_count = 0;                  // Count down counter to trigger pulse time
unsigned long previousMillis=0;                       // millis() returns an unsigned long.
void setup() {
  // put your setup code here, to run once:
  pinMode(13,OUTPUT);
  pinMode(trigPin, OUTPUT);                           // Trigger pin set to output
  pinMode(echoPin, INPUT);                            // Echo pin set to input
  Timer3.attachInterrupt(timerIsr).setPeriod(50).start(); // timer interrupt to control trigger pulse, 50uS timer.
  attachInterrupt(8, echo_interrupt, CHANGE);  // Attach interrupt to the sensor echo input
  Serial.begin (9600);                            
  digitalWrite(13,LOW);
}
void loop(){
   
   unsigned long currentMillis = millis();          
   static volatile long distance, distanceA;          
   distance = (echo_duration/58);                       // distance computed from the echo pulse
  if(currentMillis-previousMillis >= 500){              // every 500 millis run print code
   distanceA = distance;                                // Set distanceA to whatever distance has been computed
   Serial.print("A");                                   
   Serial.println(distanceA);                           // print ditanceA
   previousMillis = millis();

  }

}


void timerIsr()
{
       trigger_pulse();                             // Schedule the trigger pulses sensor 1

}
    
                                 

void trigger_pulse()
{
      static volatile int stateB = 1;                 // State machine variable

      if (!(--trigger_time_count))                   // Count to 200mS
      {                                              // Time out - Initiate trigger pulse
         trigger_time_count = TICK_COUNTS;           // Reload
         stateB = 1;                                  // Changing to state 1 initiates a pulse
      }
    
      switch(stateB)                                  // State machine handles delivery of trigger pulse
      {
        case 0:                                      // Normal state does nothing
            break;
        
        case 1:                                      // Initiate pulse
           digitalWrite(trigPin, HIGH);              // Set the trigger output high
           stateB = 2;                                // and set state to 2
           break;
        
        case 2:                                      // Complete the pulse
        default:      
           digitalWrite(trigPin, LOW);               // Set the trigger output low
           stateB = 0;                                // and return state to normal 0
           break;
     }
}

void echo_interrupt()
{
  switch (digitalRead(echoPin))                     // Test to see if the signal is high or low
  {
    case HIGH:                                      // High so must be the start of the echo pulse
      echo_end = 0;                                 // Clear the end time
      echo_start = micros();                        // Save the start time
      break;
      
    case LOW:                                       // Low so must be the end of hte echo pulse
      echo_end = micros();                          // Save the end time
      echo_duration = echo_end - echo_start;        // Calculate the pulse duration
      break;
  }
}

There is a great chance that you don't clear the Timer status register once the interrupt Handler has been triggered the first time. If the status register has not been read (and cleared), the interrupt handler is no more called. To debug, set a much larger interval (several ms) to trigger timerisr(), and Serial.print something to see whether you call it again or not. Of course, after debugging, you wil remove the Serial.print.

If you still have issues with the timer counter, use another one: https://github.com/antodom/tc_lib

or make a direct register programming (numerous example sketches in the DUE sub forum).

BTW, select 250000 rather than 9600 for Serial.begin()

Hey Thanks for the reply, so I pushed the timerIsr up to 5ms and then had it print me a message and you were right, it printed the message once and then halfway through a second time before stopping. Then I pushed the baud rate to 250k and it printed the message a bunch of times an then printed the distance in between. How ever the distance was still repeating, so does that mean with the 250k baud rate it still isn’t clearing the time status register? I put the serial print in the void(timerIsr).

#include<DueTimer.h>                                // Header file for DueTimer file library
const byte trigPin = 12;                             // Pin 12 trigger output
const byte echoPin = 8;                              // Pin 8 Echo input                                  
const unsigned long TICK_COUNTS = 4000;               // count down timer           
volatile long echo_start = 0;                         // Records start of echo pulse 
volatile long echo_end = 0;                           // Records end of echo pulse
volatile long echo_duration = 0;                      // Duration - difference between end and start
volatile int trigger_time_count = 0;                  // Count down counter to trigger pulse time
unsigned long previousMillis=0;                       // millis() returns an unsigned long.
unsigned long previousMillisB =0;
static volatile unsigned int stateB = 1;
void setup() {
  // put your setup code here, to run once:
  pinMode(13,OUTPUT);
  pinMode(trigPin, OUTPUT);                           // Trigger pin set to output
  pinMode(echoPin, INPUT);                            // Echo pin set to input
 // Timer2.attachInterrupt(
  Timer3.attachInterrupt(timerIsr).setPeriod(5000).start(); // timer interrupt to control trigger pulse, 50uS timer.
  attachInterrupt(8, echo_interrupt, CHANGE);  // Attach interrupt to the sensor echo input
  Serial.begin (250000);                            
  digitalWrite(13,LOW);
}
void loop(){
   unsigned long currentMillisB = millis();
   unsigned long currentMillis = millis();          
   static volatile long distance, distanceA;          
   distance = (echo_duration/58);                       // distance computed from the echo pulse
  if(currentMillis-previousMillis >= 100){              // every 500 millis run print code
   distanceA = distance;                                // Set distanceA to whatever distance has been computed
   Serial.print("A");                                   
   Serial.println(distanceA);                           // print ditanceA
   previousMillis = millis();
   
  }

  /*if((currentMillisB-previousMillisB)>= 20){
    stateB = 1;
    //Serial.print("CB");
    //Serial.println(currentMillisB);
    previousMillisB = millis();
    
  }*/
}


void timerIsr()
{
       trigger_pulse();                             // Schedule the trigger pulses sensor 1
       Serial.println("So triggered bro.. ;-)");    // debug serial print line, remove later. :-)
}
    
                                 

void trigger_pulse()
{
      //static volatile int stateB = 1;                 // State machine variable

      if (!(--trigger_time_count))                   // Count to 200mS
      {                                              // Time out - Initiate trigger pulse
         trigger_time_count = TICK_COUNTS;           // Reload
         stateB = 1;                                  // Changing to state 1 initiates a pulse
      }
    
      switch(stateB)                                  // State machine handles delivery of trigger pulse
      {
        case 0:                                      // Normal state does nothing
            break;
        
        case 1:                                      // Initiate pulse
           digitalWrite(trigPin, HIGH);              // Set the trigger output high
           stateB = 2;                                // and set state to 2
           break;
        
        case 2:                                      // Complete the pulse
        default:      
           digitalWrite(trigPin, LOW);               // Set the trigger output low
           stateB = 0;                                // and return state to normal 0
           break;
     }
}

void echo_interrupt()
{
  switch (digitalRead(echoPin))                     // Test to see if the signal is high or low
  {
    case HIGH:                                      // High so must be the start of the echo pulse
      echo_end = 0;                                 // Clear the end time
      echo_start = micros();                        // Save the start time
      break;
      
    case LOW:                                       // Low so must be the end of hte echo pulse
      echo_end = micros();                          // Save the end time
      echo_duration = echo_end - echo_start;        // Calculate the pulse duration
      break;
  }
}

Also, right before you replied I managed to get it working but in a way that I feel will give me headaches later as incorporate it into more complex code. I put an (if) statement in the loop that changes stateB out of the pause between pulses, so next time the Isr is called it will pulse trigger pin. let me know what you think.

#include<DueTimer.h>                                // Header file for DueTimer file library
const byte trigPin = 12;                             // Pin 12 trigger output
const byte echoPin = 8;                              // Pin 8 Echo input                                  
const unsigned long TICK_COUNTS = 4000;               // count down timer           
volatile long echo_start = 0;                         // Records start of echo pulse 
volatile long echo_end = 0;                           // Records end of echo pulse
volatile long echo_duration = 0;                      // Duration - difference between end and start
volatile int trigger_time_count = 0;                  // Count down counter to trigger pulse time
unsigned long previousMillis=0;                       // millis() returns an unsigned long.
unsigned long previousMillisB =0;
static volatile unsigned int stateB = 1;
void setup() {
  // put your setup code here, to run once:
  pinMode(13,OUTPUT);
  pinMode(trigPin, OUTPUT);                           // Trigger pin set to output
  pinMode(echoPin, INPUT);                            // Echo pin set to input
 // Timer2.attachInterrupt(
  Timer3.attachInterrupt(timerIsr).setPeriod(50).start(); // timer interrupt to control trigger pulse, 50uS timer.
  attachInterrupt(8, echo_interrupt, CHANGE);  // Attach interrupt to the sensor echo input
  Serial.begin (250000);                            
  digitalWrite(13,LOW);
}
void loop(){
   unsigned long currentMillisB = millis();
   unsigned long currentMillis = millis();          
   static volatile long distance, distanceA;          
   distance = (echo_duration/58);                       // distance computed from the echo pulse
  if(currentMillis-previousMillis >= 100){              // every 500 millis run print code
   distanceA = distance;                                // Set distanceA to whatever distance has been computed
   Serial.print("A");                                   
   Serial.println(distanceA);                           // print ditanceA
   previousMillis = millis();
   
  }

  if((currentMillisB-previousMillisB)>= 20){            // every 20ms put stateB back to trig high case for next time Isr called
    stateB = 1;                                         // so trigpin is high for 50uS, then nothing for 19950us or about 20ms
    previousMillisB = millis();                         // this puts a pause between readings.
    
  }
}


void timerIsr()
{
       trigger_pulse();                             // Schedule the trigger pulses sensor 1
      // Serial.println("So triggered bro.. ;-)");    // debug serial print line, remove later. :-)
}
    
                                 

void trigger_pulse()
{
      //static volatile int stateB = 1;                 // State machine variable

     /* if (!(--trigger_time_count))                   // Count to 200mS
      {                                              // Time out - Initiate trigger pulse
         trigger_time_count = TICK_COUNTS;           // Reload
         stateB = 1;                                  // Changing to state 1 initiates a pulse
      }
    */
      switch(stateB)                                  // State machine handles delivery of trigger pulse
      {
        case 0:                                      // Normal state does nothing
            break;
        
        case 1:                                      // Initiate pulse
           digitalWrite(trigPin, HIGH);              // Set the trigger output high
           stateB = 2;                                // and set state to 2
           break;
        
        case 2:                                      // Complete the pulse
        default:      
           digitalWrite(trigPin, LOW);               // Set the trigger output low
           stateB = 0;                                // and return state to normal 0
           break;
     }
}

void echo_interrupt()
{
  switch (digitalRead(echoPin))                     // Test to see if the signal is high or low
  {
    case HIGH:                                      // High so must be the start of the echo pulse
      echo_end = 0;                                 // Clear the end time
      echo_start = micros();                        // Save the start time
      break;
      
    case LOW:                                       // Low so must be the end of hte echo pulse
      echo_end = micros();                          // Save the end time
      echo_duration = echo_end - echo_start;        // Calculate the pulse duration
      break;
  }
}

Obviously, this is not the right way to call a callback function.

To clear the status register, you have to call Tc_getStatus(TCx) inside the TC Interrupt Handler. I guess there must be example sketches in the Due library you are using.... Or use another one

A Serial.print() takes some hundreds of us, that's why you can't Serial.print() inside an interrupt Handler.

Sorry for the delay, busy week. I'll give it shot and do more research to better understand how the due timer works. thank you!