Forum: Mikrocontroller und Digitale Elektronik Durchflussmesser an Atmega32


von Tobias (Gast)


Lesenswert?

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?

von Dennis K. (scarfaceno1)


Lesenswert?

Das hängt alles vom Sensor ab...

Vielleicht mal ein Typ oder ein Datenblatt für uns?

von Tobias (Gast)


Angehängte Dateien:

Lesenswert?

hier das Datenblatt

von Dennis K. (scarfaceno1)


Lesenswert?

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.

von Tobias (Gast)


Lesenswert?

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?

von Rudolph (Gast)


Lesenswert?

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.

von Dennis K. (scarfaceno1)


Lesenswert?

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.

von M. K. (sylaina)


Lesenswert?

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 ;)

von Tobias (Gast)


Lesenswert?

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

von Tobias (Gast)


Lesenswert?

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.

von Tobias (Gast)


Lesenswert?

Fängt der Timer dann jedes mal beim Interrupt bei 0 an zu zählen oder 
muss ich den erst reseten?

von Pandur S. (jetztnicht)


Lesenswert?

Was sagt denn das Datenblatt zu diesem timermode ?

von Tobias (Gast)


Lesenswert?

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????

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


Lesenswert?

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.

: Bearbeitet durch User
von Rudolph (Gast)


Lesenswert?

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.

von Tobias (Gast)


Lesenswert?

Ja ich merke gerade dass mir beim Atmega32 einige Funktionen fehlen. 
Kann ich den Mega324PA einfach einsetzen ohne umlöten zu müssen?

von Karl (Gast)


Lesenswert?

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.

von Uwe J. (Firma: privat) (janoschik)


Lesenswert?

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

von Helmut L. (helmi1)


Lesenswert?

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.

von M. K. (sylaina)


Lesenswert?

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.

von Christian S. (solder)


Lesenswert?

Rudolph 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?

von Helmut L. (helmi1)


Lesenswert?

Christian S. schrieb:
> Was soll das denn heißen?

Das heist er sitzt beim CEO von Microchip auf dem Schoss und weiss 
alles.

von Rudolph (Gast)


Lesenswert?

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.

von grundschüler (Gast)


Lesenswert?

codebeispiel für atmega328:
1
dle_init(){
2
DDR(dle_port)&=~(1<< dle_pin);
3
PORT(dle_port)|=((1<< dle_pin));
4
PCICR |= (1 << PCIE(dle_int_port));//PCIntControlRegister
5
PCMSK(dle_int_port) |= (1<< dle_pin);
6
sei();
7
}
8
//--------------------------------------------------
9
10
ISR(dle_vect){
11
//760imps=>1l, 12,6imps/sec
12
dle_isr_imp++;
13
}
14
15
//--------------------------------------------------
16
17
isr_dle50_start(){
18
PCMSK(dle_int_port) |= (1 << dle_pin);
19
}
20
21
//--------------------------------------------------
22
23
isr_dle50_stop(){
24
PCMSK(dle_int_port) &=~(1 << dle_pin);
25
dle_l_hou=(dle_isr_imp*10+33)/66;
26
lg(4,7);li(dle_l_hou);lw("l");
27
dle_isr_imp=0;
28
}
29
30
//==================================================
31
//in der main:
32
33
34
if(sec==8){
35
    isr_dle50_start();
36
     }
37
    
38
    
39
if(sec==58){
40
    isr_dle50_stop();
41
 }

von Tobias (Gast)


Angehängte Dateien:

Lesenswert?

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-.

von Tobias (Gast)


Lesenswert?

gibt es irgendeine Möglichkeit zu testen ob der Interrupt überhaupt 
ausgelöst hat?

von Peter II (Gast)


Lesenswert?

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.

von Tobias (Gast)


Lesenswert?

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.

von M. K. (sylaina)


Lesenswert?

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
int main(void)
9
{
10
    setUpAvr();
11
    
12
    for(;;){
13
        /* insert your main loop code here */
14
        wdt_reset();
15
    }
16
    return 0;   /* never reached */
17
}
18
19
void setUpAvr(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
        } else if (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.

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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 aber

M. 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.

von M. K. (sylaina)


Lesenswert?

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.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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.

von M. K. (sylaina)


Lesenswert?

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.

: Bearbeitet durch User
von Tobias (Gast)


Lesenswert?

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.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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.

von grundschüler (Gast)


Lesenswert?

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.

von Wolfgang (Gast)


Lesenswert?

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.

von grundschüler (Gast)


Lesenswert?

um denb

Wolfgang schrieb:
> Wozu?

Fehlersuche. zuerst im Hauptprogramm, dann in der isr. Die Verzögerung, 
damit kurze Impulse per LED sichtbar werden.

von Tobias (Gast)


Lesenswert?

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?

von Tobias (Gast)


Lesenswert?

grundschüler schrieb:
> if(!(PINx<<piny)){

was bedeutet diese Zeile?

von c-hater (Gast)


Lesenswert?

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.

von grundschüler (Gast)


Lesenswert?

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.

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.