Treiber - SRF05 Ultraschall-Entfernungsmesser

Kurzbeschreibung

Mit diesem Code kann ein SRF05 Ultraschall-Entfernungsmesser sehr einfach abgefragt werden. Verwendet wird dieser Code bei mir auf einem ATmega8 mit 16MHz. Angeschlossen ist das Modul mit dem Echo Output an einen Interrupt-Eingang (hier PORTD.3 / INT1). Der Trigger Input ist an einen beliebigen Pin angeschlossen (hier PORTD.4).
Soll die Entfernung gemessen werden, wird an den Trigger-Pin ein kurzer Puls von 20μs angelegt. Dies startet den Messprozess. Sobald das Ultraschallsignal abgesendet wird, erhält man am Echo Output eine steigende Flanke und kann damit einen Timer starten. Wurde das Echo vom Modul empfangen, gibt es eine fallende Flanke aus; das Signal, um den Timer wieder zu stoppen.

In diesem Code läuft der Controller mit 16MHz, der Timer mit einem Prescaler von 8 und damit mit einer Zählfrequenz von 2MHz, entsprechend einer Tick-Duration von 0,5μs. Dies ergibt eine Auflösung von 0,1715mm bei einer Schallgeschwindigkeit von 343 m/s.

Funktionen

SRF05_Init

Initialisiert den Interrupt-Pin für das Echo-Signal sowie den Ausgang für das Trigger-Signal.

SRF05_GetResponseTime

Startet die Messung des Moduls und gibt die Dauer der Echolaufzeit in Ticks (= 0,5μs) zurück. Die Entfernung d (in mm) zum gemessenen Objekt berechnet sich aus der Echolaufzeit t (in Ticks) mit: d = ((t / 2) × 343) / 1000

Interrupts

ISR(SRF_RESULT_ISR)

Überwacht den Echo-Pin und startet bzw. stoppt den Messtimer, je nach Art der Signalflanke.

ISR (SIG_OVERFLOW1)

Zählt die Anzahl der Timerüberläufe, um einen grösseren Messbereich zu erzielen.

Code

srf05.c

#include "srf05.h"
 
typedef enum
{
  SRF_IDLE = 0,
  SRF_WAITING_FOR_ECHO,
  SRF_ECHO_ACTIVE,
  SRF_RESULT_READY,
  SRF_TIMEOUT
} e_srfstate;
 
volatile uint32_t SRF_LastResult;
volatile uint8_t  SRF_Overflows = 0;
volatile uint16_t SRF_TCNT = 0;
volatile uint32_t SRF_TotalTimeTicks = 0;
 
volatile e_srfstate SRF_State = SRF_IDLE;
 
void SRF05_Init(void)
{
  // Setup result pin
  SRF_RESULT_PORT  &=~ (1 << SRF_RESULT_PIN);
  SRF_RESULT_DDR   &=~ (1 << SRF_RESULT_PIN);
 
  // setup trigger pin
  SRF_TRIGGER_PORT &=~ (1 << SRF_TRIGGER_PIN);
  SRF_TRIGGER_DDR  |=  (1 << SRF_TRIGGER_PIN);
 
  // Setup result pin interrupt:
  SRF_RESULT_INT_ISC_REG |= (1 << SRF_RESULT_INT_ISC_BIT);
}
 
