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.