Die
nachfolgende Schaltung (TPS-Modul) basiert auf der TPS HT46F47 von Holtek und
kann mit dem(n) unten stehenden Basisprogramm(en) z.B. das Modell „Karussell
mit Lichtschranke“ aus dem Baukasten „Profi Electronics“ von Fischertechnik
steuern. Die erweiterte TPS übernimmt dabei die Steuerungsaufgaben des
electronics Modul aus dem Baukasten.
Hinweis: Die Schaltung und das Programm sind eine eigenständige Entwicklung, in
Anlehnung an die Funktionalität des electronics-Moduls. Das
Fischertechnik-Modell wird nur als Beispiel verwendet, um die Möglichkeiten
einer TPS zu demonstrieren. Der Hardware-Aufbau und die Software des Fischertechnik-Moduls
sind dem Autor unbekannt.
Allgemeine
Funktionsweise: Das TPS-Modul verfügt über vier digitale Eingänge ID1-ID4, zwei
analoge Eingänge IA1/IA2, ein Potentiometer und vier Ausgänge O1-O4, wobei
O1/O2 zum Motorausgang M1, und O3/O4 zu M2 zusammengeschaltet sind. Alle
Eingänge können mit 9V beschaltet werden, an allen Ausgängen steht 9V als
Spannung zur Verfügung. Damit ist die Kompatibilität mit den
Fischertechnik-Sensoren (Taster, Fototransistor, NTC-Widerstand etc.) und
-Aktoren (Motor, LED etc.) gewährleistet.
Die Stellung der sechs Schiebeschalter (DIP-Schalter DIP1-6) bestimmt die Funktion der Schaltung. Mit diesen Schaltern wird auch das gewünschte Programm (zzt. das Basisprogramm als Default-Programm), welches z.B. ein Karussell steuern kann, beim Anlegen der Spannung oder nach einem Reset mit dem Taster S3 ausgewählt. Daher ist es wichtig, dass die programmspezifischen Schalterstellungen erst nach Start des Programms vorgenommen werden. Nach der Programmauswahl stehen alle sechs Schiebeschalter in der Grundstellung „OFF“. Ein (+)9V-Signal (z.B. durch Schließen eines Tasters) aktiviert den jeweiligen Eingang (Weiterleitung Signal an die Steuerung). Die DIP-Schalter DIP1-4 haben neben der Programmauswahl unabhängig vom Programm eine besondere Funktion: In der Stellung „ON“ kehren sie die Funktion des jeweiligen Eingangs um, d.h. die Unterbrechung eines ständig am Eingang stehenden Signals aktiviert ihn. Diese Funktion wird z.B. beim Einsatz einer Lichtschranke benötigt, der Eingang wird aktiviert, wenn die Lichtschranke unterbrochen wird.
Modell
„Karussell mit Lichtschranke“ (https://youtu.be/zAw-DNWjlHI ): An den Eingängen ID1 und ID3
werden Taster als Schließer angeschlossen, ID2 wird mit einem Fototransistor
verbunden, IA1 wird auf (+) 9V gelegt, ID4 und IA2 bleiben unbeschaltet. Die
LED3 wird direkt mit der 9V-Spannungsversorgung verbunden, sie bildet mit dem
Fototransistor zusammen eine Lichtschranke. Der Schiebeschalter DIP2 wird in
Stellung „ON“ gebracht. Am Ausgang M1 wird der Motor, an M2 werden zwei
parallel mit umgekehrter Polarität geschaltete LEDs LED1 und LED2 angeschlossen.
Mit den Tastern (kurzer Impuls) wird die jeweilige Drehrichtung des Motors (und
damit des Karussells) bestimmt, bei Unterbrechung der Lichtschranke stoppt das
Karussell. Mit dem Potentiometer kann die Drehgeschwindigkeit des Karussells
und die Blinkfrequenz der LED1 und LED2 synchron geregelt werden (DIP5 in
Stellung „ON“). Ist DIP5 in Stellung „OFF“, ist die Drehgeschwindigkeit
konstant maximal, mit dem Potentiometer wird nur die Blinkfrequenz geregelt.
Der nachfolgende Schaltplan zeigt den Anschluss der Sensoren und Aktoren an das TPS-Modul sowie die Stellung der DIP-Schalter:
Funktion
der DIP-Schalter:
Programm |
DIP1 |
DIP2 |
DIP3 |
DIP4 |
DIP5 |
DIP6 |
Basisprogramm M1:
Motor ID1
= Motor Drehrichtung 1 ID2
= Motor Stopp ID3
= Motor Drehrichtung 2 ID4:
keine Funktion IA1:
(+)9V für Poti IA2:
keine Funktion |
0 |
0 |
0 |
0 |
|
|
M1:
Motorgeschwindigkeit konstant (maximal) M2:
Frequenz über Poti einstellbar |
|
|
|
|
0 |
X |
M1/M2:
Motorgeschwindigkeit und Frequenz über Poti einstellbar |
|
|
|
|
1 |
X |
Allgemein |
|
|
|
|
|
|
ID1,
ID2, ID3, ID4 als Eingang (Schließer) |
0 |
0 |
0 |
0 |
|
|
ID1,
ID2, ID3, ID4 als Eingang (Öffner) |
1 |
1 |
1 |
1 |
|
|
Hinweis:
Die Einstellungen aller DIP-Schalter wird sofort übernommen, kein Neustart der
Steuerung erforderlich; X: 0 oder 1 (ohne Einfluss)
Hardware
Die TPS-Grundschaltung wird wie in der Anleitung zum Lernpaket beschrieben aufgebaut, jedoch werden die beiden Schalter S1 und S2 nicht eingebaut. Stattdessen werden ihre Eingänge direkt mit den Kollektor-Ausgängen des Optokoppler LVT427 verbunden. Die anderen Eingänge E1-E4 werden an die Kollektor-Ausgänge des Optokopplers LVT827 angeschlossen. Alle Emitter-Ausgänge werden auf GND gelegt. Der PMW-Ausgang wird jeweils mit den Ausgängen A1 und A2 UND-verknüpft (2xNAND in Serie) und an die Eingänge IN1/IN2 des Motortreibers DRV8833 (2-Kanal-DC-Motortreibermodul, H-Brücke, 1,5A pro Kanal, 3-10V, z.B. bei roboter-bausatz.de für wenige € erhältlich) angeschlossen. Die Ausgänge A1/A2 funktionieren als Enable für die Weiterleitung des PMW-Signals an die Eingänge IN1/IN2 des Mototreibers und bestimmen die Drehrichtung des Motors. Die Ausgänge A3 und A4 werden direkt mit den Eingängen IN3/IN4 des Motortreibers verbunden. Entgegen der Beschreibung des Händlers muss der Anschluss ULT, nicht EEP, des Motortreibers auf VCC gelegt werden, damit Signale an den Ausgängen Out1-Out4 ausgegeben werden. Der Anschluss EEP bleibt unbeschaltet. Das Treibermodul wird mit 9V Gleichspannung versorgt, die bei entsprechender Schaltung der Eingänge an den Ausgängen Out1-4 anliegt. Zur Versorgung der TPS/Mikrocontrollers werden die 9V auf 5V mit einem Mini Step Down-Modul AMS1117 6,5-12V auf 5V (z.B. roboter-bausatz.de, ca. 1 €) transformiert. Beiden Analogeingängen AD1 und AD2 ist jeweils ein Spannungsteiler aus jeweils zwei 1,0 kΩ-Widerständen (bei AD1 ist ein Widerstand durch ein 1,0 kΩ-Potentiometer ersetzt) vorgeschaltet, um die an den Eingängen IA1 und IA2 angeschlossenen (+)9V auf 4,5 V zu halbieren. Der Analogeingang AD1 ist mit dem Schleifer des Potentiometers verbunden, um eine variable Eingangsspannung von 0-4,5V anlegen zu können.
Die sechs Optokoppler trennen den 5V-Teil vom 9V-Teil der Schaltung: Während
die Kollektor-Eingänge der Optokoppler für die Eingänge S1 und S2 der TPS
direkt über die Schalter DIP5 und DIP6 über einen Vorwiderstand an (+)9V gelegt
werden können, werden die Eingänge ID1-ID4 zusammen mit den DIP-Schaltern
DIP1-4 zunächst XOR verknüpft (IC CD4070, über Online-Plattformen erhältlich),
bevor sie jeweils über einen Vorwiderstand mit dem Kollektor-Eingang des
Optokopplers verbunden werden. Nur eine ungleiche Beschaltung der beiden
XOR-Eingänge (also L/H oder H/L) führt zu einem H-Signal am Ausgang. Damit ist
es einerseits möglich, bei Start der Steuerung (nach einem Reset oder Anlegen
der Versorgungsspannung) das gewünschte Programm mit den DIP-Schaltern
einzustellen (vorausgesetzt, alle Eingänge sind unbeschaltet), anderseits kann
bei laufendem Programm die Funktion der Eingänge mit den DIP-Schaltern
umgekehrt werden.
Software
Die Programme sind soweit kommentiert, so dass es nicht schwer fallen sollte,
sie nachzuvollziehen, daher nachfolgend nur ein paar allgemeine konzeptionelle
Anmerkungen. Sie verwenden beide die Einzel-Bit-Verarbeitung, um die Ausgänge
getrennt voneinander ansteuern und die Eingänge einlesen zu können. Da die
unteren PMW-Frequenzen nach meiner Erfahrung für einen Fischertechnik-Motor
nicht sinnvoll nutzbar sind, wird die Zahl der PMW-Stufen auf acht halbiert,
und die geringste Geschwindigkeit beträgt ebenfalls acht. Das Blinken wird
durch periodischen Wechsel der Polarität an den Ausgängen A3/A4 erzeugt, wobei
die Blinkfrequenz (gleich Wartedauer zwischen Polaritätswechsel) durch zwei Warteschleifen
bestimmt wird, deren Zahl der Durchläufe umgekehrt proportional zum Signal am
Analogeingang AD1 ist. Während die Warteschleifen bei Programm1 durchlaufen
werden, können die Signale an den Eingängen E1 bis E4 des Mikrocontrollers
nicht abgefragt werden, so dass es bei niedriger Blinkfrequenz zu einer
deutlich verzögerten Reaktion des Programms kommt. Abhilfe könnte entweder eine
Interrupt-Programmierung schaffen, die in der TPS derzeit nicht vorgesehen ist,
oder aber eine periodische Abfrage der Eingänge, während die Warteschleifen
durchlaufen werden (Programm2). Dazu werden Haupt- und Unterprogramm getauscht:
Bei Programm1 fragt das Hauptprogramm die Eingänge ab und steuert den Motor,
das Unterprogramm kümmert sich um das Blinken der LEDs. Bei Programm2 kümmert
sich das Hauptprogramm um das Blinken der LEDs, das mehrfach aufgerufene
Unterprogramm fragt die Eingänge ab und steuert den Motor. Programm2 ist
dadurch fünf Zeilen länger als Programm1. Jeder möge für sich entscheiden,
welche Variante ihm besser gefällt.
Programm1:
SubBlinken
Adresse |
Befehl |
Daten |
Kommentar |
*1A |
4 |
3 |
A
= 0011 |
*1B |
8 |
2 |
Seite
2 |
*1C |
C |
3 |
A
= B? |
*1D |
9 |
0 |
Springe
20 „Basisprogramm“; voreingestelltes Programm, falls kein Programm über E1
bis E4 gewählt wurde |
1E |
8 |
5 |
Seite 5 |
1F |
9 |
5 |
Springe 55 „Nächstes
Programm“; wenn E4, E3 = 0 (an GND) (zzt. ohne Funktion) |
20 |
4 |
2 |
A = 2 |
21 |
5 |
1 |
B = A |
22 |
8 |
2 |
AdrHi = 2 (Seite 2) |
23 |
C |
9 |
Skip if:Din.1 =
0,"Falls Stopp gedrückt" |
24 |
9 |
A |
Springe 2A |
25 |
4 |
0 |
A = 0 |
26 |
5 |
5 |
Dout.0=A.0, "Motor links aus" |
27 |
5 |
6 |
Dout.1=A.0, "Motor rechts aus" |
28 |
8 |
3 |
AdrHi = 3 (Seite 3) |
29 |
9 |
F |
Springe 3F „Springe
Blinken“ |
2A |
6 |
9 |
A = AD1,"Poti lesen" |
2B |
7 |
6 |
A = A / B (Halbierung
der PMW-Stufen) |
2C |
5 |
1 |
B = A |
2D |
4 |
8 |
A = 8 (PMW-Basiswert) |
2E |
7 |
3 |
A = A + B |
2F |
C |
C |
Skip if: S1=0,"S1 gedrückt?" |
30 |
4 |
F |
A = 15, "PMW auf Max" |
31 |
5 |
9 |
PWM = A |
32 |
8 |
3 |
AdrHi = 3 (Seite 3) |
33 |
C |
8 |
Skip if:Din.0 = 0, "Falls
links gedrückt" |
34 |
9 |
9 |
Springe 39 „Springe
Motor rechts“ |
35 |
4 |
1 |
A = 1 |
36 |
5 |
5 |
Dout.0 = A.0, "Motor links an” |
37 |
4 |
0 |
A = 0 |
38 |
5 |
6 |
Dout.1 = A.0, "Motor rechts aus" |
39 |
C |
A |
Skip if:Din.2 = 0, "Falls
rechts gedrückt" |
3A |
9 |
F |
Springe 3F „Springe
Blinken“ |
3B |
4 |
0 |
A = 0 |
3C |
5 |
5 |
Dout.0 = A.0, "Motor links aus" |
3D |
4 |
1 |
A = 1 |
3E |
5 |
6 |
Dout.1 = A.0, "Motor rechts an" |
3F |
8 |
4 |
AdrHi = 4 (Seite 4) |
40 |
D |
3 |
Call 43,"Springe
zu Unterprogramm Blinken" |
41 |
8 |
2 |
AdrHi = 2 (Seite 2) |
42 |
9 |
0 |
Springe 20 „zurück zu
Anfang“ |
43 |
6 |
9 |
A = AD1,"Poti
einlesen" "Unterprogramm Blinken" |
44 |
7 |
A |
A = Not A (schnelles
Blinken = kurzes Warten) |
45 |
5 |
2 |
C = A (Zähler für
Warteschleife) |
46 |
5 |
3 |
D = A (Zähler für
Warteschleife) |
47 |
4 |
1 |
A = 1 |
48 |
5 |
7 |
Dout.2 = A.0,"Lampe an A3 an" |
49 |
4 |
0 |
A = 0 |
4A |
5 |
8 |
Dout.3 = A.0,"Lampe an A4 aus" |
4B |
2 |
6 |
Warte 100 ms |
4C |
A |
B |
C-mal 4B (Warteschleife) |
4D |
4 |
0 |
A = 0 |
4E |
5 |
7 |
Dout.2=A.0, "Lampe an A3 aus" |
4F |
4 |
1 |
A = 1 |
50 |
5 |
8 |
Dout.3=A.0, "Lampe an A4 an" |
51 |
8 |
5 |
AdrHi = 5 (Seite 5) |
52 |
2 |
6 |
Warte 100 ms |
53 |
B |
2 |
D-mal 52
(Warteschleife) |
54 |
E |
0 |
Return “Unterprogramm Blinken Ende” |
*entspricht Urzustand des Controllers
Programm2:
SubMotor
Adresse |
Befehl |
Daten |
Kommentar |
*1A |
4 |
3 |
A
= 0011 |
*1B |
8 |
2 |
Seite
2 |
*1C |
C |
3 |
A
= B? |
*1D |
9 |
0 |
Springe
20 „Basisprogramm“; voreingestelltes Programm, falls kein Programm über E1
bis E4 gewählt wurde |
1E |
8 |
5 |
Seite 5 |
1F |
9 |
A |
Springe 5A „Nächstes Programm“;
wenn E4, E3 = 0 (an GND) (zzt. ohne Funktion) |
20 |
4 |
2 |
A = 2 |
21 |
5 |
1 |
B = A |
22 |
6 |
9 |
A = AD1 (Pot lesen) |
23 |
7 |
A |
A = NOT A (schnelles
Blinken = kurzes Warten) |
24 |
5 |
2 |
C = A (Zähler für
Warteschleife) |
25 |
5 |
3 |
D = A (Zähler für
Warteschleife) |
26 |
7 |
A |
A = NOT A |
27 |
7 |
6 |
A = A / B (Halbierung
der PMW-Stufe) |
28 |
5 |
1 |
B = A |
29 |
4 |
8 |
A = 8 (PMW-Basiswert) |
2A |
7 |
3 |
A = A + B |
2B |
5 |
1 |
B = A |
2C |
8 |
4 |
AdrHi = 4 (Seite 4) |
2D |
D |
2 |
Call 42 “Springe Unterprogramm Motor” |
2E |
4 |
1 |
A = 1 |
2F |
5 |
7 |
Dout.2 = A.0 “Lampe an A3 an” |
30 |
4 |
0 |
A = 0 |
31 |
5 |
8 |
Dout.3 = A.0 “Lampe an A4 aus” |
32 |
8 |
4 |
AdrHi = 4 (Seite 4) |
33 |
D |
2 |
Call 42 “Springe Unterprogramm Motor” |
34 |
2 |
6 |
Warte 100ms |
35 |
8 |
3 |
AdrHi = 3 (Seite 3) |
36 |
A |
2 |
C-mal 32 (Warteschleife) |
37 |
4 |
0 |
A = 0 |
38 |
5 |
7 |
Dout.2 = A.0 “Lampe an A3 aus” |
39 |
4 |
1 |
A = 1 |
3A |
5 |
8 |
Dout.3 = A.0 “Lampe an A4 an“ |
3B |
8 |
4 |
AdrHi = 4 (Seite 4) |
3C |
D |
2 |
Call 42 „Springe
Unterprogramm Motor“ |
3D |
2 |
6 |
Warte 100ms |
3E |
8 |
3 |
AdrHi = 3 (Seite 3) |
3F |
B |
B |
D-mal 3B
(Warteschleife) |
40 |
8 |
2 |
AdrHi = 2 (Seite 2) |
41 |
9 |
0 |
Springe 20 “Springe
zurück zu Anfang” |
|
|
|
„Unterprogramm Motor“ |
42 |
C |
9 |
Skip if:Din.1 = 0
“Falls Stopp gedrückt” |
43 |
9 |
8 |
Springe 48 “Springe
Motor links/rechts” |
44 |
4 |
0 |
A = 0 |
45 |
5 |
5 |
Dout.0 = A.0 “Motor links aus” |
46 |
5 |
6 |
Dout.1 = A.0 “Motor rechts aus” |
47 |
E |
0 |
Return “Unterprogramm Motor Ende” |
48 |
6 |
1 |
A = B |
49 |
C |
C |
Skip if:S_SEL = 0 |
4A |
4 |
F |
A = 15 “PMW auf Max” |
4B |
5 |
9 |
PWM.1 = A |
4C |
8 |
5 |
AdrHi = 5 (Seite 5) |
4D |
C |
8 |
Skip if:Din.0 = 0
“Falls links gedrückt” |
4E |
9 |
3 |
Springe 53 “Springe Motor rechts” |
4F |
4 |
1 |
A = 1 |
50 |
5 |
5 |
Dout.0 = A.0 “Motor links an” |
51 |
4 |
0 |
A = 0 |
52 |
5 |
6 |
Dout.1 = A.0 “Motor rechts aus” |
53 |
C |
A |
Skip if:Din.2 = 0
“Falls rechts gedrückt” |
54 |
E |
0 |
Return “Unterprogramm Motor Ende” |
55 |
4 |
0 |
A = 0 |
56 |
5 |
5 |
Dout.0 = A.0 “Motor links aus” |
57 |
4 |
1 |
A = 1 |
58 |
5 |
6 |
Dout.1 = A.0 “Motor rechts an” |
59 |
E |
0 |
Return “Unterprogramm Motor Ende” |
*entspricht Urzustand des Controllers