Messen mit dem Ultraschall Modul HC-SR04 mit Ausgabe am PC oder auf LCD

 

 

 

Informationen zum HC-SR04 (Robosoftsystem)

************************************************************************************
Start Quellcode
************************************************************************************
// Prozesortaktfrequent festlegen
#define F_CPU 16000000UL

// Baudrate
#define BAUD 19200UL

// Baudratenberechnung
#define UBRR_VAL ((F_CPU+BAUD*8) / (BAUD*16)-1)

// CR ist Zeilenumbruch
#define CR 0x0D

// Benötigte Bibliotheken hinzufügen
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdlib.h>

// Variablen deklarieren
uint16_t rising, falling;     // Zum speichern der Timerwerte bei steigender und fallender Flanke
int counts;                         // Die Differenz der beiden Timerwerte (Signallänge in TimerTakten)
float dist;                          // Der berechnete Abstand in cm mit bis zu 6 Kommastellen
uint16_t us_per_count;    // Die Länge eines TimerTaktes in us

// ********************************************************************************************************************************************
// ****************************************************** Serielle Übertragung ****************************************************************
// UART-Init ATmega328P

void uart_init(void)
{
    // Baudrate einstellen
    UBRR0H = (unsigned char)(UBRR_VAL>>8);
    UBRR0L = (unsigned char)UBRR_VAL;
   
    // Receiver und Transmitter einschalten
    UCSR0B = (1<<RXEN0)|(1<<TXEN0);
   
    // Frame Format: Asynchron 8N1
    UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
}

// Charakter schreiben (Ein Zeichen senden als ASCII)
void uart_putChar(unsigned char c)
{
    // Warten bis Sendepuffer leer ist
    while (!(UCSR0A & (1<<UDRE0)));
   
    // Daten in den Puffer schreiben und senden
    UDR0 = c;
}

// String senden (Einen Zeichenfolge in einzelne Zeichen zerlegen und an uart_putChar zum senden übergeben)
void uart_putStr(unsigned char *s)
{
    while (*s)
    {  
        // so lange *s != ‘�’ also ungleich dem “String-Endezeichen(Terminator)”
        uart_putChar(*s);
        s++;
    }
}
// ********************************************************************************************************************************************

// ********************************************************************************************************************************************
// ************************************************* ISP **************************************************************************************

// Int. wenn die sich verändernde Flanke (von “1 nach 0 – fallende” oder von “0 nach 1 – steigende”) erkannt wird. (An PIN PB0 (ARDUINO PIN 8))
ISR(TIMER1_CAPT_vect)
{
    if (TCCR1B & (1<<ICES1))     // (Wenn das Bit ICES1 im register TCCR1B = 1 ist, also einen steigende Flanke erkennt)
    {
        TCCR1B &= ~(1<<ICES1);     // (Erkennung umschalten auf fallende Flanke (Bit ICES1 im register TCCR1B = 0))
        rising = ICR1;                           // (Den beim auslösen des Int. im Register ICR1 gespeicherten Timer/Counter Wert in die Variable “rising” speichern)

    }
    else // (Wenn das Bit ICES1 im register TCCR1B = 0 ist, also einen fallende Flanke erkennt)
    {
        TCCR1B |= (1<<ICES1);     // (Erkennung umschalten auf steigende Flanke (Bit ICES1 im register TCCR1B = 1))
        falling = ICR1;                      // (Den beim auslösen des Int. im Register ICR1 gespeicherten Timer/Counter Wert in die Variable “falling” speichern)
        counts = falling – rising;        // die Differenz zwischen tEnd und tStart berechnen (z.B.: Steigende Flanke erkannt bei tStart=120, fallenden Flanke erkannt bei tEnd=670 – 670-120=tPuls=550)

        dist = (float)us_per_count * counts * 10 / 580;     // (Laufzeit Schall in Weg “cm” umrechnen)
    }
}

// Is triggered on timer match of OCR1A (Int. wenn der Vergleichswert in OCR1A erreicht ist)
ISR(TIMER1_COMPA_vect)
{
    // Generate a 12us pulse to trigger the HR-SR04
    PORTB ^= (1<<PIN2);
    _delay_us(12);
    PORTB ^= (1<<PIN2);
}
// ********************************************************************************************************************************************

int main(void)
{
    // Uart Init
    uart_init();
   
    unsigned char str[10];
   
    DDRB |= (1<<PIN2);      // PORTB PIN 2 as output
    DDRB |= (1<<PIN5);      // PORTB PIN 5 as output
   
   
   
    // ********************************************************************************************************************************************
    // *************************************************************** TIMER1 INIT ****************************************************************

    TCCR1B |= (1<<ICNC1) | (1<<CS10) | (1<<CS11) | (1<<WGM12);      //ICNC1:Rauschunterdrückung, CS10 and CS11: Prescale (Teiler) auf 64, WGM12: CTC-Modus auswählen
    TIMSK1 |= (1<<ICIE1) | (1<<OCIE1A);      // Int. auslösen bei: Erreichen von TOP, bei steigender bzw. fallender Flanke
    TCCR1B |= (1<<ICES1);      // Int. auslösen bei steigender Flanke
   
    // TOP berechnen (70ms Laufzeit für einene Cyclus): 16MHz/64 = 250000count/sek = 250000/1000 = 25000count/us / 100 * 70 = 17500 count/70ms

    OCR1A = 17500;

      
    // CPU-Takt / Prescale = Takte/Sek. 1Sek / Takt/Sek = 4 ( t = 4us/Takt)
    us_per_count = 4;

    sei();     //Interrupt global aktivieren

    // Endlosschleife
    while (1)
    {
        if (dist < 300)     // Wenn die Distanz innerhalb des Messbereiches (max. 300cm) liegt, …
        {
            uart_putStr(dtostrf(dist, 1, 2, str));     // … dann Ausgabe der Distanz mit 2 Stellen hinter dem Komma per Seriell
            uart_putStr(” cm”);      // schreibe hinter dem Wert ein “cm”
            uart_putStr(“r”);     // gehe zurück zum Anfang der Zeile
        }
        else     // Wenn nicht, …
        {
            uart_putStr(“ERROR”);     // … schreibe “ERROR” in dei Ausgabe
            uart_putStr(“r”);    
// gehe zurück zum Anfang der Zeile 
        }
       
       
        _delay_ms(250);
    }
}


**********************************************************************************
Ende Quellcode
**********************************************************************************

Diese Seiten habne mir geholfen das Projekt umzusetzen:

ATmega168/328-Arduino Pin Mapping
CONVERTWORLD.COM – Umrechnen von Einheiten ganz einfach

 

Vielen Dank!
 
 

Schreibe einen Kommentar