PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Pin zählen, merken, vergleichen



Fehlzuender
26.02.2011, 15:34
Moin Moin,

mir fehlt auch nach mehreren Stunden suchen und googeln noch der richtige Denkansatz.
Hilft mir ein Profi auf die Sprünge?

Ich möchte mit BASCOM einen Atmega 8 programmieren.

An zwei Eingängen ist je ein Reed-Sensor angeschlossen.
Es gibt noch einen IO-Eingang und einen IO-Ausgang.

Das Programm soll die Anzahl der Magnete, die am Sensor 1 vorbeikommen zählen (etwa 60 Stück pro Sekunde, insgesamt pro Zählvorgang 70 Stück).

Als nächstes wird ein Pin auf eins gesetzt, worauf auch der Ausgang auf eins gesetzt werden soll.

Nun flitzen an Sensor 2 ebenfalls Magnete vorbei (auch ca. 60/sec).

Auch diese sollen gezählt werden. Wenn die an Sensor 1 gezählte Zahl an Sensor 2 erreicht ist, soll der Ausgang wieder auf 0 gesetzt werden.

War das verständlich?

Viele Grüße,
Johannes

TobiKa
26.02.2011, 15:51
Die Reed-Sensoren an Interrupt Eingänge und dementsprechend Variablen hochzählen.

021aet04
26.02.2011, 16:08
Du musst nur aufpassen dass diese Reedrelais nicht prellen. Sonst hast du zuviele Impulse. Besser wäre es, wenn du statt den Reedrelais einen Hallschalter nimmst. Diese brauchen keine Entprellung. Solltest du die Reedrelais trotzdem nehmen willst bzw musst würde ich das Signal entprellen.

Rest so wie schon geschrieben wurde.

MfG Hannes

Fehlzuender
26.02.2011, 17:01
Hallo,

danke für die Antworten. Mal sehen, vielleicht funktionierts auch mit einem Hallschalter. Um das Entprellen würde ich mich ja gerne drücken...

Könnte das hier funktionieren?


$regfile = "m8def.dat"
$crystal = 1000000

Config Pinb.1 = Input
Sensor1 Alias Pina.1
Config Pinb.2 = Input
Sensor2 Alias Pina.2
Config Pinb.3 = Input
Eingang Alias Portb.3
Config Portb.4 = Output
Ausgang Alias Portb.4

Dim A As Byte
Dim B As Byte
A = 0
B = 0

Do
If Sensor1 = 1 And Eingang = 0 Then
A = A + 1
End If
Loop Until Eingang = 1

If Eingang = 1 Then
B = B + 1
End If

If B = A Then
Ausgang = 0
End If

End

Über Verbesserungsvorschöäge freue ich mich,

Johannes

TobiKa
26.02.2011, 17:42
So auf keinen Fall.
So wird er A mehrfach hochzählen, während ein Magnet vorbeifährt. Und das hat mit entprellen noch garnichts zu tun.

Schau dir mal Interrupts an!

Das Entprellen kann man auch durch einen 100n Kerko, parallel zum Schalter, verhindern (tum Teil). Per Software lässt sich das aber auch leicht verhindern.

Fehlzuender
26.02.2011, 18:13
Hui, das geht hier ja fix mit euren Antworten! Danke dafür!

Hier ein neuer Versuch, diesmal mit Interrupts.
Habe ich das so richtig verstanden?


$regfile = "m8def.dat"
$crystal = 1000000

Config Pinb.3 = Input
Eingang Alias Portb.3
Config Portb.4 = Output
Ausgang Alias Portb.4

Dim A As Byte
Dim B As Byte
A = 0 'beim Start ist A=0 und B=0
B = 0

Config Int0 = Rising 'Interrupts reagieren auf steigende Flanke
Config Int1 = Rising
Enable Interrupts
Enable Int0 'Interrupts einschalten
Enable Int1
On Int0 Isr_von_int0
On Int1 Isr_von_int1


Do
If Eingang = 1 Then 'Wenn Eingang=1, dann Ausgang=1
Ausgang = 1
End If

If A = B Then 'Wenn A=B, dann Ausgang=0
Ausgang = 0
End If
Loop

Isr_von_int0: 'Zähle A hoch
Do
A = A + 1
Return

Isr_von_int1:
B = B + 1 'Zähle B hoch
Return


Am Ende erwartet Bascom laut Syntaxprüfung einen Loop. Warum?

Grüße,
Johannes

TobiKa
26.02.2011, 18:22
Loop brauch irgendeine Bedingung.

Sauerbruch
26.02.2011, 19:26
Am Ende erwartet Bascom laut Syntaxprüfung einen Loop. Warum?

Das könnte daran liegen, dass Du die ISR vom Int0 mit einem "Do" begonnen hast. Und für jedes Do will Bascom auch immer ein Loop sehen. In einer ISR brauchst Du aber kein Do/Loop.

Fehlzuender
26.02.2011, 19:56
Zitat:
Am Ende erwartet Bascom laut Syntaxprüfung einen Loop. Warum?


Das könnte daran liegen, dass Du die ISR vom Int0 mit einem "Do" begonnen hast. Und für jedes Do will Bascom auch immer ein Loop sehen. In einer ISR brauchst Du aber kein Do/Loop.


Ups stimmt, da hätte ich auch selbst drauf kommen können. Bin noch blutiger Anfänger...

E-Fan
27.02.2011, 16:56
Softwareseitig lässt sich der Eingang auch mit dem Befehl "debounce" entprellen.
Einen REED-Kontakt würd ich aber bei bis zu 60Hz nicht nehmen. Da wär ein Hallsensor wesentlich besser und prellfreier.



Isr_von_int0: 'Zähle A hoch

'A = A + 1 <- geht wesentlich einfacher
waitms 2 'Routine 2ms warten lassen
incr A 'Var A um eins erhöhen
Return

Fehlzuender
06.03.2011, 19:25
Danke, den Befehl "Incr" kannte ich noch nicht.
Ich muss das Programm mal auf einer Platine mit Hallsensoren testen,
in der Bascom-Simulation gibts noch Ungereimtheiten, der Ausgang geht nur an, wenn man den Eingang ein paar mal an und aus geschaltet hat...

Zwei Fragen noch:
1. Kennt Bascom kein "Or"?
2. Wenn ich "Debounce" einbauen will, muss das laut Hilfe in dem Hauptprogramm passieren. Wie bringe ich dann die jetzigen If..Then-Aufgaben des Hauptprogramms unter?

Hier der Code:



'------------------------------------------------------------------------------

$regfile = "m8def.dat"
$crystal = 1000000
$hwstack = 100

'--------- Ein- und Ausgaenge ------------------------------------------

Config Pinb.3 = Input
Eingang Alias Pinb.3
Config Portb.4 = Output
Ausgang Alias Portb.4


'--------- Variblen ---------------------------------------------------

Dim A As Byte 'Klemmer
Dim B As Byte 'Korb

A = 0 'Startwerte
B = 0

'--------- LCD --------------------------------------------------------

Config Lcd = 16 * 2
Config Lcdpin = Pin , Db4 = Portc.3 , Db5 = Portc.2 , Db6 = Portc.1 , Db7 = Portc.0 , E = Portc.4 , Rs = Portc.5
Config Lcdbus = 4

'-------- Interrupts --------------------------------------------------

Config Int0 = Rising 'Interrupts reagieren auf steigende Flanke
Config Int1 = Rising
Enable Interrupts
Enable Int0 'Interrups einschalten
Enable Int1
On Int0 Isr_von_int0
On Int1 Isr_von_int1

'-------- Hauptprogramm -----------------------------------------------

Main:
Do

If Eingang = 1 And B < A Then
Ausgang = 1
End If

If Eingang = 0 Then
Ausgang = 0
End If

If A <= B Then
Ausgang = 0
End If


Cls 'LCD
Locate 1 , 1
Lcd "Klemmer:"
Locate 1 , 10
Lcd A
Locate 2 , 1
Lcd "Korb:"
Locate 2 , 10
Lcd B

Loop

'--------- Interrupt-Routinen --------------------------------------------

Isr_von_int0:
Waitms 2 'Routine 2ms warten lassen
Incr A 'Var A um eins erhöhen
Return

Isr_von_int1:
Waitms 2 'Routine 2ms warten lassen
Incr B 'Var B um eins erhöhen
Return


Gruß,
Johannes

for_ro
06.03.2011, 21:07
Den Debounce Befehl setzt du zusätzlich in deine Do...Loop, z.B. an den Anfang oder ans Ende.
Die Schleife solltest du dir aber noch einmal ansehen. Die läuft im Moment vollkommen ungebremst durch. Dadurch wird etwa 25 mal pro Sekunde ein CLS und die Anzeige der Variablen A und B durchgeführt. Das ist bestimmt eine schöne Flimmerei.
Es würde sicherlich reichen, wenn du die ein paar mal pro Sekunde schreibst. Dazu würde ich allerdings auf das CLS verzichten.

Fehlzuender
06.03.2011, 22:53
Sorry, nochmal zum debouncen von Int0 und Int1:
Gebe ich im Debounce-Befehl das Label der ISR an? Ich dachte, wenn der Interrupt-Eingang High ist, wird sofort in die ISR gesprungen. Dann würde das debouncen doch überhaupt nicht beachtet?

Hier nochmal Schnipsel:


...
Enable Interrupts
Enable Int0 'Interrups einschalten
Enable Int1
On Int0 Isr_von_int0
On Int1 Isr_von_int1

'-------- Hauptprogramm -----------------------------------------------

Main:
Do

Debounce Int0 , 1 , Isr_von_int0
Debounce Int1 , 1 , Isr_von_int1

If BlaBla
Loop

'--------- Interrupt-Routinen --------------------------------------------

Isr_von_int0:
Bla Bla
Return

Isr_von_int1:
Blabla
Return

for_ro
06.03.2011, 23:55
Natürlich kennt Bascom die OR Verknüpfung.
Darüber hinaus auch ein Else im If ... Then ... Else ... End If. Also so:

If Eingang = 1 And B < A Then
Ausgang = 1
Else
Ausgang = 0
End If

Dass hier müsste übrigens auch noch äquivalent sein:

If B < A Then
Ausgang = Eingang
Else
Ausgang = 0
End If

Nun zum Debounce. Ich hatte mir nicht den ganzen Thread durchgelesen, daher auch nur die übliche Verwendung des Debounce vorgeschlagen.
Wenn du über die externen Interrupts gehen willst, damit die Auswertung sicher sofort geschieht, könntest du verschiedene Wege gehen:
1. Bei Flankenwechsel des INT0 Pins wird die zugehörige ISR angesprungen. Dort könntest du den Debounce Befehl benutzen, um eine Sub aufzurufen, in der dann irgendeine Aktion ausgeführt wird. Allerdings scheint mir das etwas von hinten rum durchs Auge in die Brust zu sein. Hierbei ist noch zu bedenken, dass die Ausführung der Sub um eine gewisse Zeit verzögert wird, falls die Bedingung im Debounce Befehl erfüllt ist. Siehe dazu Config Debounce.
2. Die ISR wird wieder angesprungen, aber nun machst du die Auswertung selber. Selbst wenn der Kontakt jetzt noch prellt, die Aktion kannst du auf jeden Fall schon einmal ausführen. Das Prellen bewirkt aber, dass nach Beendigung der ISR diese sofort wieder aufgerufen wird. Um dies zu vermeiden, könntest du in der ISR einige ms warten und dann die zwischenzeitlich aufgetretenen Interrupt-Flags zu löschen. Damiet verhinderst du, dass die ISR durch das Prellen mehrfach aufgerufen wird. Warten in der ISR klingt zwar etwas frevelhaft, ist aber in diesem Fall ok. Es sei denn, dass du andere Arbeiten in deinem Programm hast, die durch das Warten gestört würden.
Debounce wird eigentlich verwendet, wenn man relativ oft den Pin abfragen kann.

Fehlzuender
19.03.2011, 18:03
Hallo zusammen,

