
|
INFO - FAQ - CC2-Forum - CCPro-Forum |
|
Auch wenn der Thread schon etwas älter ist, möchte ich hier noch einmal darauf eingehen. Mit dem Dimmer hat Conrad ein fragliches Teil auf den Markt geworfen, dessen Ansteuerung sich zum Bleistift mit einem DA-Port weit einfacher hätte machen lassen. Der Dimmer könnte das auch, der Nutzer einer CControl-Station sucht jedoch vergebens nach einem D/A-Port an seiner Kiste :-( Das ist mal wieder Conrad live: Der geneigte Kunde hat das Nachsehen und diejenigen, die mit der Programmierung wenig am Hut haben, verzweifeln an Fragen wie: 1. Warum, muss ich krampfhaft ein und die selbe feste Variable für den auszugebenden Wert verwenden? 2. Wieso, geht das Ding nur am Digitalport 3? 3. Warum stottert die BEEP-Ausgabe? 4. Geht das denn überhaupt anders zu machen? Antworten wir mal :-) ...... zuerst mit dem Original-Dimmer-Treiber in BASIC-Worten 0101 lda #6 ' Sorge dafür, dass alles 0103 sta $52 ' ab Adresse 0106 automatisch alle 20 ms runtergerasselt wird 0105 rts ' und kehre zurück zu BASIC 0106 lda $a1 ' akku = "BASIC"-Variable 1 (byte[1]) 0108 bset 2,1 ' Port3 (des Byteport 1) = on 010a deca ' akku = akku - 1 010b bne $010a ' if akku > 0 then goto 010a 010d bclr 2,1 ' Port3 (des Byteport 1) = off 010f lda #1 ' akku = 1 0111 rts ' return binär (hexdump) sieht das so aus: a606 b752 81 b6a1 1401 4a 26fd 1501 a601 81 bzw kennt der Dimmer-Neueinsteiger das so: a6 06 b7 52 81 b6 a1 14 01 4a 26 fd 15 01 a6 01 81 Jetzt hat sicher jeder verstanden, was die merkwürdigen Zahlen hinter dem syscode-Befehl im Beispielprogramm bedeuten. zu 1. ...Variablenfrage... Wer aufmerksam mitzählt, weiß nun sicher schon, was er ändern müsste, um die Nummer der Basic-Variable zu ändern. Diese liegt im System an Adresse a1 und wird bei jedem Aufruf der Routine ab Adresse 0106 geladen. Das 7. Byte also im syscode nennt die Adresse der Varable. Hexadezimal weitergerechnet könnte man so die nächsten 23 möglichen Adressen verwenden. Der Ladebefehl lda a3 an Adresse 6 (0106 b6a3) würde also zum Bleistift byte[3] in Basic meinen. Die "sys-Bytes" entsprechend neu in den Kontroller übertragen - und schon könnte man sein Basic-Programm diesbezüglich anpassen. (nicht machen! der Treiber ist so falsch und hier nur als Beispiel gezeigt) zu 2. ...Digitalportfrage... Genau in den Quelltext gesehen? die Maschinenbefehle bset und bclr bedienen den (Bit-)Port. die Parameter hinter den Befehlen geben an, welches Bit an welchem Byteport gemeint ist. Bits werden im System von 0...7 gezählt, Basic macht daraus 1...8. Da der Kontroller als 8-Bit-Rechner nicht wirklich mit Words im Sinne von Basic rechnet, gilt in Maschinenprogrammen für den Byteport 2, zu dem in Basic die Ports 9...16 gehören: ebenfalls Bits 0...7, aber port 2. Um zum Bleistift Port 15 einzuschalten, muss bset 6,2 benutzt werden. Auf die Richtungsregister möchte ich nicht eingehen, die haben keine Bedeutung für den Dimmer, wenn man den Dimmerport bei Start des Basic-Programms off setzt. Das sollte man auch tunlichst, sonst ist der Port ein "Eingang" und nichts geht. zu 3. ...BEEP-Stotter-Frage... Basic-Benutzern ist der freilaufende 20-ms-Timer sicher schon genug geläufig. Er wird in diesem Takt (also alle 20 ms, 50 mal pro Sekunde) um 1 erhöht - völlig egal, was man tut. Somit ist er gut für Zeitmessungen einsetzbar. Seine Existenz ist aber nur die halbe Wahrheit, in Wirklichkeit ist er von einem system- internen Timer, der 10.000 mal schneller läuft und andere Timingfunktionen sowie die Echtzeituhr bedient, mathematisch abgeleitet. Die Mathematik bewirkt einen Interrupt, der alle 20 ms ausgelöst wird und eben genannte Systemfunktionen bedient. Der Dimmertreiber läßt sich von diesem Interrupt anschubsen, macht sein kurzes Ding und gibt ans System zurück. Dies dauert selbst im Höchstfall nicht einmal 1 ms! Trotzdem kommt ihm da Wer in die Quere: der BEEPer. Ich will es nicht genauer erklären - es reicht zu wissen, daß der Beep von dem selben Interrupt abgekoppelt wird. Da die Herunterzählschleife des Dimmertreibers eine Echtzeitanwendung ist und, wenn auch nur sehr kurz, so aber voll den Prozessor in Anspruch nimmt, überlagert sie den BEEP stroboskop-artig. Das heißt, nicht immer und nicht permanent, aber spürbar. Hinzu kommt, dass ein Design-Fehler im Betriebssystem (es ist nicht Microsoft! *g*) die Interrupt-Behandlung in falscher Weise erledigt und den Effekt so verdoppelt. Dies hat der Programierer des Dimmertreibers nicht beachtet. Deshalb wird der Dimmer durch den mitgelieferten Treiber auch nicht 50 mal pro Sekunde "bepulst", sondern 57,7 mal. Warum? Der BEEP-Timer löst alle 131,07 s (7,7 mal pro s) einen Roundtrip-Interrupt aus, den der Dimmertreiber eigentlich ignorieren müsste. Deshalb wird der BEEP ärger als ohnehin unterbrochen. zu 4. ...geht's besser... Klare Antwort: JA! Und zwar auf verschiednen Wegen. Einen möchte ich hier vorstellen. Er entstand als Resultat meiner "Forschungen" zur Funktionsweise der ganzen Sache und der Mithilfe bei der Programmierung einer Steuerung von Terrarien. Das Ziel des Dimmers: Zeitgesteuert Sonnenauf- und Untergang simulieren und bei Überhitzung der Becken die Lichtflut reduzieren. Da die Kennlinie des Dimmers mit der Digiport-Pulserei alles andere als auch nur ansatzweise eine Gerade ist, war diese zunächst "geradezubiegen". Ein weiterer Dorn in meinen Augen war, dass das Byte[1] in Basic als Variable für den Dimmer "festgenagelt" war. Die falsche Interruptbehandlung war auch zu lösen und der störende Einfluss des Dimmertreibers auf des BEEP zu minimieren. herausgekommen ist dabei dies: portnr equ 5 byteport equ $01 org $101 lda #$08 sta $52 clr $dc rts brclr 6,$13,_handleST jsr $ee9 clra rts _handleST jsr $e70 lda $dc cmp #20 bhs _endTOCIRQon tax lda _dimtab,x beq _endTOCIRQoff bset portnr,byteport _deca deca bne _deca _endTOCIRQoff bclr portnr,byteport clra rts _endTOCIRQon bset portnr,byteport clra rts lda $92 sta $dc rts _dimtab fcb 0, 4, 5, 6, 7, 8, 8, 10, 11, 12 fcb 13, 14, 15, 17, 19, 21, 23, 27, 40, 50 Das funktioniert folgendermaßen: Mit sys &h101 startet man in BASIC das erste Stück, womit das Ding loszulaufen beginnt. Setzt man davor oder dahinter den (im Moment) Port 6 off, so fällt der Dimmer ab. Um dem Dimmer einen neuen Ausgabewert zuzuweisen, wird mit sys &h12c,wert dieser ans Maschinenprogramm gegeben, welches den Wert in den Weiten des Systems verbuddelt. Damit ist man von der zwanghaften Verwendung einer festen Variable befreit. Der Hauptteil des Treibers holt sich den zwischengespeicherten Wert, der jetzt auch nur noch 0...20 (dezimal) betragen darf, und prüft diesen: wenn 0, dann schalte ganz aus, wenn 20, dann schalte ganz an. Damit ist man von unnützen Schleifen befreit, die den Prozessor bremsen und nur mühseelig eine Vollaussteuerung des Dimmers erreichen. Liegt der Wert im bereich 1<= x <= 19, so wird aus der fcb-Tabelle ein Wert für den Schleifenzähler geholt, und die bekannte Prozedur abgewickelt. Zu den fcb's sei gesagt, dass die Werte experimentell an der CC1-Station eines Bekannten ermittelt wurden. Die Digitalports an dieser erzeugen ein recht rundes Signal. Main-Unit'ler müssen die vereinfachte, berichtigte Routine weiter unten verwenden (nicht den original-Treiber!!!), um sich die für sie passenden Werte zu ermitteln. Diese liegen deutlich unterhalb der obigen. Somit wäre auch die Frage der Linearität des Dimmers geklärt. Je nach Situation kann der Beep zwar auch künftig stottern, jedoch kann man mit der Tonhöhe experiemntieren, um einen Ton zu finden, der störungsfrei wiedergegeben wird, wenn der Dimmer nicht gerade auf 0 oder 20 läuft - dann stört eh nichts mehr. Ich hoffe, künftigen Dimmer-Benutzern damit einen Einblick und Hilfe gegeben zu haben. Zum Schluß die einfache, aber berichtigte Standard-Routine, welche byte[1] und Port 3 benutzt. Zum Testen, Spielen und Ausgabewerte ermitteln ist sie OK: org $101 lda #6 sta $52 rts brclr 6,$13,_handleST jsr $ee9 bra _ready _handleST jsr $e70 lda $a1 beq _ready bset 2,1 _deca deca bne _deca bclr 2,1 _ready clra rts Wer das nicht erst übersetzen möchte, nimmt einen ASCII-Editor, übernimmt den folgenden Inhalt und speichert die Daten als wasweißichwas.s19 S1200101A606B752810D1305CD0EE9200ECD0E70B6A1270714014A26FD15014F8158 S5030001FB viel spaß beim dimmen :-) |
| Antwort schreiben |