Das Open-Control-Projekt - Die Alternative zur C-Control-I


Das Forum zur C-Control-1
Welche C-Control-Varianten existieren?
Übersicht - Suchen - Neueste 50 Beiträge - Neuer Beitrag - Login - Registrieren
INFO - FAQ - CC2-Forum - CCPro-Forum 

 Re: Interrupt-Routine/Beep (Kollision?) Kategorie: Programmierung ASM (von Axel F - 11.12.2006 23:55)
 Als Antwort auf Interrupt-Routine/Beep (Kollision?) von Kay - 3.02.2005 22:30
Axel F nutzt:  CC1-Station V1.1
Hallo, ein super Beitrag, mir ist nur noch nicht klar  ob  man mehrere Ports gleichzeitig als PWM verwenden kann (möchte 5 conrad Dimmer ansteuern) oder gibt es dann timing probleme

> 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

Bisherige Antworten: