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