< schnellere >Tastenabfrage?

dg2ygq

Neues Mitglied
23. Juli 2007
239
0
0
Bielefeld
Sprachen
Ich hätte da mal wieder ein Progblemchen :
Main:
Do

Debounce Pind.0 , 0 , Senden , Sub
Debounce Pind.1 , 0 , Rauf , Sub
Debounce Pind.2 , 0 , Runter , Sub
Debounce Pind.7 , 0 , Memo , Sub

Loop

Rauf:

Kanal = Kanal + 1
If Kanal = 81 Then Kanal = 1
Gosub Leddisplay
Worda_frequency = Lookup(kanal , Efreq)
Gosub Ruhe

Return

Aus der Hauptschleife wird nach Rauf: gesprungen, sobald Taster an D1 geschlossen wird.
Nachdem der Zähler um einen erhöht wurde, gehts zur Displayanzeige und zum übertragen zum PLL-IC. Danach gehts zurück zum Main: .

Nun mein Problem: Das rauf- bzw auch runterschalten geht zu langsam. Wenn ich den Taster schnell bewege überspringt er den einen oder anderen Impuls.
Nun dachte ich mir, dass das PLL doch garnicht immer angesprochen werden muss, also wenn zb der Taster innerhalb von zB 200mS noch einmal gedrückt wird, würde es reichen wenn nur der Zähler und das Display weiter gehen, und nach diesen zB 200ms erst die Übertragung zum PLL stattfindet.

Wenn ich jetzt am Kanalschalter (Taster) drehe, komme ich auf ca 1,5 Kanäle pro sec, das ist fast ne Minute für alle Kanäle ... da bin ich ja mit dem Fahrrad schneller :rolleyes:

Nun versuchte ich in Rauf: eine Schleife zu setzen, wo ich nochmals PinD1 abfragte. Entweder das geht wirklich nicht, oder ich bekomme es nicht hin .

Wäre meine Überlegung soweit richtig?

Wie würdet ihr dieses Problem(chen) angehen ?
 
Hallo Michael,

um Dein Problem zu lösen muss man nur kreativ sein :eek: Du weisst ja, es gibt nichts in SW was es nicht gibt es is tnur eine Frage des Aufwandes (Zeit und Code) und des Ansatzes. Der Fantasie sind dabei keine Grenzen gesetzt.

Aus meiner Sicht kann ich Dir keine Patentlösung anbieten, ich denke da must Du Dir schon selbst überlegen was Du tun möchtest. Ja aber alleine stehen lassen möchte ich Dich auch nicht, also denken wir in gewohnter Form einfach mal wieder über ein paar Dinge nach.

Los gehts, mal sehen wo wir rauskommen: :)

Erst mal ein paar Worte zum Debounce. Der Debounce ist, werfen wir mal einen Blick in die Spec, eine kleine Eierlegende Wollmilchsau. Das Kommando ermöglicht Dir die Kombination von verschiedenen Methoden die Du üblicherweise bei Tasteneingaben von Hand programmieren müsstest.
Das ist zum Beispiel eine Methode zur Entprellung der Taste. Das ist beim Debounce so gelöst, das der Debounce nachsieht ob das von Dir gewünschte Ereignis auf dem PIN eingetroffen ist oder nicht. Wenn ja wartet Debounce 25ms (Achtung, hier entsteht Wartezeit) und schaut nochmals den PIN an. Wenn das Ereignis immer noch ansteht, dann nimmt Debounce an, dass es ein gewolltes und nicht zufälliges Ereignis war und löst die angegebene Routine aus.
So, es passiert aber noch mehr. Debounce überprüft gleichzeitig, ob der Pegel am PIN auch wieder zurück geht und die Taste wieder losgelassen wird. Das benötigt natürlich auch Zeit! Dies bedeutet, wenn Du eine Taste einmal drückst und gedrückt hältst dann wird die gewünschte Funktion die dahinter steht nur einmal ausgelöst.
Der Komfort den man sich mit Debounce einkauft geht zu Lasten von Rechenzeit und Code.

Was also tun?

Du kannst ohne große Probleme mit dem eindem Code wie
Code:
Taste1 Alias Pina.0                                     ' rauf
Taste2 Alias Pina.1                                   ' runter

' Tastaturabfrage Taste rauf heller
If Taste1 = 0 Then
   ' mache dieses
Else
   ' mache jenes
End If

Deine Tastenabfragen selber zusammenbauen. Bedeutet aber, das Ding kann prellen und das Schwingen der Kontakte wird als mehrfaches Betätigen ausgewertet. Auch der Dauerdruck wird bei jedem Mal wo der Code durchlaufen wird abgefragt und ausgewertet.

