Durchflussmesser an Atmega32

Gast #4632847
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?
Gast #4632868
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?
#4632877
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.
#4632898
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 ;)
Gast #4632899
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
Gast #4632904
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.
Gast #4632952
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????
Gast #4633006
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.
Gast #4633143
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.
#4633219
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.
#4633230
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.
Gast #4633373
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.
Gast #4633379
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
 }
Gast #4633536
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-.
Angehängte Dateien:
Gast #4633552
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.
#4633635
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.
#4633715
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.
#4633795
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.
Gast #4633897
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.
(Firma: Vescomp) #4634019
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.
Gast #4634111
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.
Gast #4634133
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.
Gast #4634510
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren