PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Eingänge ständig abfragen mit Bascom



Hans55
13.09.2007, 22:00
Hallo,
kann mir einer sagen, wie ich mit BascomAVR am besten ein paar Eingänge ständig abfrage und wenn dann einer betätigt wird soll ein Unterprogramm aufgerufen werden. So, dass keiner verloren geht wenn z.B. zwei Eingänge
kurz hintereinander betätigt werden.
z.B. Portd.0 , Portd.1, Portd.2 Portd.3
Wie macht man sowas?

Gruß Hans

chill-flo
13.09.2007, 22:05
Hey,
wie wäre es denn mit Interrupts dan musst du die Taster allerdings an die interrupt eingänge des avr's legen

Hans55
13.09.2007, 22:50
Geht das nicht auch ohne Interupt? Ich habs mit If..Then probiert, das geht zwar, aber wenn ich zwei Eingänge hintereinander betätige vergisst er einen.
Wenn man alles ganz langsam macht funktionierts, ist aber beschi.. so.

Dnerb
14.09.2007, 01:15
Poste Deinen Code, dann schauen wir mal was man verbessern kann. ;)

MeckPommER
14.09.2007, 09:48
Nun, ganz grob könnte ich mir das so vorstellen, ohne grade an Bascom zu sitzen:

Angenommen, du hast acht Taster an einem Port.
Dazu eine Byte-Variable, in die per Interrupt der Zustand
des Ports als Oder-Verknüpfung geschrieben wird. Die Oder-Verknüpfung deshalb, weil ein gedrückter Taster zwar ein ungesetztes Bit setzen soll, ein ungedrückter Taster soll aber ein gesetztes Bit nicht löschen, das sollen die entsprechenden Unterprogramme machen.

In der Hauptschleife deines Programms kannst du nun gemächlich die einzelnen Bits dieser Variablen abfragen und bei einer 1 (je nachdem, wie du die Taster beschaltet hast) das entsprechende Unterprogramm aufrufen.
Dieses Unterprogramme löscht nach Vollendung das entsprechende Bit.

Selbst wenn du nun alle Tasten auf einmal drückst, geht nix verloren.

Gruß MeckPommER

Hans55
15.09.2007, 08:50
Erst mal Danke alle zusammen!
Ich muss mir zuerst das mit den Interrupts durchlesen und ausprobieren, das hört sich nämlich gut an. Bisher hatte ich es so wie unten. Probiert hab ichs auch mit If..Then usw.
Das ging zwar alles so lala, aber eben nicht gescheid. Wenn man schnell hintereinander die Taste betätigt kriegt er oft garnix mit.
Das ganze schaut so aus:
Gruß
Hans

-AVR 8515 und STK200 Board.
-LCD Display

'///// INITIALISIERUNG //////
$regfile = "8515def.dat"
$crystal = 4000000
Config Lcd = 20 * 4
Config Lcdmode = Port
Config Lcdbus = 4
Config Lcdpin = Pin , Db4 = Portc.4 , Db5 = Portc.5 , Db6 = Portc.6
Config Lcdpin = Pin , Db7 = Portc.7 , E = Portc.3 , Rs = Portc.2

Config Portd = Input
Config Portb = Output

Set Portb.0
Set Portb.1
Set Portb.2
Set Portb.3
Set Portb.4
Set Portb.5
Set Portb.6
Set Portb.7
Cls

'///// HAUPTPROGRAMM ///////
Do
Debounce Pind.0 , 0 , Taste0 , Sub
Debounce Pind.1 , 0 , Taste1 , Sub
Debounce Pind.2 , 0 , Taste2 , Sub
Loop

'---------------------------------------------------------
Taste0:
---------------------------------------------------------
Cls
Waitms 1000
Lcd "Das war Taste0"
Waitms 1000
....
Return

usw...


'///// Unterprogramme /////

END

Hans55
15.09.2007, 22:02
Wenn ich z.B. 5 Taster abfragen will und der AT908515 nur zwei Interrupt -Pins INT0 und INT1 hat. Was dann?
Dann müsste ich doch von jedem Taster noch eine Leitung abzweigen und damit auf ein Externes ODER gehen (evtl. reichen auch 5 Dioden) und vom Ausgang des ODERs dann auf den INT0- Eingang des AVR.

Wenn jetzt irgend ein Eingang betätigt wird, dann gibts einen INTERRUPT an INT0 (PD2) und ich kann die Interruptroutine aufrufen.

In der INTR Routine lese ich dann die Eingänge ein und schaue nach, wer von denen auf "1" war. Ist das so richtig?

Hat jemand eine Idee obs auch ohne die externe Schaltung geht?
Wie würde das mit der Interruptroutine dann ausschauen?
Hat mal jemand ein paar Codezeilen?