Im Gegensatz dazu bekommst Du Performance und bis schneller. Was Du dann in den einzelnen IF's machst beleibt Dir überlassen. Hier kann man schon auch Gosubs anspringen. Probiers doch einfach mal aus :D

Und weiter?

Wenn wir schon am optimieren und Laufzeit rausschinden sind probiers mal mit
Code:
Incr kanal
Ich bin mir sicht sicher wie toll BASCOM optimiert. Ich vermute für Incr kanal benötigst Du ein Maschinencode-Statement und für kanal = kanal + 1 ne ganze Batterie von. Das müsste man sich aber im Assembler mal genauer ansehen. Vermute aber mit Incr bist Du "viel" schneller. Übrigens, das Gegenteil zu Incr ist Decr.

So, was können wir noch tun. Wenn ich mich richtig erinnere dann hast Du einen 1.000.000 HZler, Richtig? Eine weitere Möglichkeit wäre, wenn Du auf einem STK500 arbeitest nicht den internen 1 MHz vom MEga zu nehmen sondern die knapp 4 MHz (3,xxxx) vom STK. Damit würde Dein Mega schon mal 4x so schnell laufen. Ich glaube der kann bis zu 8 MHz. Du könntest wenn extern aber auch auf dem STK500 dem Ding einfach einen 8 MHz Quarz stecken, die Fuses umhängen und schon rennt die Kiste mit 8 MHz und Du bis 8x so schnell. Da kommt Performance ins Silizium :)

Doch denken wir einfach witer nach .... hmmmm ...... was noch?

OK? Die Idee mit den 200ms und dann erst die PLL einstellen. Ja, kann mann machen ist möglich aber da Du nicht genau weißt wie lange die einzelnen Routinen laufen würde ich das ganze dann einfach entkoppel. Du könntest folgendes machen: Spendier einfach einen weiteren Timer der Dir alle 200ms oder 400ms oder 500ms einen Interrupt auslöst. In den rauf- und runter-Routinen machst Du nix anderes als die Kanal-Variable zu ändern.
In der Interrupt-Service-Routine könntest Du dann entweder en Flag für die Hauptschleife erzeugen oder direkt gleich dort die PLL programmieren. Damit hättest Du erst mal die Steuerung der PLL von der eigentlichen Tasteneingabe abgekoppelt.


Sicherlich gibt es noch x verschiedene andere Lösung. Schau Dir einfach die Themen mal an. Eine schönes Hausaufgabe wäre doch, die oben benannten Themen alle mal umzusetzen und auszuprobieren. Der Lerneffekt ist maximal und sicherlich kommst Du dann auch noch auf neue eigene Ideen die Du ausprobieren möchtest.

Außerdem mach es ja auch Spass und den wünsche ich Dir dabei!

Grüße,
Markus

PS: Bitte halte uns auf dem Laufenden wies bei Dir weiter geht :p
 
Entprellen ? Da hatte ich schon mal etwas :D

Abfrage:

sbis PIND, PD0 ;up
rjmp taste_pin0_gedrueckt
sbis PIND, PD1 ;down
rjmp taste_pin1_gedrueckt
sbis pind,pd2 ;scan
rjmp taste_pin2_gedrueckt
rjmp Abfrage

; Up *************************
taste_pin0_gedrueckt:

wdr
sbis pind,pd0
rjmp taste_pin0_gedrueckt

inc DisplayNumber
rcall LEDDisplay
rcall DecodePLLValue ;---
cpi DisplayNumber, 81
brlo abfrage ; solange DisplayNumber <81 dann weiter mit abfrage

ldi displaynumber,1 ; ansonsten DisplayNumber=1
rcall leddisplay
rcall DecodePLLValue

rjmp abfrage ; zurück

Klar, ist Assembler, aber was haltet ihr von dieser Methode?
Ist PD0 gedrückt, gehts in die Up_routine,
Dort gehts erst weiter, wenn PD0 nicht mehr gedrückt ist .....
In Basic würd ich in die Abfrage "If Then" basteln, und in die einzelnen Routinen mit Bitwait aufs Loslassen der Taste warten.

If - Then - Endif:
Muss ich nach jedem Pinabfragen Endif enbauen? Oder kann ich auch so:

If taste1 = 0 then ....
if taste2 = 0 then ....
If Taste3= 0 then ...
endif
?

Noch ein anderes Problem:
Da für RX und TX pro Kanal eine andere Frequenz gebraucht wird , hatte ich bis vorhin noch in der TX-Routine stehen :
- lookup die frequenz für tx aus Data
- schicke den wert zum PLL
- Warte bis TX-Taste losgelassen ist
- lookup die Frequenz für RX
- gehe zurück zur Tasta-Abfrage

Nun lese ich bei den Kanälen (Up / Down) gleich die beiden Werte in Verschiedene Variablen:

Rauf:

Incr Kanal
If Kanal = 81 Then Kanal = 1
Gosub Leddisplay
Frx= Lookup(kanal , Efreq)
Worda_frequency = Frx
Gosub Ruhe < ----- Hier gehts zur PLL-Routine
Ftx = Lookup(kanal , Tfreq) <----- Word für TX Frequenz einlesen und noch nix weiter damit tun
Return
Da "das auf Sendung gehen" auch sehr langsam ist, dachte ich mir den Wert für TX hier schon einmal in eine Variable zu holen, um den Befehl Lookup in der TX-Routine zu umgehen.
Senden:
Worda_frequency = Ftx <---- Ftx wurde bei UP/Down eingelesen
Portd.6 = 0 <----- Geräte Intern, damit das Gerät erst auf TX schaltet, wenn das PLL eingerastet hat 'ausgabe tx-data
Gosub Ruhe
Waitms 100
Portd.6 = 1 <--- hier sollte das PLL gerastet sein

'warte bis ptt los
Bitwait Pind.0 , Set

'übernehme rx-frequenz
Worda_frequency = Frx <---- Frx wurde bei UP/Down eingelesen

'ausgabe rx-freq.
Gosub Ruhe

Return

Das die UP/Down Funktion schon langsam ist, ist schon schlimm genug, aber zur TX-Umschaltung ist die Verzögerung noch schlimmer ....

Würdet ihr dort noch anders ansetzen ???

Ach, noch was Grundliegendes : Die FuseBits Int RC Osc 8Mhz ---- Bedeutet das wirklich dass der ATMega8515 intern mit 8Mhz arbeiten kann, ohne dass ich einen Quarz nehmen muss? Ich bin bis jetzt der Meinung dass ich für Frequenzen über 1 Mhz immer einen Externen Quarz/Osc anschließen muss ?!
 
Klar, ist Assembler, aber was haltet ihr von dieser Methode?
Ist PD0 gedrückt, gehts in die Up_routine,
Dort gehts erst weiter, wenn PD0 nicht mehr gedrückt ist .....
In Basic würd ich in die Abfrage "If Then" basteln, und in die einzelnen Routinen mit Bitwait aufs Loslassen der Taste warten.

Hallo Michael,

leider ist gerade mein Firefox abgestürzt, als ich den Beitrag fertig geschrieben hatte und nochmal ein Datenblatt ansehen wollte, ich muss mich jetzt beeilen und versuche mal schnell zu antworten.

In deinem Assemblerbeispiel erfolgt die zweite Tastenabfrage je nach fosc etwa nach 100ns bis 2us. Eine Taste kann jedoch bis Millisekunden prellen, die zweite Tastenabfrage wird somit keine Wirkung haben. Beim Entprellen muss man dafür sorgen, dass man auf eine Tasteneingabe erst dann reagiert, wenn sich für einige Zeit ein definierter Zustand des entsprechenden Portpins einstellt. Das heisst der Portpin muss zB mindestens 5ms low oder high sein.
Wenn du mit Bitwait solange wartest, bis sich der Zustand des Portpins ändert, kannst du in dieser Zeit keine anderen Programmbereiche in der selben Programmebene ausführen, Markus hatte das ja schon einmal erwähnt. Das muss nun für deine Applikation kein Nachteil sein, wenn das Display durch eine Interruptserviceroutine gemultiplext wird.

Übertragungsprotokoll:
Das Problem bei der Übertragung der Daten zum PLL sind die notwendigen Pausen, die deinen Programmablauf verzögern. Du könntest versuchen diese Pausen zu verringern, das wäre zumindest schnell zu realisieren. Ich halte dieses aber für keine sichere Lösung, da ja irgendwann die Daten nicht mehr richtig übernommen werden.
Eine andere Möglichkeit wäre die Programmbereiche Tastaturabfrage+Kanaländerung und Ubertragungsprotokoll in Programmebenen mit unterschiedlicher Priorität zu verlagern (Stickpunkt: Interrupts). Wenn Tastaturabfrage+Kanaländerung in einer Interruptserviceroutine behandelt wird und das Übertragungsprotokoll im Hauptprogramm ausgeführt wird, merkt man keine Verzögerung bei der Kanaländerung am Display. Allerdings kann es vorkommen, dass bei einer schnellen Kanaländerung das Übertragungsprotokoll nicht "mitkommt", das heisst die Übertragung der Daten läuft der Kanalanzeige ggf. nach.

Assembler und Bascom:
Ich hatte dir ja schon einmal in Assembler eine Tastaturabfrage (KeyboardManager) mit Entprellfunktion, Pausenfunktion und Wiederholfunktion geschrieben, vielleicht könnte man das in Bascom umsetzen, allerdings denke ich, dass Bascom hier schon fertige Lösungen bietet, Markus hatte da in anderen Beiträgen einiges dazu geschrieben. Ich würde an deiner Stelle auf jedenfall bei Bascom bleiben. Markus hatte hier auch schon das Übertragungsprotokoll erfolgreich realisiert.

Ach, noch was Grundliegendes : Die FuseBits Int RC Osc 8Mhz ---- Bedeutet das wirklich dass der ATMega8515 intern mit 8Mhz arbeiten kann, ohne dass ich einen Quarz nehmen muss? Ich bin bis jetzt der Meinung dass ich für Frequenzen über 1 Mhz immer einen Externen Quarz/Osc anschließen muss ?!

Nach dem Datenblatt (nein, Das PDF lade ich jetzt nicht mehr, sonst stürzt mein Firefox wieder ab :rolleyes:) geht das, ich habe es selber noch nicht probiert. Du musst allerdings bedenken, dass die Fehlergrenzen eines RC-Oszillators größer sind als die des Quarz-Oszillators. Ich glaube der interne RC-Oszillator schafft über den gesamten zulässigen Temperaturbereich des AVR +-1%.

Grüße,
Dirk
 
Ein wenig experimentieren konnte am Wochenende ja doch :D
Ich habe die "Debounce" einfach durch "If Then" ersetzt, und siehe da, die Geschwindigkeit gefällt mir schon.
Durch das einsetzen eines 16Mhz Quarzes gefällt mir das alles jetzt noch besser.
Die Taster für U/D habe ich mit 10nF gegen Masse geschaltet, allerdings "hüpft" er teilweise doch noch, so dass ich um eine Entprellung nicht drum herum komme.
Zur Zeit arbeite ich mit dem 8515 herum, letztendlich soll das ganze aber auf dem Mega8 laufen, und dann mit Multiplex Anzeige laufen.
Da ich aber auch später eine Schaltung für ein paralleles PLL-IC (8 bis 9Bit) benötige, kann ich beim ATMega8 nicht noch PB6 und PB7 für den Quarz opfern ...
In meinem Buch wird "splittng von Ports" ja ganz nett erklärt, so dass ich mir dabei erstmal gedanken um ein halbwegs gleiches Platinenlayout machen werde, um zu mindest die Tasten und die Anzeige gleich ausführen kann.

Aber erstmal dieses eine Projekt perfektionieren: schnell ohne Quarz, und entprellen. Und dann mit der Multiplex zusammen führen.

Ich halt euch auf dem laufenden.
schönen Wochenanfang!
 
Hallo Michael,

glückwunsch! Du hast Dich ja ziemlich in Deinem Thema festgebissen und eigene Lösungsansätze gefunden. Das Experimentieren mit dem Thema ist sehr für das Verständnis von Methodiken wichtig. Gut, weiter so.

Noch ein Wort von mir zum Prellen. Ja, Du kommst um eine Entprellung der Tasten nich herum, es sei denn Du besorgst Dir sehr hochwertige Tasten, ggf. auch Reed-Kontakt-Basis bei denen der Hersteller garantiert, dass diese nicht prellen. Soll es geben, hab aber selbst noch keine eingesetzt.
Ansonsten kommt das Prellen durch die Kontatakte selbst, hervorgerufen durch die im Taster vorhandenen Federn und Massen. Prellen ist nix anderes als das "Einschwingen" eines Mechanischen Schalters der am Anfang, wenn er schließen soll über die "große Distanz" mit viel Federkraft und Masse angerauscht kommt, auf sein "Gegenüberkontakt" prallt und erst mal wieder nach dem Impulserhaltungssatz zurückfedert. Er macht also wieder auf, aber nicht mehr so weit da durch die Feder eine Bremswirkung erfolgt. Also macht er wieder zu und dann vielleicht nochmals auf und wieder zu. Wie oft und wie lang hängt sehr stark von der Qualität der Taster ab. Ist ein Thema für sich aber mit so 10 ms würde ich bei normalen Taster schon rechnen, das diese noch hin und her zappeln.

Grüße und viel Spass,
Markus
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)