Hallo zusammen.
Ich bräuchte Hilfe bei einem kleinen Projekt. Mit einem Durchflussmesser
möchte ich eine kleine Wasserpumpe überwachen ob sie noch genug
Pumpleistung bringt. Laut meiner Rechnung bringt der Durchflussmesser
ca. 22Impulse/s. Ich verlange jetzt keine komplette vorgekaute Lösung
aber ein paar Denkanstöße wären sehr hilfreich. Die geförderte
Wassermenge möchte ich dann mit einem LCD anzeigen. Wie kann ich jetzt
diese Impulse zählen um sie dann auszuwerten? Muss ich das Signal an
einem Pin mit ext. Interrupt anschließen oder an einem "normalen"
Eingang und diesen dann kontinuierlich abfragen und bei Änderung von 0
auf 1 einen Zähler laufen lassen?
Ich würde den Sensor wie in Schaltbild 2 (TTL Output) anschließen und
mit einem Pin Change Interrupt am µC zählen.
Also ja, an einem Pin mit Interrupt. Bei den AVRs haben mittlerweile
allerdings fast alle µC die Möglichkeit ein PCINT an jedem Pin
durchzuführen.
Ich habe Schaltbild 1 gewählt (simple circuit) und das Signal am PB2
(INT2) angeschlossen. Wird es so nicht funktionieren? Jeder
Flankenwechsel löst also einen Interrupt aus. Und wie messe ich dann die
Zeit zwischen zwei Interrupts?
Tobias schrieb:> Und wie messe ich dann die Zeit zwischen zwei Interrupts?
Stichwort Input-Capture, schau mal im Datenblatt, was man mit dem ICP1
Pin machen kann.
Tobias schrieb:> Ich habe Schaltbild 1 gewählt (simple circuit) und das Signal am PB2> (INT2) angeschlossen. Wird es so nicht funktionieren? Jeder> Flankenwechsel löst also einen Interrupt aus. Und wie messe ich dann die> Zeit zwischen zwei Interrupts?
Je nachdem wie du den Sensor versorgst, könnte hier die Spannung zu hoch
sein...
Du kannst auch mit einem Timer 1 Sekunde einstellen und dann zählen wie
viele Pulse in dieser Zeit kommen. Da du ja 22 Pulse pro sek maximal
erhältst ist die Zeit zwischen den Captures zu messen evtl mit mehr
Rechenaufwand verbunden.
Geht aber natürlich auch.
Tobias schrieb:> Muss ich das Signal an> einem Pin mit ext. Interrupt anschließen oder an einem "normalen"> Eingang und diesen dann kontinuierlich abfragen und bei Änderung von 0> auf 1 einen Zähler laufen lassen?
Ein externer Interrupt wäre eine Lösung, alternativ könntest du aber
auch einen Pin-Change-Interrupt benutzten. Beim Atmega32 sind die IOs
auf, ich glaube, drei Pin-Change-Interrupt-Gruppen aufgeteilt. Schau dir
dazu am besten mal das Datenblatt an.
Tobias schrieb:> Jeder> Flankenwechsel löst also einen Interrupt aus. Und wie messe ich dann die> Zeit zwischen zwei Interrupts?
Indem du umstellst und den Interrupt nur auf steigende oder fallende
Flanken sensitivierst. Die Zeit zwischen zwei Interrupts kannst du z.B.
mit einem Timer messen ;)
Dennis K. schrieb:> Je nachdem wie du den Sensor versorgst, könnte hier die Spannung zu hoch> sein...
Der Sensor hängt an den gleichen 5V wie der Controller
Mit Interrupts habe ich mich jetzt beschäftigt aber auf eine Lösung für
mein Problem bin ich leider immer noch nicht gekommen
M. K. schrieb:> Indem du umstellst und den Interrupt nur auf steigende oder fallende> Flanken sensitivierst. Die Zeit zwischen zwei Interrupts kannst du z.B.> mit einem Timer messen ;)
das heißt ich schreibe in den ISR einen Timer mit entsprechender
Frequenz, so das er nicht überläuft. Und wenn ich den Timer auslese
erhalte ich in abhängikeit der eingestellt Frequenz die Zeit für einen
Takt und kann dann auf Takte pro Minute umrechnen.
Also mein Lösungsansatz währe jetzt so:
Steigende Flanke am Eingang startet einen Interrupt
--> Inhalt der Variable "wert" auf Variable "Anzahl" übertragen und
anschließend "wert" auf 0 setzen, timer reset und timer starten
--> Mit einem Overflow Interrupt zähle ich mit "wert"++ die Anzahl
Überläufe
Wenn ich jetzt die Variable "Anzahl" mit 256 multipliziere und durch
die CPU Frequenz teile müsste ich doch die Zeit für einen Impuls
haben????
Man kann auch einen Timer/Counter vom Sensor takten lassen (Stichwort
'extern Clock') und z.B. jede Sekunde den Counterwert lesen und
zurücksetzen. Kostet zwei Timer/Counter aber läuft so gut wie von
alleine.
Rudolph schrieb:> Stichwort Input-Capture, schau mal im Datenblatt, was man mit dem ICP1> Pin machen kann.
...
Und mal so als allgemeiner Tipp, die AVRs sind zwar an sich ohnehin wohl
leider kurz vor Ihrem Ende, der Mega32 ist aber auch noch ein besonders
altes Exemplar der Familie.
Ein Mega324PA wäre ein Pin-kompatibler Ersatz mit etwas mehr
Möglichkeiten.
Tobias schrieb:> Kann ich den Mega324PA einfach einsetzen ohne umlöten zu müssen?Rudolph schrieb:> Ein Mega324PA wäre ein Pin-kompatibler Ersatz mit etwas mehr> Möglichkeiten.
Bei der geringen Frequenz des Signals kann man auch einen Timer aus z.B.
1 ms einstellen und einen bel. Pin pollen und beim wechsel von Low nach
HIGH einen Zähler hochsetzen. Das geht ohne Pin-Interupt.
Schau dir mal diese Projekt an sollte, Softwaretechnisch angepasst, eine
mögliche Lösung aufzeigen.
Beitrag "Genaue Ölmengenmessung Heizung"
Impuls lost Interupt aus dieser wird gezählt und mit dem Durchfluss pro
Impuls multipliziert. Das Ergebniss wird dann angezeigt.
Gruß
Janoschik
Man macht das mit dem Input Capture mode eines Timers. Wenn man die
ausloesende Flanke im Interrupt des Capture Ereignis umstellt bekommt
man sogar eine hoehere Messrate. Das einzige was man noch beachten muss
ist einen Timeout einzubauen der Erkennt oder der Sensor steht also
keine Pulse mehr kommen. Der Rest ist dann ein bisschen Rechnen, aber
das macht der uC gerne fuer einen.
Tobias schrieb:> das heißt ich schreibe in den ISR einen Timer mit entsprechender> Frequenz, so das er nicht überläuft. Und wenn ich den Timer auslese> erhalte ich in abhängikeit der eingestellt Frequenz die Zeit für einen> Takt und kann dann auf Takte pro Minute umrechnen.
So ähnlich.
Mein Ansatz wäre wohl so:
Pin-Change-Interrupt und Timer-Overflow-Interrupt einstellen, Variable
generieren, mit der die Timer-Overflows gezählt werden.
Warten auf den ersten Pin-Change-Interrupt, der startet den Timer.
Dann wartet man auf den zweiten Pin-Change-Interrupt.
Wenn der zweite Pin-Change-Interrupt kommt erfasst man den aktuellen
Timer-Wert inclusive aller Overflows und setzt die Zählvariable für
Overflows und den Timer-Counter auf 0 zurück. Im Hauptprogramm kann man
nun die Zeit ausrechnen lassen und zur Anzeige bringen oder was man
sonst damit machen will.
Man muss sich hier noch eine Abbruchbedingung überlegen, wie lange mal
also auf den zweiten Puls warten will. Es gibt ja sicher eine Zeit wo
das keinen Sinn mehr macht auf den zweiten Puls zu warten.
Christian S. schrieb:>> Und mal so als allgemeiner Tipp, die AVRs sind zwar an sich ohnehin wohl>> leider kurz vor Ihrem Ende,...>> Was soll das denn heißen?
Sorry, der Hinweis ist einfach Off-Topic.
Ich mache nur wenig Hoffnung auf weiter-Entwicklung der AVRs, nachdem
Atmel von Microchip übernommen wurde.
Es wird langsam Zeit, sich was anderes zu suchen, ich suche auch schon
länger, nur gefunden habe ich noch nichts mit dem ich die AVRs ersetzen
wollen würde.
Nur, Mega8/Mega16/Mega32 hatte ich vor >10 Jahren schon im Einsatz und
vor ich weiss nicht wie vielen Jahren durch Mega88PA/Mega164PA/Mega324PA
ersetzt.
Ich hab jetzt mal den Weg versucht über externen Interrupt einen Timer
zu starten und die Überläufe zu zählen bis die nächste Flanke kommt aber
es funktioniert nicht. Ohne Oszi ist es hald auch schwer zu sagen ober
überhaupt ein ordentliches Eingangssignal anliegt. Eigentlich müsste
doch die Variable hochzählen und dann von der if in die else schleife
gehen. Kann da mal jemand einen blick darauf werfen? Vielleicht fällt ja
nem Könner gleich was auf was nicht passt-.
Tobias schrieb:> Vielleicht fällt ja> nem Könner gleich was auf was nicht passt
ja.
> uint8_t anzahl = 5;
anzahl muss volatile sind.
Warum lässt du das Programm nicht einfach mal im Simulator laufen, dann
wüsstest du wenigsten ob die Software richtig ist.
Peter II schrieb:> Warum lässt du das Programm nicht einfach mal im Simulator laufen, dann> wüsstest du wenigsten ob die Software richtig ist.
im Simulator häng ich dann irgendwann in der while Schleife die den Text
auf LCD ausgibt. Ohne Signal dass den Interrupt auslöst komm ich da
nicht raus.
Hier mal ein Beispiel von mir. Ausgewertet wurde hier ein Tachosignal
und je nach Geschwindigkeit wird hier eine Wicklung eines EMotors
umgeschaltet (für größeren Speed ;)).
1
/* Name: main.c
2
* Author: Michael Koehler
3
*/
4
5
#include"main.h"
6
#include<avr/wdt.h>
7
8
intmain(void)
9
{
10
setUpAvr();
11
12
for(;;){
13
/* insert your main loop code here */
14
wdt_reset();
15
}
16
return0;/* never reached */
17
}
18
19
voidsetUpAvr(void){
20
/* insert your hardware initialization here */
21
// output set
22
DDRB|=(1<<PB1);
23
// int0 set
24
// int0 interrupt at rising edge
25
MCUCR|=(1<<ISC01)|(1<<ISC00);
26
// int0 interrupt on
27
GIMSK|=(1<<INT0);
28
// timer1 overflow interrupt
29
TIMSK|=(1<<TOIE1);
30
// watchdog
31
wdt_enable(WDTO_60MS);
32
wdt_reset();
33
// enable interrupts
34
sei();
35
}
36
37
ISR(INT0_vect){
38
if(TCNT1==0){
39
//start timer
40
TCCR1|=(1<<CS13)|(1<<CS10);
41
}else{
42
if(TCNT1<144){
43
PORTB|=(1<<PB1);
44
}elseif(TCNT1>164){
45
PORTB&=~(1<<PB1);
46
}
47
TCNT1=0;
48
49
}
50
}
51
ISR(TIMER1_OVF_vect){
52
PORTB&=~(1<<PB1);
53
TCCR1&=~((1<<CS13)|(1<<CS10));
54
TCNT1=0;
55
}
Ich hab zwar mit INT0 hier gearbeitet, das geht aber genauso mit
beliebigen PC-Interrupt. Bei mir kam/kommt ein ATTiny85 mit 1 MHz Takt
zum Einsatz, nicht weil er perfekt dafür geeignet ist sondern weil das
mein Standard-8-Pin-AVR ist von dem ich noch um die zehn Stück in der
Schublade hab.
Tobias schrieb:> Ich hab jetzt mal den Weg versucht über externen Interrupt einen Timer> zu starten und die Überläufe zu zählen bis die nächste Flanke kommt aberM. K. schrieb:> Hier mal ein Beispiel von mir.
Wie kommt Ihr alle auf steigende Flanke ?
Soviel ich sehe, ist es die fallende Flanke, weil Vcc im Ruhezustand.
Marc V. schrieb:> Soviel ich sehe, ist es die fallende Flanke, weil Vcc im Ruhezustand.
hö,
1. hab ich kein Pull-Up an und
2. macht
1
...
2
MCUCR|=(1<<ISC01)|(1<<ISC00);
3
...
das Ganze auf eine steigende Flanke sensitiv (Datasheet ATTiny85, Page
51).
Wie du da jetzt darauf kommst, es sei auf fallende Flanke sensitiv
versteh ich grade nicht.
M. K. schrieb:> Wie du da jetzt darauf kommst, es sei auf fallende Flanke sensitiv> versteh ich grade nicht.
Weil im Datenblatt vom Hersteller ein OC Ausgang mit Pullup nach
VCC eingezeichnet ist.
Da ist es für mich logisch auf fallende und nicht auf steigende
Flanke zu reagieren.
Ihr könnt das natürlich machen wie es euch beliebt.
Marc V. schrieb:> Weil im Datenblatt vom Hersteller ein OC Ausgang mit Pullup nach> VCC eingezeichnet ist.
Den Pull-Up musst du aber einschalten was ich, wie man auch oben sehen
kann, nicht mache. Ohne das ist der Eingang unbestimmt (kann High oder
Low sein). Da der Drehzahlgeber den Eingang bei mir eh auf GND zieht und
nur 12V Pulse bei drehenden Rad ausgibt ist es gar nicht so verkehrt auf
eine steigende Flanke zu reagieren.
Und für eine Pulsfolge von einem Drehzahlgeber ist es idR auch völlig
egal ob man auf steigende oder fallende Flanken reagiert da die Pulse
und Pausen idR immer gleich lang sind.
M. K. schrieb:> Hier mal ein Beispiel von mir. Ausgewertet wurde hier ein Tachosignal> und je nach Geschwindigkeit wird hier eine Wicklung eines EMotors> umgeschaltet (für größeren Speed ;)).
Vielen Dank für das Beispiel. Ich glaube mein Problem ist momentan
einfach das, dass ich den INT2 nicht zum laufen bringen. Laut Datenblatt
gibt es ihn zwar und man kann über GICR auch die Bits dafür setzen aber
bei MCUCR tauchen dann nur noch bits für INT0 und INT1 auf. Ich lese das
Datenblatt jetzt zum x-ten mal aber ich werd nicht schlauer und INT1 und
0 sind bei mir leider schon durch das LCD belegt.
Tobias schrieb:> einfach das, dass ich den INT2 nicht zum laufen bringen. Laut Datenblatt> gibt es ihn zwar und man kann über GICR auch die Bits dafür setzen aber> bei MCUCR tauchen dann nur noch bits für INT0 und INT1 auf. Ich lese das> Datenblatt jetzt zum x-ten mal aber ich werd nicht schlauer und INT1 und> 0 sind bei mir leider schon durch das LCD belegt.
MCUCSR ist für INT2 zuständig
MCUCSR |= (1<<ISC2) = INT2 auf steigende Flanke
GICR |= (1<<INT2) = INT2 aktivieren.
Fang mal damit an, den pin abzufragen, ob überhaupt ein Signal ankommt,
danach den interrupt aktivieren:
if(!(PINx<<piny)){
led_on;_delay_ms(50);
}
else
{
led_off;
}
Müsste im Takt der Sensorimpulse blinken.
grundschüler schrieb:> Fang mal damit an, den pin abzufragen, ob überhaupt ein Signal ankommt,> danach den interrupt aktivieren:
Wozu? Wenn kein Signal kommt, kommt kein Interrupt.
Das Aktiveren des Interrupts kosten einen nichts und eine LED kann man
auch im Interrupt tooglen, ohne mit einem Delay() den Prozessor lahm zu
legen.
Also vielen Dank für die vielen antworten. Wird ich gleich mal
ausprobieren. Jetzt noch ne doofe Frage: Den Eingang an dem das Signal
ankommt, muss ich den auf high oder low setzen?
Tobias schrieb:> Jetzt noch ne doofe Frage: Den Eingang an dem das Signal> ankommt, muss ich den auf high oder low setzen?
Klare Antwort: weder noch.
Ggf. könnte es allerdings sinnvoll sein, dem Eingang einen PullUp- oder
PullDown-Widerstand zu verpassen, das hängt von der Signalquelle ab.
Und wenn es ein PullUp sein muss und dafür der eingebaute PullUp eines
AVR verwendet werden kann, ja dann könnte es sinnvoll sein, das
entsprechende Bit des Portregisters auf High zu setzen, weil das nämlich
eben diesen PullUp aktiviert. Jedenfalls so lange das entsprechende Bit
im zuständigen DDR-Register Low bleibt, der Pin also als Eingang
konfiguriert bleibt.
Tobias schrieb:> grundschüler schrieb:>> if(!(PINx<<piny)){>> was bedeutet diese Zeile?
du fragst das PIN-Register ab ob der enstsrechende Pin low ist. Muss
allerdings dann
>> if(!(PIN(x)&(1<<y))){
heißen.