Hallo liebe Forumsgemeinde, ich bin ein ziemlicher Anfänger was AVR Programmierung anbelangt und stehe gerade vor einem Problem, bei dem ich eure Hilfe erhoffe. Ich verwende eine Atmega88-PU als Slave für einen Rasenroboter, dieser soll 6 verschiedene HC-SR04 Ultraschallsensoren nacheinander auswerten und danach außerdem die Drehzhal der beiden Antriebsmotoren erfassen und beide Infos an den Master (auch ein Atmega88-PU) via UART schicken, wenn dieser danach fragt. Kernproblem ist hier aber die Sensorauswertung. Der restliche Code muss erst noch geschrieben werden. jetzt wollte ich diesen so verwenden, das jeder Triggereingang einen PIN vom Atmega geschenkt bekommt, die Echo Leitungen aber über Dioden und Pull Down Widerstände zusammengefasst werden. ( Da es ja nur 3 wirkliche externe Interrupts gibt, Pin Change wollte ich Zwecks des "was ist nun für ein Zustand?" nicht verwenden ) Randbedingung ist außerdem, dass INT0 und INT1 nicht verfügbar sind, da an diesen die Drehzahl über Inkrementalgeber für die Motoren ermittelt werden sollen. Nun allgemein die Frage ob der Code so funktionieren könnte? Und eher zwei speziellere die das alles schon scheitern lassen könnten: 1) Was passiert, wenn der Timer 1 bereits schon läuft ( um die Messung für Sensor x nach ca 35ms zu unterbrechen und den nächsten Sensor x+1 zu triggern ), nun aber durch den Analogkomparator ein weiterer Start des Timer 1 ausgelöst wird? ( dieser soll die steigende Flanke und fallende Flanke des Echos erfassen ) Beginnt dieser einfach erneut bei 0 zu zählen oder zählt er gemütlich weiter? Oder geht das an sich nicht? 2) Kann man, so wie ich es momentan versuche, während der Ausführung der ISR für den Analogkomparator durch Triggerung und auftreten einer steigenden Flanke an AIN0 den Komparator während der ISR die Triggerung auf eine fallende Flanke umstellen, sodass damit eine Zeitenmessung möglich ist? Entschuldigung für die doofe Darstellung, ich weiß nur leider nicht wie ich den Code hier schöner einbinden könnte. Ich hoffe die Pfiffigen unter euch können und wollen mir Amateur helfen. :D Schon einmal vielen Dank an euch! Grüße Kevin
Hi, es war nicht leicht deinen Ausführungen zu folgen, aber ich versuche mal mein bestes. Deinen Code so anzusehen ist mir nicht wirklich gelungen. Warum hast du statt den ganzen png Dateien nicht einfach die Quellcode Datei angehängt? 1) Interrupts sind im laufenden Interrupt gesperrt es sei denn du gibst sie explizit frei. Tritt während eines laufenden Interrupts ein weiterer erfasst, wird dieser sofort bearbeitet, sobald der 1. abgearbeitet ist. 2) Hab ich nicht ganz verstanden, aber ich sag mal was. Du kannst doch wenn AIN0 auf eine steigende Flanke ausgelöst wurde einfach im Interrupt direkt umkonfigurieren, dass nun auf fallende Flanke regiert werden soll. Falls du den Flankenwechsel schneller erwartest, als ihn der der 16MHz getaktete AVR verarbeiten kann musst du den Controller wechseln. Halte ich aber für unwahrscheinlich.
Erstmal danke dir Dennis! Wie binde ich das denn als Quellcode ein? Ich probiere mal etwas:
1 | /*
|
2 | * Logik Rasenroboter.c
|
3 | *
|
4 | * Created: 10.04.2017 14:25:59
|
5 | * Author : kbuckena
|
6 | */
|
7 | |
8 | #include <avr/io.h> |
9 | #include <util/delay.h> |
10 | #include <stdio.h> |
11 | #include <stdlib.h> |
12 | #include <avr/interrupt.h> |
13 | #include <avr/iom88.h> |
14 | |
15 | #ifndef
|
16 | #define F_CPU 16000000UL; /* Zum Test noch auf 8000000UL*/ |
17 | #endif
|
18 | |
19 | #define _ECHO_ PD6;
|
20 | |
21 | uint16_t Umdrehung=0; |
22 | int i=0; |
23 | int x, Hindernis; |
24 | uint16_t Dauer; |
25 | |
26 | ISR(INT1){ |
27 | |
28 | Umdrehung++; // Wenn steigende Flanke, dann eine Umdrehung erreicht |
29 | |
30 | }
|
31 | |
32 | uint16_t Drehzahlerfassung(uint16_t *DRZ_1, uint16_t *DRZ_2, int *Richtung1, int *Richtung2){ |
33 | |
34 | // Timer0 für diese Messung verwenden, außerdem mit Overflow um die 8 Bit "virtuell zu vergrößern"
|
35 | |
36 | sei(); // Gloable Interrupts einschalten |
37 | |
38 | EICRA = (1<<ISC10) | (1<<ISC11); // steigende Flanke löst Interrupt an INT1 aus |
39 | |
40 | |
41 | }
|
42 | |
43 | int Sensorzuordnung(){ |
44 | |
45 | switch (i) |
46 | {
|
47 | // Sensor Vorn Rechts
|
48 | case 0: x= PB0; |
49 | break; |
50 | |
51 | // Sensor Vorn Links
|
52 | case 1: x=PB1; |
53 | break; |
54 | |
55 | // Sensor Hinten Rechts
|
56 | case 2: x=PB2; |
57 | break; |
58 | |
59 | // Sensor Hinten Links
|
60 | case 3: x=PB3; |
61 | break; |
62 | |
63 | // Sensor Vorn Unten
|
64 | case 4: x=PB4; |
65 | break; |
66 | |
67 | // Sensor Hinten Unten
|
68 | case 5: x=PB5; |
69 | break; |
70 | |
71 | }
|
72 | |
73 | return x; // anzusprechenden Sensor zurückgeben |
74 | }
|
75 | |
76 | int Gegenstandserkennung(int *Himmelsrichtung, int* Hindernis_da){ |
77 | |
78 | Sensorzuordnung(); |
79 | |
80 | ACSR = (1<<ACIE) | (1<<ACIC) ; // Enable Analog Komparator, bei Triggerevent Timer 1 auslösen |
81 | ACSR = (1<<ACIS1) | (1<<ACIS0); // Analog Komparatorauf steigender Flanke triggern |
82 | TCNT1 = 0; // Bei 0 loszäheln |
83 | |
84 | sei(); // Enable Globale Interrupt Flags |
85 | |
86 | while (i < 6 && Hindernis != 1) // solange nicht alle Sensoren durchgeschaut sind und kein Hindernis erkannt worden ist, Miss die Entfernung |
87 | {
|
88 | |
89 | PORTB &= ~(1<<x); // Sensor Initialisierung |
90 | _delay_us(3); |
91 | PORTB = (1<<x); |
92 | _delay_us(10); |
93 | PORTB &= ~(1<<x); |
94 | _delay_us(200); |
95 | |
96 | OCR1A = 8750; // 8750 Ticks sind bei 250kHz ca. 35ms, also der TOP Wert für kein Echo Empfangen |
97 | TCCR1B = (1<<CS11) | (1<<CS10); // Prescaler Timer 1 auf 64 setzen --> 250kHz und Timer 1 starten |
98 | // _delay_ms(35); ????
|
99 | |
100 | }
|
101 | |
102 | cli(); |
103 | ACSR = (1<<ACD); // Den Analog Komparator wieder ausschalten |
104 | i=0; |
105 | |
106 | *Himmelsrichtung = x; // Hier von sehen ob Vorn oder Hinten oder Mäher angehoben |
107 | *Hindernis_da = Hindernis; // es ist ein Hindernis da |
108 | |
109 | }
|
110 | |
111 | ISR(TIMER1_OVF_vect){ // Falls Zeit Überschritten und kein Echo, beginne wieder bei 0 zu zählen und mache beim nächsten Sensor weiter |
112 | |
113 | Dauer=0; |
114 | TCNT1 = 0; |
115 | TCCR1B &= ~(1<<CS11) // um Timer 1 auszuschalten |
116 | TCCR1B &= ~(1<<CS10) |
117 | i++; // zum nächsten Sensor schalten |
118 | |
119 | }
|
120 | |
121 | ISR(ANALOG_COMP_vect){ // Wenn nun Triggerflanke eintrifft |
122 | |
123 | if (ACIS0==1) // Falls noch auf steigende Flanke gestellt |
124 | {
|
125 | ACSR = (1<<ACIS1) | (0<<ACIS0); // Analog Komparator auf fallende Flanke triggern |
126 | TCNT1 = 0; // Trigger könnte ja kurz vor Overflow kommen, also Trigger "rücksetzen" und erst nach doppelter Dauer Overflow Interrupt auslösen |
127 | |
128 | }
|
129 | else{ |
130 | Dauer=TCNT1; // Dauer erhält hochgezählten Wert von Timer/Counter1 |
131 | Hindernis=1; |
132 | }
|
133 | |
134 | }
|
135 | |
136 | int main(void) |
137 | {
|
138 | uint16_t DRZ_1, DRZ_2; |
139 | int Himmelsrichtung, Hindernis_da, Richtung1, Richtung2; |
140 | DDRB = (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) | (1<<PB4) | (1<<PB5); // Sensorausgänge setzen |
141 | DDRD &= ~(1<<_ECHO_); // Echoeingang für Sensoren setzen |
142 | DDRD = (0<<PD4) | (0<<PD5); // Richtungseingänge für Drehrichtung setzen |
143 | |
144 | TCCR1B &= ~(1<<WGM13); // WGM13 auf 0 um Normal Mode, also keine PWM, auszuwählen ( Timer 1 ) |
145 | //TCCR0B &= ~(1<<WGM02); // WGM02 auf 0 um Normal Mode, also keine PWM, auszuwählen ( Timer 0 )
|
146 | TIMSK1 = (1<<OCIE1A); // Compare Match Interrupt für Timer 1 aktivieren |
147 | //TIMSK0 = (1<<OCIE0A); // Compare Match Interrupt für Timer 0 aktivieren
|
148 | |
149 | while (1) |
150 | {
|
151 | Gegenstandserkennung(&Himmelsrichtung, &Hindernis_da); |
152 | if (Hindernis_da==1) // Überhaupt Hindernis da? |
153 | {
|
154 | float Entfernung = (343*Dauer*0.000004)/2; // ( 343 m/s * Timer1 * 64/16MHz )/2 , da Echo hin und zurück und wir nur Hinweg haben wollen == Ergebnis in Meter |
155 | |
156 | |
157 | if (Entfernung<=0.08) // Hindernis 8cm vor mir? Wenn ja aber Hoppa und stehenbleiben! |
158 | {
|
159 | |
160 | if (Himmelsrichtung==0 || Himmelsrichtung==1) |
161 | {
|
162 | |
163 | //Sende via UART "Vorn"
|
164 | }
|
165 | |
166 | if (Himmelsrichtung==2 || Himmelsrichtung==3) |
167 | {
|
168 | //Sende via UART "Hinten"
|
169 | }
|
170 | |
171 | if (Himmelsrichtung==4 || Himmelsrichtung==5) |
172 | {
|
173 | // Sende via UART "Mähwerk aus"
|
174 | }
|
175 | }
|
176 | }
|
177 | else{ |
178 | |
179 | Drehzahlerfassung(&DRZ_1, &DRZ_2, &Richtung1, &Richtung2); |
180 | |
181 | }
|
182 | |
183 | |
184 | // Drehzahl aktuell senden
|
185 | |
186 | Hindernis=0; // Hindernis auf 0 zurücksetzen wenn in Gegenrichtung gefahren |
187 | |
188 | }
|
189 | }
|
Ich hoffe das hat so funktioniert! Schneller erwarte ich den Flankenwechsel keinesfalls. Ich möchte ja die Sensoren auf 8cm Entfernung Triggern, selbst mit Prescaler von 256 käme ich da auf eine so kurze Entfernung, die der HC SR04 schon gar nicht mehr erfassen kann. Zu 1) Also söllte es wohl so funktionieren oder? Zu 2)Sorry für die blöde Umschreibung. Also folgendes Szenario: Echo kommt an, da der Komparator auf steigende Flanke gestellt ist und der Timer 1 bereits läuft ( wird direkt nach der Triggerung des jeweiligen Sensors gestartet, um nach spätestens 35ms die Messung abzubrechen ( da kein Objekt in der Nähe ) und zum nächsten Sensor überzugehen) würde dieser den Timer 1 erneut starten, da ja das ACIC Bit gesetzt ist. Jetzt die Frage: startet der Timer einfach erneut von 0 an zu zählen oder macht dieser einfach ganz normal weiter oooder will der µC am Liebsten gar nichts von beiden tun und verweigert seine Arbeit? Nun weiter: Da jetzt eine Flanke kam wird die ISR für den Analog Komparator gestartet. Dieser schaut mit if(ACIS0==1), ob dieser noch auf die steigende Flanke eingestellt ist und wenn ja, soll dieser während der ISR auf die fallende Flanke umgestellt werden und den Timer mit TCNT1=0 von 0 an neu zählen lassen. Jetzt geht das ECHO auf LOW wodurch die ISR des Analog Komparators erneut ausgeführt wird, diesmal springt er aber in den else Zweig und übergibt den aktuellen Wert des Timers und setzt zusätzlich Hindernis=1, da sich etwas vor dem Sensor befindet. Danach wird alles dem Hauptprogramm übergeben, welches die Entfernung ausrechnet und bei einer Entfernung <= 8cm diese Information + die Richtung des Objektes, also Vorn oder Hinten, via UART an den Master schickt, welcher nun einen Bremsvorgang einleitet. Ich hoffe diese Beschreibung war etwas ausführlicher und hilft dir das ganze besser zu verstehen. Die Farge besteht nur noch, ob das ganze so funktioniert, wie ich es mir denke bzw geschrieben habe. Für weitere Hilfe würde ich mich weiter bedanken! :) Grüße Kevin
Zu 1) Ja das mit den Interrupts kann so funktionieren. Zu 2) Eine weitere Frage. Wenn du den Analog Comparator nutzt musst du ja beide Pins beschalten (AIN0 und AIN1). Ich denke es wäre einfacher über PCINT irgendeinen PIN zu nehmen und über EICRA (DB Seite 73) auf Interrupt bei "any logical change" zu konfigurieren. ACIC zählt ja nur hoch wenn auch Ereignisse am Analog Comparator auftreten. Wenn also die Flanke auf High wechelt zählt er einmal und das nächste mal wenn du ihn umkonfiguriert hast und er die fallende Flanke zählt. dein Ergebnis ist immer 2. Egal wie lange das dauert. Ich würde es so machen: Messung starten an SR04 - 1 Timer starten mit einem PCINT erfassen (kann auf steigend, fallend und any gesetzt werden) Wert aus Timer holen Wert speichern Timer stoppen Messung starten an SR04 - 2 ... ... ... Ich benutze den PCINT eigentlich sehr gerne: ISR(PCINT0_vect) // PC0 -> PCINT8 { char x=0,y=0; temp_old = temp; test(); x = temp; x &= 4; y = temp_old; y &= 4; if (!(x == y)) { if (x) { start0 = TCNT1; } if (!x) { stop0 = TCNT1; steer = stop0 - start0; } } } char test (void) { int_mask = PCMSK0; temp = PINB; temp &= int_mask; return temp; } Ein kleiner Code Ausschnitt um am PCINT festzustellen welcher Pin betätigt wurde macht die Funktion test(). Im Interrupt werte erfasse ich den Zählerstand des Timers und subtrahiere den Startwert vom Endwert (fallende - steigende Flanke). Ich finde das recht simpel. Kannst du dir ja mal überlegen.
Hallo Bastelgemeinde, Jetzt versuche ich gerade mehrere ( 6 Stück ) parallel laufen zu lassen. Die Auswertung eines Sensors über UART mit dem Atmega88p läuft 1A ( ohne Interrupts, nur über Pinzustände ). Nun frage ich mich aber, ob es einen "Pinsparenden" Weg gibt die Sensoren zusammen zu schalten? Getriggert werden muss einzeln ( oder vielleicht mit Schieberegister möglich ), jetzt habe ich aber versucht die ECHO Ausgänge zusammen zu schalten. Direkt zusammen kommt nur 0 cm raus, mit Dioden kommen wiederum nur schwankende und sehr hohe Werte heraus ( ca. doppelt so viel ). Anzumerken sei hierbei, dass beim anstecken des zweiten Sensors bei beiden Varianten immer noch nur Sensor 1 getriggert und ausgewertet wurde. Also nur das physische Anschließen des zweiten Sensors hat die Werte schon so sehr verändert. Kennt jemand einen einfachen Weg, wodurch ich die ECHO Ausgänge zusammenschalten kann? LG, Kevin
Hi Zur Not per Spannungsfolger, Inverter, OR-Gatter, Opto-Koppler, ... to be continue ... und per Dioden entkoppelt. MfG
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.