PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Ansteuerung Ultraschallsensor HC-SR04



icebreaker
02.08.2013, 19:35
Hallo Community! :D

Ich möchte einen HC-SR04 mit einem Atmega8 auslesen
es gibt ja ein paar programme dazu im Internet, die ich allerdings nicht zum laufen bekomme.

nun meine Frage: Warum geht das nicht so einfach wie im folgenden Code probiert?
also es lässt sich ohne Fehler Compilieren, danach leuchtet die LED allerdings nur rot.

das Programm soll die LED einschalten wenn etwas näher als 5 cm am Ultraschallsensor ist.

Trigger: PC0
Echo: PC1
LED: PC3


#define F_CPU 16000000UL

#include <avr/io.h>
#include <util/delay.h>



#define ps 1024 //prescaler
#define ss 343.2 //sound speed




volatile uint16_t value;


void timer_init(void){
TCCR0|=(1<<CS02)|(1<<CS00);//prescale for timer 1024 @16MHz
}


uint8_t HC_SR04(void)
{
//generate a trigger signal
PORTC &= ~(1<<PC0);
_delay_us(1);
PORTC |= (1<<PC0);
_delay_us(10);
PORTC &= ~(1<<PC0);

while(!(PINC & (1<<PC1)))
{

}
//wait until echo pin be high
TCNT0=0;
while(PINC & (1<<PC1))
{

}


//count until echo pin be low

return TCNT0*ps*(1/F_CPU)*ss*100;
}






void motorInit(void)
{
DDRD |= (1<<7) | (1<<6) | (1<<5);
DDRB |= (1<<0);

PORTD |= (1<<7);
PORTB |= (1<<0);

PORTD &= ~((1<<6) | (1<<5));
}












int main(void)
{
motorInit(); //muss aufgrund der gegebenen Platine ausgeführt werden

uint16_t y;

DDRC |= (1<<3) | (1<<0);
DDRC &= ~(1<<1);
PORTC &= ~(1<<1);
timer_init();

while(1)
{

y=HC_SR04();
if(y<5)
{
PORTC |= (1<<3);
}
else
{
PORTC &= ~(1<<3);
}

_delay_ms(1000);
}
}

Ich hab denk ich alles durchprobiert und da schon einige Stunden dran geschwitzt ^^

würde mich sehr freuen, wenn mir jemand helfen kann!

Lukas

Hubert.G
03.08.2013, 12:52
Bist du sicher das die Rechnung nicht 0 ergibt?

return TCNT0*ps*(1/F_CPU)*ss*100;

1/F_CPU ergibt sicher 0 bei einem uint8_t

icebreaker
03.08.2013, 15:04
Erstmal vielen Dank für die Antwort!

ich hab jetzt nochmal probiert mich in die Formel reinzudenken.

dabei ist mir was aufgefallen.

der Timer läuft ja mit einer Frequenz von 16000000/1024 also 15625 Hz.
da es ja ein 8-bit timer ist kann er ja nur bis 256 Zählen.
also ist alle 256/15625te Sekunde ein Overflow. also alle 0,016384 Sekunden ein Overflow.
in der Zeit würde der Schall ja 0,016384*343m zurücklegen. also 5,6 m.
da er ja in der Zeit hin und zurück muss das ganze durch 2 also 2,8 m.
na das reicht ja sogar fürs erste^^



Ich hab jetzt als neue Formel.

(TCNT0*ps*ss)/(F_CPU*100)

und ich mach jetzt nen uint_16t draus..

- - - Aktualisiert - - -

Immer noch kein Erfolg..
weiterhin leuchtet die LED nur rot..

der Code ist jetzt:



#define F_CPU 16000000UL


#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>






#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
#define CR "\r\n"
#define ps 1024 //prescaler
#define ss 343.2 //sound speed




volatile uint16_t value;


void timer_init(void){
TCCR0|=(1<<CS02)|(1<<CS00);//prescale for timer 1024 @16MHz
}


uint16_t HC_SR04(void)
{
//generate a trigger signal
PORTC &= ~(1<<PC0);
_delay_us(1);
PORTC |= (1<<PC0);
_delay_us(10);
PORTC &= ~(1<<PC0);

while(!(PINC & (1<<PC1)))
{

}
//wait until echo pin be high
TCNT0=0;
while(PINC & (1<<PC1))
{

}


//count until echo pin be low

return (TCNT0*ps*ss)/(F_CPU*100);
}






void motorInit(void)
{
DDRD |= (1<<7) | (1<<6) | (1<<5);
DDRB |= (1<<0);

PORTD |= (1<<7);
PORTB |= (1<<0);

PORTD &= ~((1<<6) | (1<<5));
}












int main(void)
{
motorInit(); //muss aufgrund der gegebenen Platine ausgeführt werden

uint16_t y;

DDRC |= (1<<3) | (1<<0);
DDRC &= ~(1<<1);
PORTC &= ~(1<<1);
timer_init();

while(1)
{

y=HC_SR04();
if(y<5)
{
PORTC |= (1<<3);
}
else
{
PORTC &= ~(1<<3);
}

_delay_ms(1000);
}
}

Hubert.G
03.08.2013, 16:26
(TCNT0*ps*ss)/(F_CPU*100)

Meiner Meinung nach hast du hier ein paar Gedankenfehler. sehen wir uns die Brechung mal an, wie sie tatsächlich gerechnet wird.
1, (TCNT0*ps*ss) <-- hier hast du als Einheiten eine UNIT8 und 2 defines die max ein Uinteger sind, hiermit wird das Zwischenergebnis auch im besten Fall ein Uinteger.
Beispiel: TCNT0 kann max 255 sein. 255*1024*343.2= 89616384 ABER du hast nur einen Uinteger, hiermit Max 65535
Weiters ist ein define 343.2 ist auch gefährlich. Im Besten Fall macht er schneidet er das Nachkomma weg.

2, F_CPU*100 <- wird eine sehr große zahl 16*10^8

3, du rechnest 65535/ 16*10^8 <-- da kommt immer null bzw eine sehr kleine Kommazahl heraus die automatisch als null gilt.

Um sicher zu gehen, wurde ich die Rechnung mal aufteilen und die Zwischenwerte über UART ausgeben.

shedepe
04.08.2013, 20:02
Und als weiteren Hinweis würde ich dir empfehlen dazu Interrupts zu verwenden, damit du noch mehr Sachen parallel auf dem Controller machen kannst.

icebreaker
05.08.2013, 18:40
int main(void){
USART_Init(); // Initialise USART
sei(); // enable all interrupts
motorInit(); //muss aufgrund der gegebenen Platine ausgeführt werden

uint16_t y;

DDRC |= (1<<3) | (1<<0);
DDRC &= ~(1<<1);
PORTC &= ~(1<<1);
timer_init();

unsigned long v;
char v2[12];

while(1)
{
PORTC &= ~(1<<PC0);
_delay_us(1);
PORTC |= (1<<PC0);
_delay_us(10);
PORTC &= ~(1<<PC0);

while(!(PINC & (1<<PC1)))
{

}
//wait until echo pin be high
TCNT0=0;
while(PINC & (1<<PC1))
{

}


//count until echo pin be low



v=TCNT0;
sprintf( v2, "%d", v );
uart_puts( v2 );
uart_puts( "WERT" CR);

_delay_ms(500);
}
}

so sieht jetzt mein code aus..
und er gibt konstant 169 oder 170 aus..
warum ist mir zur zeit auch noch unerklärlich. eigentlich müsste er doch schon abstandsabhängig was ausgeben oder?

icebreaker
05.08.2013, 21:43
achso und ja mit interrupts werd ichs auch noch probiern, aber erst mal muss es so klappen (;

icebreaker
07.08.2013, 17:12
auf wundersame weise funktioniert es jetzt doch. ich hab eigentlich nichts geändert.

jedoch ist mir in der Formel noch ein grober fehler aufgefallen.
sie muss statt
(TCNT0*ps*ss)/(F_CPU*100)
(TCNT0*ps*ss*100)/(F_CPU*2)
heißen.
oder in meinem Fall jetzt gekürzt TCNT0*(625/686)

Ich möchte mich nochmal für die Hilfe insbesonders bei Hubert.G Bedanken!