ich bin mal wieder etwas ratlos.
Für die, die den bisherigen Thread nicht gelesen haben, noch mal kurz was mein Ziel ist:
Ein Atmega8 soll über einen Mosfet ein Magnetventil schalten, dieses wird erstmal nur durch eine Led simuliert.
An den Interrupt-Eingängen sind zwei Hallsensoren angeschlossen. Diese zählen die Variablen „Klemmer“ und „Korb“.

Außerdem gibt es zwei Eingänge: der Eingang "Messen" soll die Led auf Wunsch ausschalten, der Eingang "Var_reset" die Variablen bei Bedarf auf Null zurücksetzen.

Die Led soll leuchten, wenn "Messen" high ist, bis Korb = Klemmer ist.

Auf einem Display werden die Werte der Variablen angezeigt.

Folgende Probleme treten auf:
1. der Klemmer läßt sich nur hochzählen, wenn der Wert des Korbs höher als der des Klemmers ist. In der Anwendung muss aber der Klemmer erst gezählt werden, danach der Korb.
2. erreicht der Wert des Klemmers den des Korbs, werden beide Werte Null.
3. die Led leuchtet nicht wie sie soll dauerhaft, sondern geht nur kurz an, wenn der Klemmer ein Signal hatte.

Hat jemand eine Idee?
Hier der Code:

'------------------------------------------------------------------------------

$regfile = "m8def.dat"
$crystal = 1000000
$hwstack = 100

'--------- Ein- und Ausgaenge ------------------------------------------

Config Pind.5 = Input
Messen Alias Pind.5 'Eingang um den Messvorgang zu starten
Config Pind.6 = Input
Var_reset Alias Pind.6 'Eingang um die Variablen vor jeder Messung auf Null zu stellen
Config Portb.4 = Output
Led Alias Portb.4 'Led und Magnetventil


'--------- Variablen ---------------------------------------------------

Dim Klemmer As Byte 'Klemmer
Dim Korb As Byte 'Korb

Klemmer = 0 'Startwerte
Korb = 0

'--------- LCD --------------------------------------------------------

Config Lcd = 16 * 2
Config Lcdpin = Pin , Db4 = Portc.3 , Db5 = Portc.2 , Db6 = Portc.1 , Db7 = Portc.0 , E = Portc.4 , Rs = Portc.5
Config Lcdbus = 4

'-------- Interrupts --------------------------------------------------

Config Int0 = Falling 'Interrupts reagieren auf fallende Flanke
Config Int1 = Falling
Enable Interrupts
Enable Int0 'Interrupts einschalten
Enable Int1
On Int0 Isr_von_int0
On Int1 Isr_von_int1

'-------- LCD-Starttext ------------------------------------------------

Waitms 20
Locate 1 , 1
Lcd "Klemmer:"
Locate 2 , 10
Lcd Klemmer ; " "

Locate 2 , 1
Lcd "Korb:"
Locate 2 , 10
Lcd Korb ; " "


'-------- Hauptprogramm -----------------------------------------------

Main:
Do

If Var_reset = 1 Then 'setzt Variablen auf Null
Korb = 0
Klemmer = 0
Locate 1 , 10
Lcd Klemmer ; " "
Locate 2 , 10
Lcd Korb ; " "
End If

If Messen= 1 And Korb < Klemmer Then 'schaltet Led
Led = 1
Else
Led = 0
End If

Loop

'--------- Interrupt-Routinen --------------------------------------------

Isr_von_int0:

Waitms 2 'Routine 2ms warten lassen
Incr Klemmer 'Var Klemmer um eins erhöhen

Locate 1 , 10 'Variable auf LCD aktualisieren
Lcd Klemmer ; " "

Return


Isr_von_int1:

Waitms 2 'Routine 2ms warten lassen
Incr Korb 'Var Korb um eins erhöhen

Locate 2 , 10 'Variable auf LCD aktualisieren
Lcd Korb ; " "

ReturnPrellen ist bei den Sensoren erfreulicherweise überhaupt kein Problem. Es wird jedes Ereignis sauber erkannt und gezählt.

Vielen Dank in Voraus,
Johannes

Fehlzuender
19.03.2011, 21:23
Fehler gefunden! Habs oben im Code korrigiert.
War ein ganz simpler Fehler bei der Angabe von Ports.

Danke an alle die sich gedanken gemacht haben!
Johannes