Radom
25.03.2017, 10:30
Hi an alle!
Zur Zeit versuche ich eine Weichensteuerung für die Lego Eisenbahn meines Sohnes zu realisieren.
Zur mir:
- bin recht neu in Arduino/Microcontroller
- lese gerade das AVR Lehrbuch von Roland Walter
- hab mir das meiste Programmieren selbst beigebracht (ca. 8 Jahre beruflich VBA, 2x C++ Kurs)
- Elektronik-Kenntnisse auch selbst beigebracht (Anfängerkenntnisse würde ich sagen)
- mit dem Projekt und den Bauteilen beschäftige ich mich jetzt ca. seit 5 Monaten, immer mal wieder am Wochenende, oder wenn es sich Abends ausgeht
Folgende Bauteile verwende ich:
- Arduino UNO
- MUX-Shield (1. Generation)
- umgebautes PC-Netzteil als ext. Stromquelle (so ähnlich wie das hier http://www.kondensatorschaden.de/2015/06/13/how2-experimentiernetzteil/ )
- Servos "Tower Pro SG90" (also die http://www.micropik.com/PDF/SG90Servo.pdf)
- Taster mit RC-Glied (10 k & 100nF)
- Shift-Register 74HC595
Jede Weiche hat einen Taster, dieser toggelt die Weiche. Für die Gerade Fahrt auf der Weiche brauche ich den Servo auf 45°, für die Abzweigung ganz links (0°).
Das Programm ist ungefähr so aufgebaut (Code am Ende):
# herzlichen Dank an Oberallgeier für die Lösung mit dem Timer PWM ! :) https://www.roboternetz.de/community/threads/61379-Kopfsache-und-ein-m1284-etliche-Servos-viel-Alu/page3?p=577715&viewfull=1#post577715
(hoffentlich hab ich es richtig verstanden :p )
- Timer 1 CompA
→ Prescaler 1:64
→ 4999 Ticks / n Servos um das 20ms Intervall für jeden Servo zu starten
→ setzt den Ausgang des Registers des aktuellen Servos auf 1
→ prüft auf Tastendruck
→→ wenn gedrückt, führe Funktion aus und setzt die Shift-Register der LEDs neu
(so gelöst damit die LEDs nicht flackern und dass TIMER 1 so wenig wie möglich gestört wird)
→ setzt den Wert für Timer 1 CompB
- Timer 1 CompB
→ sendet eine 0 an die Register und schaltet so das Servosignal ab
Im Grunde funktioniert es, ABER :p
- anders als im Datenblatt des Servos fahren die Servos nur auf die
→ linkeste Position, wenn die Pulsweite ~ 0,6 ms ist
→ 45° Position, wenn die Pulsweite ~ 1 ms ist
- manche Servos fahren spiegelverkehrt ( 0 = 180 und die Bewegung ist auch gespiegelt )
- der Puls ab dem 2. Schieberegister zappelt am Ende
→ Register 1: schönes Rechteck-Signal
→ Register 2: steigende Flanke sauber, das Zappeln beginnt ab dem eigentlichen Ende des Signals (z.B. 1ms) und verlängert das Signal um ca. 0,75 ms
Edit: irgendwo habe ich gelesen dass ein Servo ca. 1 A Strom braucht, wenn 12 Servos am Netzteil hängen, zeigt das Multimeter aber nur ~350 mA an - ist da was falsch ?
Und mir gehen jetzt die Ideen und Suchbegriffe aus um eine Lösung zu finden... :(
Hat jemand Lust sich das anzusehen und mir vielleicht Tipps zu geben? :confused: :D
PS: im Code habe ich 18 Weichen eingestellt, da ja (aktuell) die Pulsweite für die benötigten 45° nur 1ms sein muss (die Bahn hat auch 18 Weichen, das passt halt auch zu gut :) )
In den Versuchen macht es keinen Unterschied ob ich max. 18 oder max 10 einstelle.
// Define ************************************************** ************************************************** *****************
#define CONTROL0 6 // 5 //MUX control pin 0 (S3 is connected to Arduino pin 2)
#define CONTROL1 5 //4
#define CONTROL2 4 //3
#define CONTROL3 3 //2
/* --> das Shield wurde um einen Pin nach oben verschoben, um den Pin 2 fuer die Interrupt der Taster zu
* verwenden !!
*
* !! ALT !! -> Interrupt mit Taster sind nicht empfohlen, wegen Prellen
* -> meine Schaltungs-/Softwareversuche haben das bestaetigt...
*/
#define MUX0 14 //^= Analog 0
#define MUX1 15 //^= Analog 1
#define MUX2 16 //^= Analog 2
// Variablen / Konstanten ************************************************** ************************************************** *
// 1. konstante Vorgaben
const int PIN_TMR_INI_OK = 1; //Kontroll-LED für erfolgreiche Timer-Initialisierung
const int PIN_TMR_INI_NOK = 13; //Kontroll-LED für fehlgeschlagene Timer-Initialisierung -> wenn ocr1a < ocr1b ist !!
const int PIN_TAKT_SRV = 7; //Takteingang ( SH_CP )
const int PIN_SPEICHER_SRV = 8; //Speicher-Sendung ( ST_CP )
const int PIN_DATEN_SRV = 9; //Pin für den Binär-Wert ( DS )
const int PIN_TAKT_LED = 10; //Takteingang ( SH_CP )
const int PIN_SPEICHER_LED = 11; //Speicher-Sendung ( ST_CP )
const int PIN_DATEN_LED = 12; //Pin für den Binär-Wert ( DS )
const int TICKS_ABZW = 150; //Weiche abzweigend - 0.60 ms = 150 Ticks bei Prescaler 1 : 64
const int TICKS_GERADE = 250; //Weiche gerade - 1.00 ms = 250 Ticks bei Prescaler 1 : 64
const int nSRV_MAX = 18; //max Anzahl an Servos -> es sind max 18 Servos moeglich !
// -> ocr1a > ocr1b ist Pflicht
// -> 4999 / 250 = 19.9 -->> 18 fuer Puffer
// -> NUR wenn max Stell-Signal = 250 ist !!
const int FLAG_LED_GERADE = 0; //Offset um die LED des n-ten Servos fuer gerade Fahrt zu setzen
const int FLAG_LED_ABZW = 1; //Offset um die LED des n-ten Servos fuer abzweigende Fahrt zu setzen
const int IX_SRV_POS = 0; //Index der Positionen im Array
const int IX_RTG_LED = 1; //Index der LED-Flags im Array
// 2. variable Werte
int srv = -1; //der aktuelle Servo als Zähler - für OCR1A
int srvPositionen[ nSRV_MAX ][ 2 ]; //Array für die Servo-Positionen und den Pin fuer die Richtungs LED
int tasterStatus[ nSRV_MAX ]; //Logische Schaltung zur Erfassung der Taster-Status-Wechsel
int ocr1b; //variabler Wert für das, je Servo verschiedene, Steuersignal
int srvByte = 0; //1 Byte = 8 Bit, also ein Paket von 8 Servos
int srvZaehler = 0; //Zaehler zur Ermittlung in welchem Byte = Register sich der aktuelle Servo befindet
int ledByte = 0; //1 Byte = 8 Bit, also ein Paket von 4 Servos, da 1 Servo = 2 LED
int ledZaehler = 0; //Zaehler zur Ermittlung in welchem Byte = Register sich die LEDs befinden
int nShiftRegisterSrv; //Anzahl der vorhandenen/noetigen Register fuer die Servos
int nShiftRegisterLEDs; //Anzahl der vorhandenen/noetigen Register fuer die Richtungs-LEDs
// 3. Berechnete Werte
int ocr1a = 4999 / nSRV_MAX; //Intervall für OCR1A um für jeden Servo ein 20 ms Intervall zu erhalten ( 1 : 64 )
// Setup ************************************************** ************************************************** ******************
void setup ( ) {
// Serial Monitor
// Serial.begin ( 115200 );
// MUX Pins setzen
pinMode(CONTROL0, OUTPUT);
pinMode(CONTROL1, OUTPUT);
pinMode(CONTROL2, OUTPUT);
pinMode(CONTROL3, OUTPUT);
pinMode( MUX0, INPUT); //Multiplexer 0 zu input setzen - empfaengt die Taster-Eingaben
pinMode( MUX1, INPUT); //Multiplexer 1 zu input setzen - empfaengt die Taster-Eingaben
pinMode( MUX2, INPUT); //Multiplexer 2 unbenutzt
// Ausgaenge festlegen
pinMode ( PIN_TAKT_SRV, OUTPUT );
pinMode ( PIN_SPEICHER_SRV, OUTPUT );
pinMode ( PIN_DATEN_SRV, OUTPUT );
pinMode ( PIN_TAKT_LED, OUTPUT );
pinMode ( PIN_SPEICHER_LED, OUTPUT );
pinMode ( PIN_DATEN_LED, OUTPUT );
pinMode ( PIN_TMR_INI_OK, OUTPUT );
pinMode ( PIN_TMR_INI_NOK, OUTPUT );
//Es muss zwingend ocr1a > ocr1b sein! -> fuer ocr1b muss das laengste Servo-Signal angenommen werden (nServMax x laen. SrvSig)
if ( ocr1a < TICKS_GERADE ) {
digitalWrite ( PIN_TMR_INI_NOK, HIGH );
}
else {
// nShiftRegisterSrv bestimmen und Ueberlauf abfangen
nShiftRegisterSrv = nSRV_MAX / 8 + 1; //Register je aktueller Servo Nr., bzw. Anzahl Register bei nServMax
if ( nShiftRegisterSrv * 8 == nSRV_MAX ) //Korrektur bei einer Oktave ( 16 / 8 + 1 = 3, es sind aber nur 2 Byte ! )
nShiftRegisterSrv--;
// nShiftRegisterLEDs bestimmen und Ueberlauf abfangen
nShiftRegisterLEDs = ( nSRV_MAX ) / 4 + 1; //Teiler = 4 da es pro Servo 2 LEDs gibt (gerade Fahrt && abzweigende Fahrt)
if ( nShiftRegisterLEDs * 4 == nSRV_MAX ) //Korrektur bei einer Oktave ( 16 / 4 + 1 = 5, es sind aber nur 4 Byte ! )
nShiftRegisterLEDs--;
// Definiere Timer
cli ( ); //Interrupts abschalten
// Interrupt - Timer 1
TCCR1A = 0; //reset Register A
TCCR1B = 0; //reset Register B
TCNT1 = 0; //Zaehler nullen
OCR1A = ocr1a; //setze Intervall A
TCCR1B |= ( 1 << CS11 ) | ( 1 << CS10 ); //Prescaler Timer 1 auf 1 : 64 einstellen
TCCR1B |= ( 1 << WGM12 ); //Timer auf CTC mode stellen
TIMSK1 |= ( 1 << OCIE1A ); //Timer 1 aktivieren
sei ( ); //Interrupts einschalten
digitalWrite ( PIN_TMR_INI_OK, HIGH );
// Alle Positionen initialisieren
for ( int serv = 0; serv < nSRV_MAX; serv++ ) {
srvPositionen[ serv ][ IX_SRV_POS ] = TICKS_ABZW;
srvPositionen[ serv ][ IX_RTG_LED ] = FLAG_LED_ABZW;
tasterStatus[ serv ] = 0;
}
}
// Register der Servos loeschen
digitalWrite ( PIN_SPEICHER_SRV, LOW );
for ( int shift = nShiftRegisterSrv; shift >= 0; shift-- )
shiftOut ( PIN_DATEN_SRV, PIN_TAKT_SRV, MSBFIRST, 0 );
digitalWrite ( PIN_SPEICHER_SRV, HIGH );
// Register der LEDS setzen
setLEDs();
}
// // ************************************************** ************************************************** ********************
// ISR TIMER 1 COMP A ************************************************** ************************************************** *****
ISR ( TIMER1_COMPA_vect ) {
const int muxMax = 16; //max Anzahl Pins je MUX-Register (Anzahl, NICHT hoechste Pin-Nr !!)
const int mux0 = 14; //Pin des 1. MUX-Registers
int offsetMUXRegister; //Offset um das aktuelle MUX-Register aus dem aktuellen Servo zu errechnen
int muxReg; //MUX-Register des Servo-Tasters
int muxPin; //Pin des akt. Servos je MUX-Regisert
// Auf naechsten Servo zeigen
srv++;
if ( srv > nSRV_MAX - 1 ) { //Ueberlauf abfangen
srv = 0;
srvZaehler = 0;
srvByte = 0;
}
// Den n-ten Servo dem richtigen Register zuordnen
int servRegister = srv / 8 + 1;
// Dem n-ten Servo ueber das entsprechende Register das Steuersignal senden
digitalWrite ( PIN_SPEICHER_SRV, LOW );
for ( int shiftToRegister = nShiftRegisterSrv; shiftToRegister > 0; shiftToRegister-- ) {
if ( shiftToRegister == servRegister ) {
// sende an Shift-Register
// -> der Binaer-Wert ist 2^( srv - srvByte * 8 )
shiftOut ( PIN_DATEN_SRV, PIN_TAKT_SRV, MSBFIRST, 1 << ( srv - ( srvByte * 8 ) ) );
// Taster des aktuellen Servos auf Veraenderung pruefen
offsetMUXRegister = srv / 16;
muxReg = mux0 + offsetMUXRegister;
muxPin = srv - offsetMUXRegister * muxMax;
digitalWrite ( CONTROL0, ( muxPin & 15 ) >> 3 );
digitalWrite ( CONTROL1, ( muxPin & 7 ) >> 2 );
digitalWrite ( CONTROL2, ( muxPin & 3 ) >> 1 );
digitalWrite ( CONTROL3, ( muxPin & 1 ) );
if ( digitalRead ( muxReg ) && digitalRead ( muxReg ) != tasterStatus[ srv ] ) {
if ( srvPositionen[ srv ][ IX_SRV_POS ] == TICKS_ABZW ) {
srvPositionen[ srv ][ IX_SRV_POS ] = TICKS_GERADE;
srvPositionen[ srv ][ IX_RTG_LED ] = FLAG_LED_GERADE;
}
else {
srvPositionen[ srv ][ IX_SRV_POS ] = TICKS_ABZW;
srvPositionen[ srv ][ IX_RTG_LED ] = FLAG_LED_ABZW;
}
// bei Tastendruck die LEDs neu schalten
setLEDs();
}
tasterStatus[ srv ] = digitalRead ( muxReg );
}
else {
// sende an Shift-Register
shiftOut ( PIN_DATEN_SRV, PIN_TAKT_SRV, MSBFIRST, 0 );
}
}
digitalWrite ( PIN_SPEICHER_SRV, HIGH );
// Das Byte des naechsten Servos ermitteln
srvZaehler++;
if ( srvZaehler == 8 ) {
srvZaehler = 0;
srvByte++;
}
ocr1b = srvPositionen[ srv ][ IX_SRV_POS ]; //Länge des Steuersignals aus dem Array lesen
OCR1B = ocr1b; //Timer B setzen
TIFR1 |= ( 1 << OCF1B ); // ??? Klappt immer wenn das gesetzt wird
TIMSK1 |= ( 1 << OCIE1B ); //Timer B aktivieren
}
// // ************************************************** ************************************************** ********************
// ISR TIMER 1 COMP B ************************************************** ************************************************** *****
ISR ( TIMER1_COMPB_vect ) {
TIMSK1 &= ~ ( 1 << OCIE1B ); //CompB Match interrupt disabled
digitalWrite ( PIN_SPEICHER_SRV, LOW );
for ( int shift = nShiftRegisterSrv; shift >= 0; shift-- ) //das Steuersignal abschalten --> Shift-Ausgang = OFF
shiftOut ( PIN_DATEN_SRV, PIN_TAKT_SRV, MSBFIRST, 0 );
digitalWrite ( PIN_SPEICHER_SRV, HIGH );
}
// // ************************************************** ************************************************** ********************
// setLEDs ************************************************** ************************************************** ****************
void setLEDs() {
//Reset
shiftOut ( PIN_DATEN_LED, PIN_TAKT_LED, MSBFIRST, 0 );
//Senden der 0/1 Zustaende der LEDs an die Register
// -> festes setzen aller LEDs um Flackern zu verhindern
digitalWrite ( PIN_SPEICHER_LED, LOW );
for ( int srvLEDs = nSRV_MAX; srvLEDs >= 0; srvLEDs-- ) {
if ( srvPositionen [ srvLEDs ][ IX_RTG_LED ] == FLAG_LED_GERADE ) {
digitalWrite ( PIN_TAKT_LED, HIGH ); //"abzweigendes" Bit auf 0 setzen
digitalWrite ( PIN_TAKT_LED, LOW ); //Takt wieder abschalten
digitalWrite ( PIN_DATEN_LED, HIGH ); //"gerades" Bit auf 1 setzen
digitalWrite ( PIN_TAKT_LED, HIGH ); //"gerades" Bit uebertragen
digitalWrite ( PIN_DATEN_LED, LOW ); //Daten abschalten
digitalWrite ( PIN_TAKT_LED, LOW ); //Takt abschalten
}
else {
digitalWrite ( PIN_DATEN_LED, HIGH ); //"abzweigendes" Bit auf 1 setzen
digitalWrite ( PIN_TAKT_LED, HIGH ); //"abzweigendes" Bit uebertragen
digitalWrite ( PIN_DATEN_LED, LOW ); //Daten abschalten
digitalWrite ( PIN_TAKT_LED, LOW ); //Takt abschalten
digitalWrite ( PIN_TAKT_LED, HIGH ); //"gerades" Bit auf 0 setzen
digitalWrite ( PIN_TAKT_LED, LOW ); //Takt abschalten
}
}
Serial.println();
digitalWrite ( PIN_SPEICHER_LED, HIGH );
}
// // ************************************************** ************************************************** ********************
// loop ************************************************** ************************************************** *******************
void loop ( ) { }
// // ************************************************** ************************************************** ********************
Zur Zeit versuche ich eine Weichensteuerung für die Lego Eisenbahn meines Sohnes zu realisieren.
Zur mir:
- bin recht neu in Arduino/Microcontroller
- lese gerade das AVR Lehrbuch von Roland Walter
- hab mir das meiste Programmieren selbst beigebracht (ca. 8 Jahre beruflich VBA, 2x C++ Kurs)
- Elektronik-Kenntnisse auch selbst beigebracht (Anfängerkenntnisse würde ich sagen)
- mit dem Projekt und den Bauteilen beschäftige ich mich jetzt ca. seit 5 Monaten, immer mal wieder am Wochenende, oder wenn es sich Abends ausgeht
Folgende Bauteile verwende ich:
- Arduino UNO
- MUX-Shield (1. Generation)
- umgebautes PC-Netzteil als ext. Stromquelle (so ähnlich wie das hier http://www.kondensatorschaden.de/2015/06/13/how2-experimentiernetzteil/ )
- Servos "Tower Pro SG90" (also die http://www.micropik.com/PDF/SG90Servo.pdf)
- Taster mit RC-Glied (10 k & 100nF)
- Shift-Register 74HC595
Jede Weiche hat einen Taster, dieser toggelt die Weiche. Für die Gerade Fahrt auf der Weiche brauche ich den Servo auf 45°, für die Abzweigung ganz links (0°).
Das Programm ist ungefähr so aufgebaut (Code am Ende):
# herzlichen Dank an Oberallgeier für die Lösung mit dem Timer PWM ! :) https://www.roboternetz.de/community/threads/61379-Kopfsache-und-ein-m1284-etliche-Servos-viel-Alu/page3?p=577715&viewfull=1#post577715
(hoffentlich hab ich es richtig verstanden :p )
- Timer 1 CompA
→ Prescaler 1:64
→ 4999 Ticks / n Servos um das 20ms Intervall für jeden Servo zu starten
→ setzt den Ausgang des Registers des aktuellen Servos auf 1
→ prüft auf Tastendruck
→→ wenn gedrückt, führe Funktion aus und setzt die Shift-Register der LEDs neu
(so gelöst damit die LEDs nicht flackern und dass TIMER 1 so wenig wie möglich gestört wird)
→ setzt den Wert für Timer 1 CompB
- Timer 1 CompB
→ sendet eine 0 an die Register und schaltet so das Servosignal ab
Im Grunde funktioniert es, ABER :p
- anders als im Datenblatt des Servos fahren die Servos nur auf die
→ linkeste Position, wenn die Pulsweite ~ 0,6 ms ist
→ 45° Position, wenn die Pulsweite ~ 1 ms ist
- manche Servos fahren spiegelverkehrt ( 0 = 180 und die Bewegung ist auch gespiegelt )
- der Puls ab dem 2. Schieberegister zappelt am Ende
→ Register 1: schönes Rechteck-Signal
→ Register 2: steigende Flanke sauber, das Zappeln beginnt ab dem eigentlichen Ende des Signals (z.B. 1ms) und verlängert das Signal um ca. 0,75 ms
Edit: irgendwo habe ich gelesen dass ein Servo ca. 1 A Strom braucht, wenn 12 Servos am Netzteil hängen, zeigt das Multimeter aber nur ~350 mA an - ist da was falsch ?
Und mir gehen jetzt die Ideen und Suchbegriffe aus um eine Lösung zu finden... :(
Hat jemand Lust sich das anzusehen und mir vielleicht Tipps zu geben? :confused: :D
PS: im Code habe ich 18 Weichen eingestellt, da ja (aktuell) die Pulsweite für die benötigten 45° nur 1ms sein muss (die Bahn hat auch 18 Weichen, das passt halt auch zu gut :) )
In den Versuchen macht es keinen Unterschied ob ich max. 18 oder max 10 einstelle.
// Define ************************************************** ************************************************** *****************
#define CONTROL0 6 // 5 //MUX control pin 0 (S3 is connected to Arduino pin 2)
#define CONTROL1 5 //4
#define CONTROL2 4 //3
#define CONTROL3 3 //2
/* --> das Shield wurde um einen Pin nach oben verschoben, um den Pin 2 fuer die Interrupt der Taster zu
* verwenden !!
*
* !! ALT !! -> Interrupt mit Taster sind nicht empfohlen, wegen Prellen
* -> meine Schaltungs-/Softwareversuche haben das bestaetigt...
*/
#define MUX0 14 //^= Analog 0
#define MUX1 15 //^= Analog 1
#define MUX2 16 //^= Analog 2
// Variablen / Konstanten ************************************************** ************************************************** *
// 1. konstante Vorgaben
const int PIN_TMR_INI_OK = 1; //Kontroll-LED für erfolgreiche Timer-Initialisierung
const int PIN_TMR_INI_NOK = 13; //Kontroll-LED für fehlgeschlagene Timer-Initialisierung -> wenn ocr1a < ocr1b ist !!
const int PIN_TAKT_SRV = 7; //Takteingang ( SH_CP )
const int PIN_SPEICHER_SRV = 8; //Speicher-Sendung ( ST_CP )
const int PIN_DATEN_SRV = 9; //Pin für den Binär-Wert ( DS )
const int PIN_TAKT_LED = 10; //Takteingang ( SH_CP )
const int PIN_SPEICHER_LED = 11; //Speicher-Sendung ( ST_CP )
const int PIN_DATEN_LED = 12; //Pin für den Binär-Wert ( DS )
const int TICKS_ABZW = 150; //Weiche abzweigend - 0.60 ms = 150 Ticks bei Prescaler 1 : 64
const int TICKS_GERADE = 250; //Weiche gerade - 1.00 ms = 250 Ticks bei Prescaler 1 : 64
const int nSRV_MAX = 18; //max Anzahl an Servos -> es sind max 18 Servos moeglich !
// -> ocr1a > ocr1b ist Pflicht
// -> 4999 / 250 = 19.9 -->> 18 fuer Puffer
// -> NUR wenn max Stell-Signal = 250 ist !!
const int FLAG_LED_GERADE = 0; //Offset um die LED des n-ten Servos fuer gerade Fahrt zu setzen
const int FLAG_LED_ABZW = 1; //Offset um die LED des n-ten Servos fuer abzweigende Fahrt zu setzen
const int IX_SRV_POS = 0; //Index der Positionen im Array
const int IX_RTG_LED = 1; //Index der LED-Flags im Array
// 2. variable Werte
int srv = -1; //der aktuelle Servo als Zähler - für OCR1A
int srvPositionen[ nSRV_MAX ][ 2 ]; //Array für die Servo-Positionen und den Pin fuer die Richtungs LED
int tasterStatus[ nSRV_MAX ]; //Logische Schaltung zur Erfassung der Taster-Status-Wechsel
int ocr1b; //variabler Wert für das, je Servo verschiedene, Steuersignal
int srvByte = 0; //1 Byte = 8 Bit, also ein Paket von 8 Servos
int srvZaehler = 0; //Zaehler zur Ermittlung in welchem Byte = Register sich der aktuelle Servo befindet
int ledByte = 0; //1 Byte = 8 Bit, also ein Paket von 4 Servos, da 1 Servo = 2 LED
int ledZaehler = 0; //Zaehler zur Ermittlung in welchem Byte = Register sich die LEDs befinden
int nShiftRegisterSrv; //Anzahl der vorhandenen/noetigen Register fuer die Servos
int nShiftRegisterLEDs; //Anzahl der vorhandenen/noetigen Register fuer die Richtungs-LEDs
// 3. Berechnete Werte
int ocr1a = 4999 / nSRV_MAX; //Intervall für OCR1A um für jeden Servo ein 20 ms Intervall zu erhalten ( 1 : 64 )
// Setup ************************************************** ************************************************** ******************
void setup ( ) {
// Serial Monitor
// Serial.begin ( 115200 );
// MUX Pins setzen
pinMode(CONTROL0, OUTPUT);
pinMode(CONTROL1, OUTPUT);
pinMode(CONTROL2, OUTPUT);
pinMode(CONTROL3, OUTPUT);
pinMode( MUX0, INPUT); //Multiplexer 0 zu input setzen - empfaengt die Taster-Eingaben
pinMode( MUX1, INPUT); //Multiplexer 1 zu input setzen - empfaengt die Taster-Eingaben
pinMode( MUX2, INPUT); //Multiplexer 2 unbenutzt
// Ausgaenge festlegen
pinMode ( PIN_TAKT_SRV, OUTPUT );
pinMode ( PIN_SPEICHER_SRV, OUTPUT );
pinMode ( PIN_DATEN_SRV, OUTPUT );
pinMode ( PIN_TAKT_LED, OUTPUT );
pinMode ( PIN_SPEICHER_LED, OUTPUT );
pinMode ( PIN_DATEN_LED, OUTPUT );
pinMode ( PIN_TMR_INI_OK, OUTPUT );
pinMode ( PIN_TMR_INI_NOK, OUTPUT );
//Es muss zwingend ocr1a > ocr1b sein! -> fuer ocr1b muss das laengste Servo-Signal angenommen werden (nServMax x laen. SrvSig)
if ( ocr1a < TICKS_GERADE ) {
digitalWrite ( PIN_TMR_INI_NOK, HIGH );
}
else {
// nShiftRegisterSrv bestimmen und Ueberlauf abfangen
nShiftRegisterSrv = nSRV_MAX / 8 + 1; //Register je aktueller Servo Nr., bzw. Anzahl Register bei nServMax
if ( nShiftRegisterSrv * 8 == nSRV_MAX ) //Korrektur bei einer Oktave ( 16 / 8 + 1 = 3, es sind aber nur 2 Byte ! )
nShiftRegisterSrv--;
// nShiftRegisterLEDs bestimmen und Ueberlauf abfangen
nShiftRegisterLEDs = ( nSRV_MAX ) / 4 + 1; //Teiler = 4 da es pro Servo 2 LEDs gibt (gerade Fahrt && abzweigende Fahrt)
if ( nShiftRegisterLEDs * 4 == nSRV_MAX ) //Korrektur bei einer Oktave ( 16 / 4 + 1 = 5, es sind aber nur 4 Byte ! )
nShiftRegisterLEDs--;
// Definiere Timer
cli ( ); //Interrupts abschalten
// Interrupt - Timer 1
TCCR1A = 0; //reset Register A
TCCR1B = 0; //reset Register B
TCNT1 = 0; //Zaehler nullen
OCR1A = ocr1a; //setze Intervall A
TCCR1B |= ( 1 << CS11 ) | ( 1 << CS10 ); //Prescaler Timer 1 auf 1 : 64 einstellen
TCCR1B |= ( 1 << WGM12 ); //Timer auf CTC mode stellen
TIMSK1 |= ( 1 << OCIE1A ); //Timer 1 aktivieren
sei ( ); //Interrupts einschalten
digitalWrite ( PIN_TMR_INI_OK, HIGH );
// Alle Positionen initialisieren
for ( int serv = 0; serv < nSRV_MAX; serv++ ) {
srvPositionen[ serv ][ IX_SRV_POS ] = TICKS_ABZW;
srvPositionen[ serv ][ IX_RTG_LED ] = FLAG_LED_ABZW;
tasterStatus[ serv ] = 0;
}
}
// Register der Servos loeschen
digitalWrite ( PIN_SPEICHER_SRV, LOW );
for ( int shift = nShiftRegisterSrv; shift >= 0; shift-- )
shiftOut ( PIN_DATEN_SRV, PIN_TAKT_SRV, MSBFIRST, 0 );
digitalWrite ( PIN_SPEICHER_SRV, HIGH );
// Register der LEDS setzen
setLEDs();
}
// // ************************************************** ************************************************** ********************
// ISR TIMER 1 COMP A ************************************************** ************************************************** *****
ISR ( TIMER1_COMPA_vect ) {
const int muxMax = 16; //max Anzahl Pins je MUX-Register (Anzahl, NICHT hoechste Pin-Nr !!)
const int mux0 = 14; //Pin des 1. MUX-Registers
int offsetMUXRegister; //Offset um das aktuelle MUX-Register aus dem aktuellen Servo zu errechnen
int muxReg; //MUX-Register des Servo-Tasters
int muxPin; //Pin des akt. Servos je MUX-Regisert
// Auf naechsten Servo zeigen
srv++;
if ( srv > nSRV_MAX - 1 ) { //Ueberlauf abfangen
srv = 0;
srvZaehler = 0;
srvByte = 0;
}
// Den n-ten Servo dem richtigen Register zuordnen
int servRegister = srv / 8 + 1;
// Dem n-ten Servo ueber das entsprechende Register das Steuersignal senden
digitalWrite ( PIN_SPEICHER_SRV, LOW );
for ( int shiftToRegister = nShiftRegisterSrv; shiftToRegister > 0; shiftToRegister-- ) {
if ( shiftToRegister == servRegister ) {
// sende an Shift-Register
// -> der Binaer-Wert ist 2^( srv - srvByte * 8 )
shiftOut ( PIN_DATEN_SRV, PIN_TAKT_SRV, MSBFIRST, 1 << ( srv - ( srvByte * 8 ) ) );
// Taster des aktuellen Servos auf Veraenderung pruefen
offsetMUXRegister = srv / 16;
muxReg = mux0 + offsetMUXRegister;
muxPin = srv - offsetMUXRegister * muxMax;
digitalWrite ( CONTROL0, ( muxPin & 15 ) >> 3 );
digitalWrite ( CONTROL1, ( muxPin & 7 ) >> 2 );
digitalWrite ( CONTROL2, ( muxPin & 3 ) >> 1 );
digitalWrite ( CONTROL3, ( muxPin & 1 ) );
if ( digitalRead ( muxReg ) && digitalRead ( muxReg ) != tasterStatus[ srv ] ) {
if ( srvPositionen[ srv ][ IX_SRV_POS ] == TICKS_ABZW ) {
srvPositionen[ srv ][ IX_SRV_POS ] = TICKS_GERADE;
srvPositionen[ srv ][ IX_RTG_LED ] = FLAG_LED_GERADE;
}
else {
srvPositionen[ srv ][ IX_SRV_POS ] = TICKS_ABZW;
srvPositionen[ srv ][ IX_RTG_LED ] = FLAG_LED_ABZW;
}
// bei Tastendruck die LEDs neu schalten
setLEDs();
}
tasterStatus[ srv ] = digitalRead ( muxReg );
}
else {
// sende an Shift-Register
shiftOut ( PIN_DATEN_SRV, PIN_TAKT_SRV, MSBFIRST, 0 );
}
}
digitalWrite ( PIN_SPEICHER_SRV, HIGH );
// Das Byte des naechsten Servos ermitteln
srvZaehler++;
if ( srvZaehler == 8 ) {
srvZaehler = 0;
srvByte++;
}
ocr1b = srvPositionen[ srv ][ IX_SRV_POS ]; //Länge des Steuersignals aus dem Array lesen
OCR1B = ocr1b; //Timer B setzen
TIFR1 |= ( 1 << OCF1B ); // ??? Klappt immer wenn das gesetzt wird
TIMSK1 |= ( 1 << OCIE1B ); //Timer B aktivieren
}
// // ************************************************** ************************************************** ********************
// ISR TIMER 1 COMP B ************************************************** ************************************************** *****
ISR ( TIMER1_COMPB_vect ) {
TIMSK1 &= ~ ( 1 << OCIE1B ); //CompB Match interrupt disabled
digitalWrite ( PIN_SPEICHER_SRV, LOW );
for ( int shift = nShiftRegisterSrv; shift >= 0; shift-- ) //das Steuersignal abschalten --> Shift-Ausgang = OFF
shiftOut ( PIN_DATEN_SRV, PIN_TAKT_SRV, MSBFIRST, 0 );
digitalWrite ( PIN_SPEICHER_SRV, HIGH );
}
// // ************************************************** ************************************************** ********************
// setLEDs ************************************************** ************************************************** ****************
void setLEDs() {
//Reset
shiftOut ( PIN_DATEN_LED, PIN_TAKT_LED, MSBFIRST, 0 );
//Senden der 0/1 Zustaende der LEDs an die Register
// -> festes setzen aller LEDs um Flackern zu verhindern
digitalWrite ( PIN_SPEICHER_LED, LOW );
for ( int srvLEDs = nSRV_MAX; srvLEDs >= 0; srvLEDs-- ) {
if ( srvPositionen [ srvLEDs ][ IX_RTG_LED ] == FLAG_LED_GERADE ) {
digitalWrite ( PIN_TAKT_LED, HIGH ); //"abzweigendes" Bit auf 0 setzen
digitalWrite ( PIN_TAKT_LED, LOW ); //Takt wieder abschalten
digitalWrite ( PIN_DATEN_LED, HIGH ); //"gerades" Bit auf 1 setzen
digitalWrite ( PIN_TAKT_LED, HIGH ); //"gerades" Bit uebertragen
digitalWrite ( PIN_DATEN_LED, LOW ); //Daten abschalten
digitalWrite ( PIN_TAKT_LED, LOW ); //Takt abschalten
}
else {
digitalWrite ( PIN_DATEN_LED, HIGH ); //"abzweigendes" Bit auf 1 setzen
digitalWrite ( PIN_TAKT_LED, HIGH ); //"abzweigendes" Bit uebertragen
digitalWrite ( PIN_DATEN_LED, LOW ); //Daten abschalten
digitalWrite ( PIN_TAKT_LED, LOW ); //Takt abschalten
digitalWrite ( PIN_TAKT_LED, HIGH ); //"gerades" Bit auf 0 setzen
digitalWrite ( PIN_TAKT_LED, LOW ); //Takt abschalten
}
}
Serial.println();
digitalWrite ( PIN_SPEICHER_LED, HIGH );
}
// // ************************************************** ************************************************** ********************
// loop ************************************************** ************************************************** *******************
void loop ( ) { }
// // ************************************************** ************************************************** ********************