Software-UART RXD                           

Elektronik-Labor  Projekte  Mikrocontroller  TLScript         




Nachdem ich schon serielle Daten einer RS232 mit dem Trigger-Oszilloskop im Testlab ansehen konnte, kommt nun der nächste Schritt: Programmieren eines Software-UART, erstmal nur in  Empfangsrichtung. Für den ersten Versuch wurde eine Übertragungsgeschwindigkeit von 100 Baud gewählt, weil das gut zum Timing in PicoBasic passt. Das Ziel war, dass ich beliebige Bytes vom PC abschicke, die dann an acht LEDs angezeigt werden. Sinnlos, könnte man denken, weil der Controller das ja über USB und seinen Hardware-UART schon kann. Aber das Fernziel ist eine Kommunikation zwischen zwei Controllern ohne Umweg über den PC.

Als Eingang verwende ich AD0, damit alle acht Bits des Ausgabeports frei bleiben. Dadurch wird zwar mehr Zeit verbraucht, aber das spielt keine Rolle, solange ich das Timing im Millisekundentakt halten kann. Zur Erkennung der Pegel verwende ich Vergleiche mit 128. B = 128 kann dann im ganzen Programm stehen bleiben und dient auch dazu, das höchste Datenbit zu setzen, wenn der entsprechende Pegel zur passenden Zeit erkannt wird. Die RS232 sendet zwar Bit 0 zuerst, aber die Daten wandern Schritt für Schritt nach rechts, sodass das zuerst empfangene Bit am Ende bei Bit 0 steht.

              Rem RX100Bd
0x09FF  Pdir = 255
              L1:
0x2105  Call L2:
0x4500  Pout = A
0x4200  Print A
0x2001  Jmp L1:
              L2:
0x0280  B = 128
0x3C00  A = AD0
0x2405  If A<B Jmp L2:
0x190F  Delay ms = 15
0x0400  D = 0
0x0307  C = 7
              L3:
0x3900  A = D
0x3200  A = A Shr 1
0x3800  D = A
0x3C00  A = AD0
0x2313  If A>B Jmp L4:
0x3900  A = D
0x2A00  A = A + B
0x3800  D = A
              L4:
0x3900  A = D
0x190A  Delay ms = 10
0x250B  C*Jmp L3:
0x4800  Ret

Jedes Bit benötigt bei 100 Baud eine Zeit von 10 ms. Zuerst wird auf das Startbit gewartet. Dazu dient eine schnelle Schleife ohne Wartezeiten. Solange A kleiner B ist, also die Spannung unter 128 erscheint, wird nach L2 gesprungen. Sobald eine positive Flanke erkannt wurde, geht es weiter. Zuerst wird aber 15 ms gewartet, damit die nächste Abfrage mitten im ersten Datenbit landet. Ein Low-Pegel bedeutet ein 1-Bit, dann wird B zu A hinzuaddiert, also das höchste Bit gesetzt. Beim nächsten Durchlauf der Empfangsschleife werden zuerst alle Bits um eine Stelle nach rechts geschoben. Immer wieder muss A in D zwischengespeichert werden, weil A auch für die Spannungsmessung gebraucht wird. Die Zählschleife wird mit C = 7 gestartet, weil ja der erste Durchlauf dazukommt und so insgesamt acht Bits gelesen werden.

Das sieht alles ganz einfach aus, aber ich habe mehrere Tests und Korrekturen gebraucht, bis alles richtig funktionierte. Als ich dann mit meinem Terminal alle acht LEDs steuern konnte, war das ein Erfolgserlebnis wie vor Jahrzehnten, als sich das zum ersten Mal mit einem 8048 in Assembler geschafft habe, damals mit 1200 Baud. In Assembler muss ich genau die pro Befehl verbrauchten Taktzyklen addieren, um ein korrektes Timing zu erreichen. Das ist diesmal etwas einfacher, weil Delay ms das Programm in einen Millisekundentakt zwingt und die Programmlaufzeiten deutlich unter einer Millisekunde bleiben.



Als nächstes wollte ich eine Version für einen USB-Seriell-Wandler bauen, der allerdings meist 100 Baud nicht akzeptiert, sondern bei 300 Baud beginnt. Wegen der 1,5-fachen Wartezeit nach dem Startbit bietet sich eine Bitlänge von 2 ms an, also eine Übertragungsgeschwindigkeit von 500 Baud. Die erste Wartezeit beträgt dann 3 ms. Außerdem sind die Pegel invertiert, was bei den Vergleichen zur Auswertung der Pegel beachtet werden muss. Der Schutzwiderstand am Eingang AD0 kann entfallen, weil nun TTL-Pegel von 5 V vorliegen.

              Rem RX500BdTTL
0x09FF  Pdir = 255
              L1:
0x2105  Call L2:
0x4500  Pout = A
0x4200  Print A
0x2001  Jmp L1:
              L2:
0x0280  B = 128
0x3C00  A = AD0
0x2305  If A>B Jmp L2:
0x1903  Delay ms = 3
0x0400  D = 0
0x0307  C = 7
              L3:
0x3900  A = D
0x3200  A = A Shr 1
0x3800  D = A
0x3C00  A = AD0
0x2413  If A<B Jmp L4:
0x3900  A = D
0x2A00  A = A + B
0x3800  D = A
              L4:
0x3900  A = D
0x1902  Delay ms = 2
0x250B  C*Jmp L3:
0x4800  Ret

Diesmal reicht ein Test mit dem eigenen USB-Wandler. Dazu muss man die Schnittstelle in der PicoBasic IDE freigegen, indem man sie beendet oder eine andere nicht verwendete COM eingibt. Dann kann ein beliebiges Terminal die Kommunikation übernehmen und mit 500 Baud senden.






Wesentlich höhere Baudraten sind auch möglich, wenn man Verzögerungszeiten in Mikrosekunden verwendet. Aber dann entfällt das Zeitraster in Millisekunden, sodass man selbst für genaue Abtastpunkte sorgen muss. Da kann es einen Unterschied machen, ob 0- oder 1-Bits empfangen werden, den man durch NOP-Befehle an den richtigen Stellen ausgleichen muss.


Elektronik-Labor  Projekte  Mikrocontroller  TLScript