Loconet

Aus Digital Modellbahn

Wechseln zu: Navigation, Suche

Eigenbau | Allgemein | LocoNet Buffer | LocoNet Kreuzung | LocoNet Throttle | LocoNet Light Control | LocoNet Spezialdekoder

Loconet logo.jpg
Komponenten für LocoNet: LocoNet Buffer für PC Anbindung (links), LocoNet Verteiler (Mitte) und Handregler FREDi (rechts)

Protokoll

Das LocoNet-Protokoll ist nicht offiziell offengelegt. Unter diesen Links sind die vorhanden Dokumentationen zu dem Protokoll zu finden:

Rocrail GCA-Module

Rocrail bietet auch einige Module für LocoNet zum Eigenbau auf seiner Webseite an:

Loconet Patch Panel

Loconet Patch Panel

An diesem Verteiler finden mehrere Loconet Geräte wie der FredI Anschluss. Dazu sind vier RJ12 Buchsen je zwei auf der einen und zwei auf der anderen Seite installiert. Die Eingangsbuchse ist dabei frei wählbar.
Der Verteiler ist im wesentlichen eine Kopie des MVG91 von Rocrail. Jedoch wurde auf die GCA-LocoNet SUB-D Buchsen und die Jumper für die zusätzliche Stromversorgung verzichtet. Als Statusanzeige ist eine LED zur Aktivitätsanzeige von LocoNet und eine Power ON LED vorhanden.

Schaltplan:


Arduino und LocoNet

Hardware

Simple Arduino LocoNet Interface (Eagle)
Arduino LocoNet Interface mit Comperator LM311 (Eagle)
Full LocoNet Interface (Eagle)

serielle Datenübertragung

  • TxPin wird bei der Initialisierung des Interface gesetzt. Der Standard ist in der Library auf Pin 6 festgelegt:
 LocoNet.init(TxPin);


  • RxPin ist an ICP1 und beim Arduino Mega an ICP5:
 Arduino Uno (ATmega168, ATmega328, etc.) PB0, Digital Pin 8
 Arduino Leonardo (ATmega32U4) PD4, Digital Pin 4	
 Arduino Mega (ATmega1280, ATmega2560) PL1, Digital Pin 48
 Arduino Sanguino (ATmega644p) PD6, Digital Pin 6


Arduino Interface

Je nach Arduino wird ein anderer fester Pin für das Rx-Signal(ICP) verwendet. Das LocoNet Interface nutzt zur Kommunikation den Timer1 und im Arduino Mega den Timer 5


LocoNet Steckeranschlüsse

FREMO 15 mA Stromquelle für LocoNet

Stromquelle

Ein Pull-Up (15 mA) für die Datenleitung ist dann notwendig, wenn sich zum Beispiel kein Master am LocoNet befindet. Um Daten senden zu können muss die Datenleitung mit einer 15 mA Stromquelle ausgestattet sein.

Software

Arduino Bibliothek

Die Software ist mit der Arduino IDE geschrieben. Diese Bibliothek von MRRWA erzeugt einen LocoNet Client. Um die Library auch mit dem Arduino MEGA (wie oben unter Hardware beschrieben) nutzbar zu machen, wurde die "ln_config.h" Datei angepasst.

Download

Beispiele

LocoNet Monitor

#include <LocoNet.h>
lnMsg        *LnPacket;

#define LOCONET_TX_PIN 7

void setup() {
  LocoNet.init(LOCONET_TX_PIN);  //First initialize the LocoNet interface

  // Configure the serial port for 57600 baud
  Serial.begin(57600);
  Serial.println("LocoNet Monitor");
}

void loop() {  
  //Check for any received LocoNet packets
  LnPacket = LocoNet.receive() ;
  if( LnPacket ) {
    //First print out the packet in HEX
    Serial.print("RX: ");
    uint8_t msgLen = getLnMsgSize(LnPacket); 
    for (uint8_t x = 0; x < msgLen; x++)
    {
      uint8_t val = LnPacket->data[x];
      //Print a leading 0 if less than 16 to make 2 HEX digits
      if(val < 16)
        Serial.print('0');
        
      Serial.print(val, HEX);
      Serial.print(' ');
    }
    
    //If this packet was not a Switch or Sensor Message then print a new line 
    if(!LocoNet.processSwitchSensorMessage(LnPacket)) {
      Serial.println();
    }
  }
}

// This call-back function is called from LocoNet.processSwitchSensorMessage
// for all Sensor messages
void notifySensor( uint16_t Address, uint8_t State ) {
  Serial.print("Sensor: ");
  Serial.print(Address, DEC);
  Serial.print(" - ");
  Serial.println( State ? "Active" : "Inactive" );
}

// This call-back function is called from LocoNet.processSwitchSensorMessage
// for all Switch Request messages
void notifySwitchRequest( uint16_t Address, uint8_t Output, uint8_t Direction ) {
  Serial.print("Switch Request: ");
  Serial.print(Address, DEC);
  Serial.print(':');
  Serial.print(Direction ? "Closed" : "Thrown");
  Serial.print(" - ");
  Serial.println(Output ? "On" : "Off");
}

// This call-back function is called from LocoNet.processSwitchSensorMessage
// for all Switch Report messages
void notifySwitchReport( uint16_t Address, uint8_t Output, uint8_t Direction ) {
  Serial.print("Switch Report: ");
  Serial.print(Address, DEC);
  Serial.print(':');
  Serial.print(Direction ? "Closed" : "Thrown");
  Serial.print(" - ");
  Serial.println(Output ? "On" : "Off");
}

// This call-back function is called from LocoNet.processSwitchSensorMessage
// for all Switch State messages
void notifySwitchState( uint16_t Address, uint8_t Output, uint8_t Direction ) {
  Serial.print("Switch State: ");
  Serial.print(Address, DEC);
  Serial.print(':');
  Serial.print(Direction ? "Closed" : "Thrown");
  Serial.print(" - ");
  Serial.println(Output ? "On" : "Off");
}

LocoNet Throttle

#include <LocoNet.h>
#include <BasicTerm.h>
#include <ctype.h>

#define LOCONET_TX_PIN 7

// Address Recall Stack Length
#define RECALL_STACK_LEN  6
#define AJS_RECALL_STACK  { 38, 44, 53, 99, 191, 192 }

typedef struct {
	word	RecallStack[ RECALL_STACK_LEN ] ;
	word	LastAddress ;
	byte	LastSlot ;
} TH_EE_CONFIG ;

TH_EE_CONFIG		eeConfig __attribute__((section(".eeprom")))
	= { AJS_RECALL_STACK, 0, 0xFF };
	
LocoNetThrottleClass  Throttle ;
word                  LocoAddr ;
byte                  RecallIndex ;
LnBuf                 LnRxBuffer ;
lnMsg                 *RxPacket ;
byte                  i ;
byte                  tByte ;
uint32_t              LastThrottleTimerTick;

BasicTerm Term(&Serial);

void DrawStaticText(void) {
  Term.show_cursor(0);
  Term.cls();
  Term.position(0,0);
  Term.println(F("LocoNet Throttle Library Demonstration Version: 1"));
  Term.println();
  Term.println(F("Address    :"));
  Term.println();
  Term.println(F("Speed      :"));
  Term.println();
  Term.println(F("Direction  :"));
  Term.println();
  Term.println(F("Functions  : 0 1 2 3 4 5 6 7 8"));
//                        1         2         3             
//              0123456789012345678901234567890  
  Term.println();
  Term.println("Status     :");
  Term.println();
  Term.println("Error      :");
  Term.println();
  Term.println("Last Key   :");
  Term.println();
  Term.println(F("Keys: A    - Enter Loco Address, <BS> to delete, <ENTER> to select"));
  Term.println(F("Keys: Q    - Release Loco Address"));
  Term.println(F("Keys: [    - Reduce Speed"));
  Term.println(F("Keys: ]    - Increase Speed"));
  Term.println(F("Keys: F    - Forward"));
  Term.println(F("Keys: R    - Reverse"));
  Term.println(F("Keys: T    - Toggle Direction"));
  Term.println(F("Keys: <SP> - Stop"));
  Term.println(F("Keys: 0..8 - Toggle Functions 0..8"));
}

void notifyThrottleAddress( uint8_t UserData, TH_STATE State, uint16_t Address, uint8_t Slot ) {
  Term.position(2,13);
  Term.print(Address);
  Term.print("     "); // Erase any extra chars
};

void notifyThrottleSpeed( uint8_t UserData, TH_STATE State, uint8_t Speed ) {
  Term.position(4,13);
  Term.print(Speed);
  Term.print("     "); // Erase any extra chars
};

void notifyThrottleDirection( uint8_t UserData, TH_STATE State, uint8_t Direction ) {
  Term.position(6,13);
  Term.print(Direction ? "Reverse" : "Forward");
};

void notifyThrottleFunction( uint8_t UserData, uint8_t Function, uint8_t Value ) {
  Term.position(8,13 + (Function * 2) );
  if(Value)
    Term.set_attribute(BT_BOLD);
    
  Term.print(Function, DEC);

  if(Value)
    Term.set_attribute(BT_NORMAL);
};

void notifyThrottleSlotStatus( uint8_t UserData, uint8_t Status ) {};

void notifyThrottleState( uint8_t UserData, TH_STATE PrevState, TH_STATE State ) {
  Term.position(10, 13);
  Term.print(State, DEC);
  Term.print(' ');
  Term.print(Throttle.getStateStr(State));
  Term.print("                   ");
}

void notifyThrottleError( uint8_t UserData, TH_ERROR Error ) {
  Term.position(12, 13);
  Term.print(Error, DEC);

  Term.print(' ');
  Term.print(Throttle.getErrorStr(Error));
  Term.print("                   ");
}

void setup() {
  LocoNet.init(LOCONET_TX_PIN); // First initialize the LocoNet interface

  // Configure the serial port for 57600 baud
  Serial.begin(115200);
  Term.init();
  DrawStaticText();
  
  Throttle.init(0, 0, 9999);
}

boolean isTime(unsigned long *timeMark, unsigned long timeInterval) {
    unsigned long timeNow = millis();
    if ( timeNow - *timeMark >= timeInterval) {
        *timeMark = timeNow;
        return true;
    }    
    return false;
}

void loop() {  
  // Check for any received LocoNet packets
  RxPacket = LocoNet.receive() ;
  if( RxPacket ) {
    digitalWrite(13, LOW);
    
    if( !LocoNet.processSwitchSensorMessage(RxPacket) )
      Throttle.processMessage(RxPacket) ; 
  }
  
  if( Serial.available())   {
    int16_t inChar = toupper(Serial.read());
    Term.position(14,13);
    Term.print(inChar);
    switch(inChar){
      case 'A': Throttle.setAddress(1234);
                break;
      case 'X': DrawStaticText();
                Throttle.freeAddress(1234);
                break;
      case 'Q': DrawStaticText();
                Throttle.releaseAddress(); 
                break;
      case 'F': Throttle.setDirection(0); 
                break;
      case 'R': Throttle.setDirection(1); 
                break;
      case 'T': Throttle.setDirection(!Throttle.getDirection());
                break;
      case '[': if(Throttle.getSpeed() > 0 )
                  Throttle.setSpeed(Throttle.getSpeed() - 1);
                break;
      case ']': if(Throttle.getSpeed() < 127 )
                  Throttle.setSpeed(Throttle.getSpeed() + 1);
                break;
      case ' ': Throttle.setSpeed(0); break;
      default:  if( (inChar >= '0') && (inChar <= '8'))
                  Throttle.setFunction( inChar - '0', !Throttle.getFunction(inChar - '0'));
                break;
    }
  }
  
  if(isTime(&LastThrottleTimerTick, 100)) {
    Throttle.process100msActions() ; 
    digitalWrite(13, HIGH);
  }
}