uint32_t SRF05_GetResponseTime(void)
{
  SRF_LastResult = 0xFFFFFFFF;
  // Response signal 100us - 25ms
  // FCPU = 16MHz
  // Prescaler 8 => 2 MHz => 0.5 us tick duration
 
  // Prepare Timer
  TCCR1A = 0; // Standard timer; just count here
  TCCR1B = 0; // Stop timer
  TCNT1 = 0;
  SRF_Overflows = 0;
  SRF_TCNT = 0;
  SRF_TotalTimeTicks = 0;
 
  // clear a possible pending interrupt request
  SRF_RESULT_INT_FLAG_REG |= (1 << SRF_RESULT_INT_FLAG_BIT);
 
  // enable interrupt (both edges)
  SRF_RESULT_INT_MSK_REG |= (1 << SRF_RESULT_INT_MSK_BIT);
 
  // enable timer overflow interrupt
  TIMSK |= (1 << TOIE1);
 
  SRF_State = SRF_WAITING_FOR_ECHO;
 
  // Send trigger pulse (20us)
  SRF_TRIGGER_HIGH();
  _delay_us(20);
  SRF_TRIGGER_LOW();
 
  // wait until measurement is complete
  while((SRF_State == SRF_ECHO_ACTIVE) || (SRF_State == SRF_WAITING_FOR_ECHO))
  {
    // nothing to do; just wait...
  }
 
  // Calculate result  
  SRF_TotalTimeTicks  = SRF_Overflows;
  SRF_TotalTimeTicks <<= 16;
  SRF_TotalTimeTicks += SRF_TCNT;
  SRF_LastResult = SRF_TotalTimeTicks;
  return SRF_TotalTimeTicks;
}
 
ISR(SRF_RESULT_ISR)
{
  uint8_t pinlevel = SRF_RESULT_INPUT & (1 << SRF_RESULT_PIN);
 
  if (pinlevel)
  {
    // rising edge: result pulse started
    // start timer for counting
    TCCR1B = (1 << CS11);
    SRF_State = SRF_ECHO_ACTIVE;
  }
  else
  {
    // falling edge: result pulse end
    // stop timer
    SRF_TCNT = TCNT1;
    TCCR1B = 0;
 
    // disable trigger interrupt
    SRF_RESULT_INT_MSK_REG &=~ (1 << SRF_RESULT_INT_MSK_BIT);
 
    // disable timer overflow interrupt
    TIMSK &=~ (1 << TOIE1);
    SRF_State = SRF_RESULT_READY;
 
    // clear possible pending interrupt requests
    SRF_RESULT_INT_FLAG_REG |= (1 << SRF_RESULT_INT_FLAG_BIT);
    TIFR |= (1 << TOV1);
  }
}
 
ISR (SIG_OVERFLOW1) // Interrupt Timer 1
{
  SRF_Overflows++;
}

srf05.h

#ifndef _SRF05_H_
#define _SRF05_H_
 
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "srf05_cfg.h"
 
extern volatile uint32_t SRF_LastResult;
 
#define SRF_TRIGGER_HIGH()   (SRF_TRIGGER_PORT |=  (1 << SRF_TRIGGER_PIN))
#define SRF_TRIGGER_LOW()    (SRF_TRIGGER_PORT &=~ (1 << SRF_TRIGGER_PIN))
 
void SRF05_Init(void);
uint32_t SRF05_GetResponseTime(void);
 
#endif

srf05_cfg.h

#ifndef _SRF05_CFG_H_
#define _SRF05_CFG_H_
 
// Pin, the trigger signal is connected to
#define SRF_TRIGGER_PORT     PORTD
#define SRF_TRIGGER_DDR      DDRD
#define SRF_TRIGGER_PIN      4
 
// Pin, the echo/result signal is connected to
#define SRF_RESULT_PORT      PORTD
#define SRF_RESULT_DDR       DDRD
#define SRF_RESULT_INPUT     PIND
#define SRF_RESULT_PIN       3
 
// Interrupt configuration for echo pin
#define SRF_RESULT_INT_ISC_REG  (MCUCR)
#define SRF_RESULT_INT_ISC_BIT  (ISC10)
 
// Interrupt mask register and bit for echo pin
#define SRF_RESULT_INT_MSK_REG  (GICR)
#define SRF_RESULT_INT_MSK_BIT  (INT1)
 
// Interrupt flag register and bit for echo pin
#define SRF_RESULT_INT_FLAG_REG (GIFR)
#define SRF_RESULT_INT_FLAG_BIT (INTF1)
 
// Name of the interrupt, the echo pin is connected to
#define SRF_RESULT_ISR           SIG_INTERRUPT1
#endif

Downloads

srf05.c
srf05.h
srf05_cfg.h
srf05.zip (Alle Dateien)


Letzte Änderung: 2016-05-05 23:14:41
Seite erzeugt in 0.033 Sekunden (17.1 kB)