Forum: Mikrocontroller und Digitale Elektronik Atmega32 und Mikroe distance meter 2 proto


von Fab (Gast)


Lesenswert?

Hallo liebe Microcontroller-Gemeinde!

Ich bin neu in dieser Welt und habe als Aufgabe, einen 
Ultraschall-Abstandsmesser über einen Atmega32 zum laufen zu bringen und 
die Distanz über LCD auszugeben. Leider habe ich schon aller versucht 
und stehe einfach an.
So bitte ich nun um Hilfe. Möglicherweise hat damit jemand Erfahrung der 
mir sagen kann warum das Programm nicht funktioniert.
Nachfolgend der Code. Wahrscheinlich nicht optimal und unschön, da schon 
zigamal neu geschrieben.
1
#define F_CPU 8000000UL
2
3
#include <util/delay.h>
4
#include <avr/io.h>
5
#include <stdint.h>
6
#include <time.h>
7
#include <stdlib.h>
8
#include <stdio.h>
9
#include <string.h>
10
#include <avr/interrupt.h>
11
12
using namespace std;
13
14
class LCD {
15
  private:
16
  void inline toggleEN();
17
  public:
18
  void init();
19
  void writeOut( char *);
20
  void command(char *);
21
  void printOut( char *);
22
};
23
24
25
void LCD::toggleEN() {
26
  PORTB |= (1<<3);
27
  _delay_us(50);
28
  PORTB &= ~(1<<3);
29
}
30
31
void LCD::printOut( char *printChar) {
32
  
33
  PORTB &= 0x0F;
34
  PORTB |= ((*printChar & 0xF0));
35
  this->toggleEN();
36
  _delay_ms(2);
37
  PORTB &= (0x0F);
38
  PORTB |= ((*printChar<<4));
39
  this->toggleEN();
40
  _delay_ms(2);
41
}
42
43
44
void LCD::command(char *cmd) {
45
  PORTB &= 0x00;
46
  this->printOut(cmd);
47
  _delay_ms(2);
48
}
49
50
void LCD::writeOut( char *str) {
51
  PORTB &= 0x00;
52
  PORTB |= (1<<2);
53
  int i = 0;
54
  int len = strlen(str);
55
  for (i = 0; i < len ; i++)  {
56
    this->printOut(&str[i]);
57
  }
58
}
59
60
void LCD::init() {
61
  DDRB = 0xFF;
62
  PORTB = 0x00;
63
  _delay_ms(15);
64
  PORTB |= (1<<4);
65
  PORTB |= (1<<5);
66
  this->toggleEN();
67
  _delay_ms(5);
68
  this->toggleEN();
69
  _delay_us(200);
70
  this->toggleEN();
71
  PORTB &= ~(1<<4);
72
  this->toggleEN();
73
  PORTB = 0x00;
74
  PORTB |= (1<<5);
75
  this->toggleEN();
76
  PORTB = 0x00;
77
  PORTB |= (1<<6);
78
  PORTB |= (1<<7);;
79
  this->toggleEN();
80
  _delay_us(40);
81
  PORTB = 0x00;
82
  this->toggleEN();
83
  PORTB |= (1<<6);
84
  PORTB |= (1<<7);
85
  this->toggleEN();
86
  _delay_us(40);
87
  PORTB = 0x00;
88
  this->toggleEN();
89
  PORTB |= (1<<4);
90
  this->toggleEN();
91
  _delay_us(40);
92
  _delay_ms(2);
93
  PORTB = 0x00;
94
  this->toggleEN();
95
  PORTB |= (1<<4);
96
  this->toggleEN();
97
  _delay_us(40);
98
  _delay_ms(2);
99
  PORTB = 0x00;
100
}
101
102
unsigned int timeMeasurementOFCounter = 0;
103
uint8_t pwmCounter = 0;
104
uint8_t adcVal = 0;
105
uint16_t timerVal = 0;
106
107
int main(void) {
108
  
109
  unsigned int distance = 0;
110
  
111
  //LCD
112
  LCD lcd;
113
  lcd.init();
114
115
  //ADC Init
116
  ADMUX = (1<<REFS0); // Voltage reference to AVCC
117
  ADCSRA |= ((1<<ADPS1) | (1<<ADPS2) | (1<<ADPS0));  //Prescaler (128)
118
  ADCSRA |= (1<<ADIE);  //activate Conversion complete interrupt
119
  ADMUX |= (1<<ADLAR);  // left adjust result
120
  //ADCSRA |= (1<<ADEN); //enable adc
121
  //ADCSRA |= (1<<ADSC); //start first conversion
122
  
123
  OCR2 = 155;
124
  
125
  sei();
126
  
127
  char clear = 0x02;
128
  
129
  //Enable interrupts (Overflow Timer2, Overflow Timer1, CompareMatchInterrupt Timer2)
130
  TIMSK |= (1<< TOIE2);
131
  TIMSK |= (1<<OCIE2);
132
  TIMSK |= (1<<TOIE1);
133
  
134
  //Init Timer2 (Fast PWM-Mode, no prescaler, non inverting mode, inverted Fast PWM PIN 3)
135
  TCCR2 |= (1<<COM21);
136
  TCCR2 |= (1<<WGM21);
137
  TCCR2 |= (1<<WGM20);
138
  DDRD |= (1<<PD7);
139
  DDRD |= (1<<PD3);
140
//  PORTD |= (1<<PD3);
141
  
142
  //Start PWM/Timer2
143
  TCCR2 |= (1<<CS20);
144
145
146
  
147
  while (true) {
148
    
149
    if(adcVal>100) {
150
      timerVal = TCNT1;
151
      distance = (int) ((double) 0.00214375 * timerVal); //Zeitberechnung: Schallgeschw. 343 m/s * 0,000000125 s (Zeit für einen Takt bei 8MHz) * 100 (für zentimeter) / 2 (für doppelten weg, hin und zurück) * timerVal (gemssene Takte)
152
      TCCR2 |= (1<<CS20);
153
      ADCSRA &= ~(1<<ADEN);
154
      TCCR1B &= ~(1<<CS10);
155
      TCNT1 = 0;      
156
    }
157
    
158
    else {
159
      distance = 0;
160
    }
161
    lcd.command(&clear);
162
    char temp[16];
163
    char text[16];
164
    dtostrf(distance, 3, 0, temp);
165
    sprintf(text, "Distance: %s cm", temp);
166
    lcd.writeOut(text);
167
    _delay_ms(300);
168
    
169
  }
170
}
171
172
ISR (TIMER1_OVF_vect) {
173
  pwmCounter = 0;
174
  TCCR2 |= (1<<CS20);
175
  ADCSRA &= ~(1<<ADEN);
176
}
177
178
ISR (TIMER2_OVF_vect) {
179
  TCNT2 = 55;
180
  PORTD ^= (1<<PD3);
181
}
182
183
ISR (TIMER2_COMP_vect) {
184
  pwmCounter++;
185
  if(pwmCounter == 4) {
186
    TCCR2 &= ~(1<<CS20);
187
    ADCSRA |= (1<<ADEN);
188
    ADCSRA |= (1<<ADSC);
189
    TCCR1B |= (1<<CS10);
190
    pwmCounter = 0;
191
  }
192
}
193
194
ISR (ADC_vect) {
195
  adcVal = ADCH;
196
}

Um das LCD Display braucht man sich nicht kümmern, das funktioniert.
Die PWM kommt raus und es kommt auch was an beim ADC.
Das Problem liegt an der Zeitmessung.
Leider hilft das  "Datenblatt" von Mikroe nicht wirklich weiter.
Wäre nett wenn vielleicht jemand helfen könnte.

von Stefan F. (Gast)


Lesenswert?

> einen Ultraschall-Abstandsmesser zum laufen zu bringen

Welchen?
Wie hast du ihn angeschlossen. Zeige deinen Schaltplan.

> Das Problem liegt an der Zeitmessung.

Geht es wesentlich konkreter?

Warum benutzt du einen ADC?

von Fab (Gast)


Lesenswert?

hi,
danke für die schnelle reaktion.
geht um den mikroe distance meter 2 proto.
schaltplan habe ich leider keinen, aber der distance meter hat 5 pins. 
GND, VCC, PWM-A-line, PWM-B-line und einen AN. PWM-A hängt am Atmega am 
PORTD PD7 und die PWM-B hängt am PORTD PD3. Durch die PWM wird ein 
Ultraschall-Signal abgesetzt, welches dann von einem Gegenstand 
reflektiert wird. Wenn dieses Signal wieder ankommt, wird es vom 
Distancemeter verstärkt und durch den AN-Pin an den atmega PORTA PA0 
geleitet. durche eine ständige ADC kann irgendwann festgestellt werden 
das sich der Wert erhöht (also etwas ankommt). Man muss die Zeitmessung 
beginnen wenn die PWM bei PD7 bzw. PD3 rausgeht. Sobald sich dann am ADC 
was tut stoppt man die Zeitmessung und kann dann die Distanz berechnen.
So hätte ich es mir zumindest gedacht.
Was genau das Problem bei der Zeitmessung ist kann ich nicht sagen, 
sonst wär ich wahrscheinlich schon einen Schritt weiter.
Bei der Schaltung an sich, bin ich mir zu 95 % sicher, dass sie stimmt. 
Hab auch eine LED-Bar dabei und da sieht man schön wenn ein Signal bei 
PA0 ankommt.
Hoffe das bringt ein bisschen mehr Klarheit.
grüße
Fab

von Stefan (Gast)


Lesenswert?


von void (Gast)


Lesenswert?

Fab, ich gehe jetzt einfach mal davon aus, dass deine Timer+Adc 
Kontrollorgie in den ISRs so richtig ist und periodisch der Sender 
aktiviert wird und passend der Timer gestartet.
Aber wie genau denkst du wird der Zeitpunkt des Empfangs mit dem Adc 
erkannt, wenn in der Hauptschleife vor dem Auslesen des timers TCNT1 
noch bis zu 300ms vergehen? (Das sollte so eine systematische 
Messungenauigkeit von +/-100m geben)
1
while (true) {
2
    if(adcVal>100) {
3
      timerVal = TCNT1;
4
       ... 
5
    }
6
   ... 
7
    _delay_ms(300);
8
  }

P.S.: Im von Stefan gefundenen Handbuch(Schaltplan) fällt übrigens der 
Satz:

"Concrete examples on how to measure distance using DistanceMeter 2 
PROTO, can be found on our website at
http://www.mikroe.com/eng/products/view/439/distance-meter-2-proto-board/
"

von Fab (Gast)


Lesenswert?

Danke für die rückmeldung.
Ok jetzt wo du sagst is das natürlich unsinn. Allerdings hatte ich es 
auch schon anders geschrieben. Zb bei jedem adc converion complete 
interrupt den TCNT1 abzufragen.
Hat auch nicht gepasst.
Bezüglich den link in der usermanual. Der is nicht mehr gültig bzw ist 
da nix mehr drinne.
Grüße
Fab

von Christian S. (roehrenvorheizer)


Lesenswert?

Hallo,

wichtig ist natürlich auch, möglichst genau die Resonanzfrequenz der 
Ultraschallwandler zu treffen, da deren Resonanzmaximum recht schmal 
ausfällt.

Dieses findet man am leichtesten durch Variation der Sendefrequenz und 
Beobachtung der Amplitude am Ausgang.

MfG

von Stefan (Gast)


Lesenswert?

Möglich das man diese Dinger zum
laufen bekommt. Ich benutze diese.

https://www.ebay.de/itm/HC-SR04-Ultraschall-Sensor-Modul-Entfernungsmesser-Arduino-Raspberry-Pi/252715059842?hash=item3ad6fdca82:g:M7cAAOSwWB5b4cDk:rk:1:pf:0

Sie funktionieren gut und die Programmierung ist auch
einfach.

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.