Go Down

Topic: HC - SR04 interrupt driven MEGA code (Read 123 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