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.
#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++; }
#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
#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