Go Down

Topic: HC - SR04 interrupt driven MEGA code (Read 290 times) previous topic - next topic

mikesbaker

Nov 14, 2014, 10:11 pm Last Edit: Nov 17, 2014, 05:22 pm by mikesbaker
 I wasn't happy with the code examples which are blocking and use pulseIn for what are hopefully obvious reasons. Because of the issues with blocking I have written an interrupt based sketch for the MEGA. Consulting the datasheet should allow this to be easily converted to work on any of the 8 bit arduinos.

Trigger is pin 11

Echo is pin 12

I hope this helps someone.

Code: [Select]

#define FREQ_TRIG 15
#define PRESCALE_TRIG 64
#define PERIOD_TRIG ((F_CPU/PRESCALE_TRIG/FREQ_TRIG) - 1)

volatile uint32_t start,width;
float pingDistCentimeters,pingDistMeters;
volatile boolean newPing;

void setup(){
  Serial.begin(115200);
  SonarInit();//must go above detectRC or the program breaks!
}

void loop(){
  if (newPing == true){
    newPing = false;
    pingDistCentimeters = width  * 0.01724137;
    pingDistMeters = pingDistCentimeters * 0.01;
    Serial.println(pingDistCentimeters);
  } 
}

void SonarInit(){

  DDRB |= (1<<PB5);
  TCCR1A = (1<<WGM11)|(1<<COM1A1);
  TCCR1B = (1<<WGM13)|(1<<WGM12)|(1<<CS11)|(1<<CS10);
  ICR1 = PERIOD_TRIG; 
  OCR1A = 2;

  DDRB &= ~(1<<PB6);
  PORTK |= (1<<PB6);
  PCMSK0 |= 1<<PCINT6;
  PCICR |= 1<<0;

}


ISR(PCINT0_vect){
  if (newPing == true){
    return;
  }
  if (((PINB & 1<<PB6)>>PB6) == 1){
    start = micros();

  }
  else{
    width = (micros() - start);
    if (width <= 17400){
      newPing = true;
    }

  }

}



The above code has been corrected as per robtillaart's suggestion.

robtillaart

#1
Nov 14, 2014, 11:29 pm Last Edit: Nov 14, 2014, 11:32 pm by robtillaart
thanks for sharing!

refactored your code a bit,
+ newping should be volatile too
+ removed volatile from two others
+ use the newping flag to shortcut the ISR
  (prevents width to be changed by the ISR during the multiplication in loop, is not atomic)

Code: [Select]

volatile uint32_t start, width;
volatile boolean newPing;

uint32_t pingDistCentimeters;
float pingDistMeters;


void setup()
{
  Serial.begin(115200);
  SonarInit(); //must go above detectRC or the program breaks!
}

void loop()
{
  if (newPing == true)
  {
    pingDistCentimeters = width  * 0.01724137931034482758620689655172;
    newPing = false;       
    pingDistMeters = pingDistCentimeters * 0.01;
    Serial.println(pingDistCentimeters);
  } 
}

void SonarInit()
{
  DDRB |= (1<<PB5);
  TCCR1A = (1<<WGM11)|(1<<COM1A1);
  TCCR1B = (1<<WGM13)|(1<<WGM12)|(1<<CS11)|(1<<CS10);
  ICR1 = PERIOD_TRIG; 
  OCR1A = 2;

  DDRB &= ~(1<<PB6);
  PORTK |= (1<<PB6);
  PCMSK0 |= 1<<PCINT6;
  PCICR |= 1<<0;
}

ISR(PCINT0_vect)
{
  if (newPing == true)
    return;
  if (PINB & (1 << PB6))  // all values != 0 are true  // HIGH
  {
    start = micros();
  }
  else  // LOW
  {
    width = (micros() - start);
    if (width <= 17400)
    {
      newPing = true;
    }
  }
}
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

mikesbaker

#2
Nov 17, 2014, 05:04 pm Last Edit: Nov 17, 2014, 05:07 pm by mikesbaker
Nice catch there. Thanks. Though I suppose that both the distance in meters and centimeters should be floats.

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy