Forum: Mikrocontroller und Digitale Elektronik Ultraschallmessung, Atmega8 resettet sich


von Niine (Gast)


Lesenswert?

Hi,

ich habe leider ein Problem. Ich möchte ein Ultraschallsensor HC-SR04 
ansteuern. Man muss ihm ein 10 us High Signal geben und nach der Messung 
sendet er ein Abstandsabhängiges (Zeitlänge) High Signal auf dem Echo 
Kanal zurück.

Nun wollte ich bei einer Messung einen schnellen Timer starten und 
sobald das High Signal anliegt die Dauer messen und wenn es vorbei ist, 
den Counter auswerten, damit ich die Zeitdauer habe.

Allerdings stürzt der Atmega dann irgendwie ab. Er bringt die Test1 und 
Test2 auf dem Display und dann wieder Test1. Schafft er es von der 
Geschwindigkeit irgendwie nicht und stürzt deswegen ab?

Auffallend ist noch, das die eig 300ms zwischen Test1/Test2 viel mehr 
ist. Die Frequenz von 8Mhz hab ich bei Symbols im Projektmenü im 
AtmelStudio eingestellt.

Hier mein Code:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
#include <stdbool.h>
5
#include "lcd-routines.h"
6
7
#define triggeraus PORTB &= ~(1 << PB2)
8
#define triggeran PORTB |= (1 << PB2)
9
10
int counter=0;
11
int first = 0;
12
int lastValue=0;
13
int messen = 0;
14
  
15
ISR(TIMER0_COMPA_vect) //Timer alle 5 Mikrosekunden!
16
{
17
  if(first==0) 
18
  {
19
    if(bit_is_set(PINB,1)) {counter++; first = 1;} else { counter=0;}
20
  }
21
  else
22
  {
23
    if(bit_is_set(PINB,1)) {counter++;} else { lastValue=counter; counter=0; first = 0; messen = 0; TIMSK = (0<<OCIE1A);}
24
  }
25
26
}
27
28
int Ausgabe(int value) 
29
{
30
  lcd_clear();
31
  char Buffer[20];
32
  
33
  lcd_string("Distanz: "); //Ausgabe als String
34
  itoa( value, Buffer , 10 );
35
  lcd_string(Buffer);
36
}  
37
  
38
int getAbstand()
39
{
40
  int cm=0;
41
  
42
  triggeraus;
43
  _delay_us(2);
44
  triggeran;
45
  _delay_us(10);
46
  triggeraus;
47
  messen = 1;
48
  TIMSK = (1<<OCIE1A);
49
  
50
  
51
  while(messen == 1) { }
52
  
53
  cm = lastValue*5 / 58;
54
  
55
  return cm;
56
}
57
58
int main(void)
59
{
60
    //Timer initialisieren
61
    TCCR1A = 0x00;
62
    TCCR1B = (1<<CS11);    //Prescaler 8, CTC-Mode
63
    OCR1A = 4;    //Vergleiswert setzten
64
    TIMSK = (0<<OCIE1A);  //OC-Interrupt aktivieren
65
    sei();
66
  
67
  DDRB |= _BV(PB2);
68
  DDRB &= ~_BV(PB1);
69
    
70
  PORTC &= ~_BV(PB2);
71
  PORTB|= _BV(PB1);
72
  
73
  lcd_init();
74
  lcd_string("Test1");
75
  _delay_ms(300);
76
  lcd_clear();
77
  lcd_string("Test2");  
78
  _delay_ms(300);
79
  lcd_clear();
80
    
81
    while(1)
82
    {
83
        //TODO:: Please write your application code 
84
    int abstand=0;
85
    
86
    abstand = getAbstand();
87
    
88
    Ausgabe(abstand);      
89
        
90
    _delay_ms(200);
91
  }
92
}

Danke für eure Hilfe.

Mit besten Grüßen

Niine

von Hubert G. (hubertg)


Lesenswert?

Deine Timer Initialisierung stimmt nicht. Es fehlt WGM12 im TCCR1B.
Im TIMSK das OCIE1A Bit zu löschen ist nicht sehr sinnvoll. Sollte eine 
ISR anstehen, wird sie sofort ausgeführt.
Besser wäre es den Timer zu stoppen.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Niine schrieb:
> Auffallend ist noch, das die eig 300ms zwischen Test1/Test2 viel mehr
> ist. Die Frequenz von 8Mhz hab ich bei Symbols im Projektmenü im
> AtmelStudio eingestellt.

Etwa 8-mal so viel? Dann solltest du dir mal anschauen, ob der MC vllt. 
noch im Auslieferzustand ist. In diesem Fall ist nämlich die CLKDIV Fuse 
gesetzt und der MC läuft mit 1 MHz statt mit 8.

> int counter=0;
Variablen, die auch in einer ISR geändert werden, solltest du immer als 
'volatile' angeben, damit der Compiler weiss, das sie benutzt werden. Im 
allgmeinen sind ISRs für den Compiler erstmal Unterroutinen, die nicht 
angesprungen werden.
Und dir ist klar, das 'int' eine 16-bit Variable ist? Wenn es das 
wirklich sein soll, musst du 'atomic' Zugriffe gestalten, da es sonst 
passieren kann, das die eine Hälfte der Variable bearbeitet wurde und 
dann ein Interrupt zuschlägt, wodurch die andere Hälfte (AVRs sind ja 
8-bitter) evtl. vermurkst wird.
Besser ist es, eindeutige Typen zu nehmen:
uint8_t ist immer ein Byte ohne Vorzeichen
uint16_t ein Word ohne Vorzeichen usw.

> Nun wollte ich bei einer Messung einen schnellen Timer starten und
> sobald das High Signal anliegt die Dauer messen und wenn es vorbei ist,
> den Counter auswerten, damit ich die Zeitdauer habe.

Schau dir dafür den Input Capture Modus an. Das scheint mir genau das zu 
sein, was du suchst.

> TCCR1A = 0x00;
>     TCCR1B = (1<<CS11);    //Prescaler 8, CTC-Mode
Nö, ist kein CTC Modus. Du startest einfach nur den Timer.

> ISR(TIMER0_COMPA_vect) //Timer alle 5 Mikrosekunden!
Du hast eine ISR für Timer 0 geschrieben, programmierst aber Timer 1. 
Das wird abstürzen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.