Danke nochmal Hans55

MeckPommER
15.09.2007, 22:31
Ich glaube, du hast mich nicht richtig verstanden.

Die Taster sind alle an einem normalen Port. Ein Interrupt, der z.B. alle 10 Millisekunden ausgeführt wird, springt in ein Unterprogramm, in dem die gesetzten Bits in eine Variable übergeben werden.
HIER kommt dann eine logische Oder-Verknüpfung, da die bisher gesetzten Bits in der Variable bleiben und nur die per Tasten hinzugekommenen eingetragen werden sollen.

Hans55
16.09.2007, 09:43
Hallo Meckpommer,
als Anfänger mit Bascom (und über 55) hat man schon so seine Probleme. Ich finde ja nicht mal einen Befehl wie OR oder AND um auf die schnelle vergleichen zu können, welcher Eingang sich geändert hat. Vermutlich gibts den in Bascom nicht. Das alles ist vermutlich auch so einfach, dass man in keinem Forum was findet.
Naja, dann heißt das eben weiterforschen.
Gruß Hans55

linux_80
16.09.2007, 12:45
Hallo,

die Operatoren sind gut versteckt auf dieser Seite zu finden,
http://avrhelp.mcselec.com/language_fundamentals.htm
auch in der lokalen Hilfe.

Wenn soviele Taster auf einmal abgefragt werden sollen, und alle an einem Port sind (wenn nicht müssen die halt alle an einen ;-) ), kann man doch den ganzen Port auf einmal ein lesen, und dann nur vergleichen,
ob der Wert grösser 0 ist, wenn die Taster nach Vcc schalten,
oder kleiner 255 wenn die nach Gnd schalten.
Danach kann man immer noch die einzelnen Werte raussuchen, um den richtigen Taster zu finden.

Hans55
16.09.2007, 12:56
Ja, Danke!
Ich hab inzwischen die Logischen Operatoren gefunden und ausprobiert.
Genauso werd ich das auch versuchen.

Hans55
16.09.2007, 13:17
Noch eine dämliche Frage?
Warum wird mir am LCD nichts angezeigt, wenn ich eine Taste drücke?
Unten bei LCD Eingang
oder LCD PortD
Müßte da nicht eine 2 kommen, wenn ich die Taste 1 betätige?


$regfile = "8515def.dat"
$crystal = 4000000
Config Lcd = 20 * 4
Config Lcdmode = Port
Config Lcdbus = 4
Config Lcdpin = Pin , Db4 = Portc.4 , Db5 = Portc.5 , Db6 = Portc.6
Config Lcdpin = Pin , Db7 = Portc.7 , E = Portc.3 , Rs = Portc.2
Baud = 9600

'--- Definitionen
Dim A As Byte
Dim B As Byte
Dim C As Byte
Dim Eingang As Byte

'-- PortD.0 bis PortD.7 als Input (Taste 0...7) konfigurieren
Config Portd = Input
Config Portb = Output

'-- Alle Leds ausschalten. Wegen pullup ist 0= eingeschaltet
Set Portb.0
Set Portb.1
Set Portb.2
Set Portb.3
Set Portb.4
Set Portb.5
Set Portb.6
Set Portb.7
Cls


Main:

Do
A = 10 And 2 'Ergebnis 2
B = 10 Or 2 'Ergebnis 10
C = 10 Xor 2 'Ergebnis 8

Cls
Locate 1 , 1
Lcd A
Waitms 500

Locate 2 , 1
Lcd B
Waitms 500

Locate 3 , 1
Lcd C
Waitms 500

' keine Anzeige wenn eine Taste gedrückt wird? Warum?

Eingang = Portd
Locate 4 , 1
Lcd Eingang
Lcd Portd

Wait 3
Loop
End

linux_80
16.09.2007, 14:03
Hi,

weil man die Eingänge an PinD einliest,
PortD ist für den Ausgang
:-$

Hans55
16.09.2007, 14:53
Danke!
Und schon gehts.
Gruß
Hans

Hans55
16.09.2007, 20:18
So schauts jetzt aus und es funktioniert.
Danke an alle die mir geholfen haben!


