Eine elektronische Schaltung für ein Roulette-Spiel haben wir bereits konstruiert. Sie wurde mit dem Timer NE555, zwei Logikbausteinen und drei
Zählern CD4017BE ausgeführt. Die Beschreibung der Schaltung ist auf der folgenden Seite zu finden:
In diesem Fall wird die Schaltung mit einem Mikrocontroller und drei Schieberegistern realisiert. Als Mikrocontroller kommt der PIC16F1503 zum
Einsatz. Da der Mikrocontroller lediglich drei Ausgänge zum Steuern der Schieberegister benötigt, könnte man hier ebenso gut den PICF200 einsetzen. Mit
PIC16F1503 bleiben uns jedoch einige weitere I/Os für andere Zwecke zur Verfügung, was sich stets als vorteilhaft erweisen kann.
Als Schieberegister kommen drei M74HC595B1 zum Einsatz. Jedes Schieberegister hat acht Ausgänge und kann problemlos mit weiteren Schieberegistern
verschaltet werden.
PIC16F1503
Der Mikrocontroller PIC16F1503 von Microchip hat in der Schaltung die Aufgabe, die Schieberegister mit Bits zu versorgen. Ansonsten sind an ihn ein
Taster und eine Leuchtdiode angeschlossen. An dieser Stelle kann lediglich erwähnt werden, dass der kleine „Computer“ viel mehr leisten kann, als ihm in
dieser Schaltung abverlangt wird.
Das Spielbrett unseres Roulette-Spieles besteht aus 24 Feldern mit jeweils einer LED. Der Mikrocontroller PIC16F1503 verfügt jedoch nicht über eine
ausreichende Anzahl an Ausgängen, um alle diese Leuchtdioden anzusprechen. Die Aufgabe der Schieberegister besteht darin, eine ausreichende Anzahl an Ausgängen
bereitzustellen. Pro Schieberegister stehen uns acht Ausgänge zur Verfügung. Da wir hier 24 Leuchtdioden steuern müssen, werden folglich drei Schieberegister
verwendet. Jedes Schieberegister verfügt über einen zusätzlichen Ausgang, der an ein folgendes Schieberegister angeschlossen werden kann. So kann eine
Reihenschaltung aus mehreren Schieberegistern aufgebaut werden. Es reichen dann nur drei Verbindungen mit dem Mikrocontroller aus, um alle Schieberegister
anzusteuern und damit alle zur Verfügung stehende Ausgänge zu verwalten.
Die Testschaltung besteht aus einer ziemlich hohen Anzahl von Brücken und Drahtverbindungen. In Wirklichkeit ist sie äußerst simpel. Wie bereits
erwähnt, ist der Mikrocontroller über drei Leitungen mit dem ersten Schieberegister verbunden. Das in einer Endlosschlaufe laufendes Programm hat lediglich die
Aufgabe, in bestimmten Zeitabständen die Bits 0 oder 1 in Schieberegister zu laden. Es wird zuerst ein Bit mit dem Wert „1“ in das Schieberegister geladen.
Danach folgen 23 0-Bits. Anschließend wiederholt sich der Vorgang. Die ganze Bits-Schieberei überwacht im Programm die Variable „Umlauf_Zaehler“.
Das Laden der Bits in die Schieberegister wird in dem Unterprogramm „Bit_laden (Bit)“ erledigt. Der Vorgang ist einfach. Man setzt zuerst die Ausgänge des
Mikrocontrollers, die mit „STCP“-Eingängen und „SHCP“-Eingängen der Schieberegister verbunden sind, auf „false“ (LOW). Damit werden die Bausteine auf „Bereit“
gesetzt. Anschließend schaltet man den Ausgang, der mit dem „DS“-Eingang des ersten Schieberegisters verbunden ist, auf „false“, wenn man „0“ schreiben will
oder „true“, wenn man „1“ schreiben will. Danach wird die SHCP-Leitung auf „true“ geschaltet. Damit wird der aktuelle Wert, der auf DS Leitung steht, in den
internen Speicher des Schieberegisters übernommen. Schaltet man anschließend die STCP-Leitung auf „true“ (HIGH), werden entsprechend die Ausgänge gesetzt.
Bei jedem Bit, das in das Schieberegister neu geschoben wird, wird das letzte Bit aus dem Speicher rausgeschoben. Es erscheint auf dem Ausgang Q7‘ und wird,
falls man mit einer Reihenschaltung der Schieberegister zu tun hat, in das nächste Schieberegister wieder reingeschoben (Kaskadenschaltung).
Nach jeder Runde muss die „laufende“ Leuchtdiode auf einer per Zufall bestimmten Position angehalten werden. Hierfür ist die Variable „Zeit_Zaehler“ zuständig.
Sie wird fortlaufend, während der Start-Taster gedrückt gehalten wird, inkrementiert. Da nicht bekannt ist, wann der Taster wieder losgelassen wird, entspricht
der Endwert der Variable einer Zufallszahl.
Das Programm
// ***************************************************************************
// Roulette mit PIC16F1503 und Schieberegistern
// MPLAB X IDE v6.00
// XC8-Compiler 2.4
// ***************************************************************************
// PIC16F1503 Configuration Bit Settings
// CONFIG1
#pragma config FOSC = INTOSC
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config MCLRE = OFF
#pragma config CP = OFF
#pragma config BOREN = OFF
#pragma config CLKOUTEN = OFF
// CONFIG2
#pragma config WRT = OFF
#pragma config STVREN = OFF
#pragma config BORV = LO
#pragma config LPBOR = OFF
#pragma config LVP = OFF
#include <xc.h>
#include <stdbool.h>
#define _XTAL_FREQ 1000000 // Taktfrequenz
#define SHCP PORTCbits.RC0 // STCP Schieberegister / Pin 10
#define STCP PORTCbits.RC1 // SHCP Schieberegister / Pin 9
#define DS PORTCbits.RC2 // DS Schieberegister / Pin 8
#define LED PORTCbits.RC3 // LED: Runde beendet
#define Taster_Start PORTAbits.RA3 // Spiel Start
int Schritt; // aktueller Programmschritt
int Umlauf_Zaehler; // aktuelle LED, max. 24
int Zeit_Zaehler; // Lauf - Verlangsamung + Zufall
int Felder = 24;
void Bit_laden (bool Bit) { // Bits in Schieberegister übernehmen
STCP = false;
SHCP = false;
if (Bit == 0) {
DS = false;
} else {
DS = true;
}
SHCP = true; // übernehmen
STCP = true; // Ausgänge aktualisieren
}
void main(void) {
ANSELA = 0b00000000; // Pins als digitale I/Os
ANSELC = 0b00000000; // Pins als digitale I/Os
TRISA = 0b00001000; // I/O PORT A, 1-Eingang, 0-Ausgang
TRISC = 0b00100000; // I/O PORT C, 1-Eingang, 0-Ausgang
PORTA = 0b00000000; // Ausgänge nullen
PORTC = 0b00000000; // Ausgänge nullen
Zeit_Zaehler = 30;
while (true) { // Endlos Schleife
// Schritt 0: LED Nr. 1 Ein
if (Taster_Start == false & Schritt == 0 & Umlauf_Zaehler == 0) {
LED = false; // LED Runde beendet AUS
Bit_laden (1); // Erste LED EIN
__delay_ms(10); // Wartezeit
Zeit_Zaehler++; // dient der Zufallbestimmung
Schritt = 1; // Schritt 0 abgeschlossen
}
// Schritt 1: es werden 0-Bits in Register
// geschoben, bis Taster losgelassen wird
// Wenn Position 24 erreicht, geht es mit
// Schritt=0 zurück (erste LED muss wieder
// eingeschaltet werden)
if (Taster_Start == false & Schritt == 1) {
Bit_laden (0);
__delay_ms(10);
Zeit_Zaehler++;
if (Zeit_Zaehler > 50) {
Zeit_Zaehler = 30;
}
Umlauf_Zaehler++;
if (Umlauf_Zaehler > Felder) {
Schritt = 0;
Umlauf_Zaehler = 0;
}
}
// Taster wurde losgelassen = Schritt 2
if (Taster_Start == true & Schritt == 1) {
Schritt = 2;
}
// Der Lauf wird
// fortgesetzt, bis Zeit_Zaehler erreicht
// Die Wartezeiten werden konstant erhöht =
// Lauf - Verlangsamung
if (Taster_Start == true & Schritt == 2) {
for (int i=1; i<Zeit_Zaehler; i++) {
Umlauf_Zaehler++;
if (Umlauf_Zaehler < Felder) {
Bit_laden (0);
for (int j=1; j<(10+3*i); j++) {
__delay_ms(1);
}
}
if (Umlauf_Zaehler > (Felder-1)) {
Bit_laden (1);
Umlauf_Zaehler = 0;
for (int j=1; j<(10+3*i); j++) {
__delay_ms(1);
}
}
}
LED = true; // Lauf abgeschlossen, gelbe LED Ein
Schritt = 0;
Umlauf_Zaehler = 0;
}
}
}
// ***************************************************************************