'///////////////////////////////////////////////////////////////////////////////
'Die Taster 0,1,2,3 abfragen
' STK200 mit AT90S8515 und LCD- Display an PortC
'///////////////////////////////////////////////////////////////////////////////
$regfile = "8515def.dat"
$crystal = 4000000
Config Lcd = 20 * 4
Config Lcdmode = Port
Config Lcdbus = 4
Config Lcdpin = Pin , Db4 = Portc.4 , Db5 = Portc.5 , Db6 = Portc.6
Config Lcdpin = Pin , Db7 = Portc.7 , E = Portc.3 , Rs = Portc.2
Baud = 9600
Config Portd = Input
Config Portb = Output
'-- Alle Leds ausschalten. Wegen pullup ist 0= eingeschaltet
Set Portb.0
Set Portb.1
Set Portb.2
Set Portb.3
Set Portb.4
Set Portb.5
Set Portb.6
Set Portb.7
Cls
'///////////////////////////////////////////////////////////////////////////////
'Achtung Eingänge mit PIND einlesen!
'Wenn keine Taste gedrückt=255 . d.h. 0 wenn keine Taste betätigt
' Das sind die Möglichkeiten bei 4 Tastern
' 0 0 0 0 = 255
' 0 0 0 1 = 254
' 0 0 1 0 = 253
' 0 0 1 1 = 252
' 0 1 0 0 = 251
' 0 1 0 1 = 250
' 0 1 1 0 = 249
' 0 1 1 1 = 248
' 1 0 0 0 = 247
' 1 0 0 1 = 246
' 1 0 1 0 = 245
' 1 0 1 1 = 244
' 1 1 0 0 = 243
' 1 1 0 1 = 242
' 1 1 1 0 = 241
' 1 1 1 1 = 240
'///// HAUPPROGRAMM /////////////////////////////////////////////////////////
Zustand_eingaenge:
Do
If Pind = 255 Then Goto Kein_eingang_angesprochen

Eingang_angesprochen:
If Pind = 254 Then Goto E0
If Pind = 253 Then Goto E1
If Pind = 251 Then Goto E2
If Pind = 247 Then Goto E3
If Pind = 252 Then Goto E0_e1
If Pind = 250 Then Goto E0_e2
If Pind = 249 Then Goto E1_e2
If Pind = 248 Then Goto E0_e1_e2
If Pind = 246 Then Goto E0_e3
If Pind = 245 Then Goto E1_e3
If Pind = 244 Then Goto E0_e1_e3
If Pind = 243 Then Goto E2_e3
If Pind = 242 Then Goto E0_e2_e3
If Pind = 241 Then Goto E1_e2_e3
If Pind = 240 Then Goto E0_e1_e2_e3

E0:
Cls
Locate 1 , 1
Lcd "Eingang 0"
Wait 2
Goto Zustand_eingaenge

E1:
Cls
Locate 1 , 1
Lcd "Eingang 1"
Wait 2
Goto Zustand_eingaenge

E2:
Cls
Locate 1 , 1
Lcd "Eingang 2"
Wait 2
Goto Zustand_eingaenge

E3:
Cls
Locate 1 , 1
Lcd "Eingang 3"
Wait 2
Goto Zustand_eingaenge

E0_e1:
Cls
Locate 1 , 1
Lcd "Eingang 0 / 1"
Wait 2
Goto Zustand_eingaenge

E0_e2:
Cls
Locate 1 , 1
Lcd "Eingang 0 / 2"
Wait 2
Goto Zustand_eingaenge

E1_e2:
Cls
Locate 1 , 1
Lcd "Eingang 1 / 2"
Wait 2
Goto Zustand_eingaenge

E0_e1_e2:
Cls
Locate 1 , 1
Lcd "Eingang 0 / 1 / 2"
Wait 2
Goto Zustand_eingaenge

E0_e3:
Cls
Locate 1 , 1
Lcd "Eingang 0 / 3"
Wait 2
Goto Zustand_eingaenge

E1_e3:
Cls
Locate 1 , 1
Lcd "Eingang 1 / 3"
Wait 2
Goto Zustand_eingaenge

E0_e1_e3:
Cls
Locate 1 , 1
Lcd "Eingang 0 / 1 / 3"
Wait 2
Goto Zustand_eingaenge

E2_e3:
Cls
Locate 1 , 1
Lcd "Eingang 2 / 3"
Wait 2
Goto Zustand_eingaenge

E0_e2_e3:
Cls
Locate 1 , 1
Lcd "Eingang 0 / 2 /3"
Wait 2
Goto Zustand_eingaenge

E1_e2_e3:
Cls
Locate 1 , 1
Lcd "Eingang 1 / 2 / 3"
Wait 2
Goto Zustand_eingaenge

E0_e1_e2_e3:
Cls
Locate 1 , 1
Lcd "Eingang 0 / 1 / 3 / 3"
Wait 2
Goto Zustand_eingaenge

'///// WENN KEIN EINGANG ANGESPROCHEN ////////////////////////////////
Kein_eingang_angesprochen:
Cls
Lcd "Alle Eingange sind 0"
Wait 1
Loop
' Weiter im Programm ......
End

chr-mt
17.09.2007, 08:16
Hi,
soll jetzt keine Kritik am Programm sein...
Alles was geht ist auch OK.

Aber es ist schöner, das zB. mit Gosub/Return oder Sub zu machen.
Das macht es etwas übersichtlicher, da die Haupschleife dann wesentlich kürzer ist.
Bei so kleinen Programmen ist das eigentlich Egal, aber wenn du einige hundert Zeilen hast, dann ist ein Loop am Ende schon etwas blöd. ;)

Des weiteren wird dein LCD ja jede Sekunde komplett gelöscht, wenn keine Taste gedrückt wird.
Das sieht unschön aus.
Du könntest ein Bit setzen, wenn die Anzeige einmal "Alle Eingänge sind 0" angezeigt hat und das dann auswerten.
Wenn eine Taste gedrückt wird, wird das Bit rückgesetzt.
Dadurch kommt beim loslassen der Taste nur einmal die Anzeige und ist dann bis zum nächsten Tastendruck gesperrt.

Gruß
Christopher

MeckPommER
17.09.2007, 13:56
Hallo Hans,

man freu sich ja als Anfänger über alles was funktioniert - ging mir auch nicht anders, und meine ersten Programme sahen echt erheblich schlimmer aus als deine ... :)

aber wie immer kann man einiges verbessern. ich glaube, dein programm funktioniert auch jetzt noch nicht optimal. wenn du eine taste drückst, und eine sekunde später eine andere, dann geht der tastendruck verloren, da das programm in der "wait 2" anweisung hängt.
desweiteren musst du alle möglichen kombinationen an tastern abfragen, was viel code bedeutet und bei einem evtl. hinzukommenden taster dann wirklich unübersichtlich wird.

hier aus dem bauch ein paar verbesserungen, ohne das getestet zu haben. ich sitze auch grade nicht an bascom, deswegen wirds sicherlich ein paar schreibfehler geben ;-)
einiges könnte man auch kürzer machen, aber ich schreibe einiges etwas ausführlicher und dabei leider auch umständlicher

$regfile = "8515def.dat"
$crystal = 4000000
Config Lcd = 20 * 4
Config Lcdmode = Port
Config Lcdbus = 4
Config Lcdpin = Pin , Db4 = Portc.4 , Db5 = Portc.5 , Db6 = Portc.6
Config Lcdpin = Pin , Db7 = Portc.7 , E = Portc.3 , Rs = Portc.2
Baud = 9600
Config Portd = Input
Config Portb = Output

'-- Alle Leds ausschalten. Wegen pullup ist 0= eingeschaltet
portb = 255
Cls

dim tasten as byte
tasten=255 'alle bits gesetzt. eine 0 bedeutet: taster gedrückt

'interrupt configurieren. wird ca. 60 mal pro sekunde ausgelöst
config timer0 = counter, prescale=256
on timer0 tastenlesen
enable interrupts

do
if tasten.0 = 0 then gosub t0
if tasten.1 = 0 then gosub t1
if tasten.2 = 0 then gosub t2
if tasten.3 = 0 then gosub t3
loop

t0:
'hier wird das gemacht, was taste 0 auslösen soll
...
tasten.0 = 1 'taste wieder als ungedrückt markieren
return

t1:
'hier wird das gemacht, was taste 1 auslösen soll
...
tasten.1 = 1 'taste wieder zurücksetzen
return

t2:
'hier wird das gemacht, was taste 2 auslösen soll
...
tasten.2 = 1 'taste wieder zurücksetzen
return

t3:
'hier wird das gemacht, was taste 3 auslösen soll
...
tasten.3 = 1 'taste wieder zurücksetzen
return

tastenlesen:
'interrupt-routine: wenn eine tasten gedrückt ist (=0) dann wird die null in der variablen "tasten" vermerkt
'da es per interrupt geschiet, braucht es nicht in der hauptschleife zu stehen und funktioniert auch während das programm irgendwo in einer wait anweisung hängt
if pind.0=0 then tasten.0 = 0
if pind.1=0 then tasten.1 = 0
if pind.2=0 then tasten.2 = 0
if pind.3=0 then tasten.3 = 0
return

Hans55
17.09.2007, 19:35
Danke für die Infos!
Ich werd das Progrämmchen gleich mal nach euren Angaben optimieren und ausprobieren.
Das von Meckpommer schaut gut aus, muss es aber erst mal einwirken lassen um es zu verstehen.
Gruß
Hans

Hans55
17.09.2007, 20:53
Hallo Meckpommer,
das mit den Interrupts funktioniert auch, wenn man
das ENABLE TIMER0 einfügt.
(Hab ich nach langer Sucherei im AVR-Buch Roland Walter gefunden)

So recht versteh ich's allerdings noch nicht warum das geht.

...
Config Timer0 = Timer , Prescale = 256
Enable Timer0 <=== Das hier fehlt meine ich
...
Alles Super, Danke!