LANC und DMX gleichzeitg

Hallo,

bisher habe ich mit dem Arduino nur etwas rumgespielt und mal ausprobiert was man damit so alles machen kann. Jetzt bin ich gerade dabei ein für mich nützliches Projekt zu realisieren.
Erstmal ein paar allgemeine Informationien für die, die nicht in der Materie drin sind:
Sony Videokameras haben einen LANC Anschluss, über den sich (fast) alle Funktionen einer Kamera steuern lassen. (The SONY LANC protocol)
DMX ist ein auf RS-485 basierendes Protokoll, welches in der Veranstaltungstechnik zu finden ist (DMX (Lichttechnik) – Wikipedia)

Nun zu meinem Projekt. Ich habe eine Videokamera auf einem selbstgebauten Remotehead montiert, welchen ich per DMX über Motoren bewegen kann. Nun möchte ich aber auch aus der ferne über DMX zoomen können, dass wenn z.B. der DMX Wert über 100 liegt den Lanc Befehl zum Zoomen senden. Dazu habe ich folgende Programmbeispiele für den Arduino gefunden:
DMX A Arduino Library for sending and receiving DMX
LANC http://micro.arocholl.com/index.php?option=com_content&view=article&id=19:lanc&catid=35:arduino-article&Itemid=53
Unabhängig voneinander also nur DMX empfangen ODER nur LANC senden funktioniert auch. Allerdings nicht beides zusammen. Schreibe ich die Codes aber so zusammen, dass ich beides auf den Arduino laden kann, kann ich, sobald ein DMX Signal empfangen wird keine LANC Befehle senden. Ich weis nicht so recht wie ich das ändern kann und warum das so ist. Kann es sein, dass ich zwei "Prozesse" parallel ausführen müsste, dies aber nicht geht?
Ich bin für jede Hilfe dankbar. Zur Zeit denke ich ernsthaft darüber nach das ganze mit zwei Controllern zu realisieren. Einer empfängt DMX und gibt dann den Befehl an den zweiten weiter, welcher dann das signal an die Kamera sendet.
Ich weis, dass es eine sehr spezielle Frage ist, aber villeicht kann mir ja jemand weiter helfen. Villeicht mache ich auch nur einen Denkfehler und so wie ich mir das vorstelle kann es gar nicht funktionieren.
Wenn nötig kann ich auch noch den zusammengeschriebenen Code Posten, wenn er euch weiterhilft.
Danke, Gruß
Daniel

Im Moment ist das doch so das beide Programme die Hardware UART(RS232-TTL) nutzen. Der DMX muss auf der Hardwareserial bleiben da du sonst Porbleme mit der Geschwindigkeit bekommst. Es müsste aber Funktionieren wenn die LANC Schnitstelle auf der NewSoftSerial benutzt, da diese nur 9600baud hat.
Ein bisschen Sketch und deinen Schaltplan dann werden Sie geholfen:-)

Das ist erstmal mein Sketch. NewSoftSerial sagt mir gerade gar nichts. Aber ich werde mal googeln und mich dahin etwas belesen. Villeicht bekomme ich es dann ja schon hin. Irgendwie war ich der Meinung, dass meine Lanc ausgabe mit der Seriellen Schnittstelle nichts zu tun hat. Liege ich da falsch?

/*
 LANC Control - v1.0
 (C) Ariel Rocholl - 2008, Madrid Spain
 Feel free to share this source code, but include explicit mention to the author.
 Licensed under creative commons - see http://creativecommons.org/licenses/by-sa/3.0/
// - - - - -
// DmxSerial - A hardware supported interface to DMX.
// DmxSerialRecv.pde: Sample DMX application for retrieving 3 DMX values:
// address 1 (red) -> PWM Port 9
// address 2 (green) -> PWM Port 6
// address 3 (blue) -> PWM Port 5
// 
// Copyright (c) 2011 by Matthias Hertel, http://www.mathertel.de
// This work is licensed under a BSD style license. See http://www.mathertel.de/License.aspx
// 
// Documentation and samples are available at http://www.mathertel.de/Arduino
// 25.07.2011 creation of the DmxSerial library.
// 10.09.2011 fully control the serial hardware register
//            without using the Arduino Serial (HardwareSerial) class to avoid ISR implementation conflicts.
// 01.12.2011 include file and extension changed to work with the Arduino 1.0 environment
 */
 
#include <DMXSerial.h>
const int LEDPin =    6;  // LED welche testweise einfach nur per DMX gedimmt werden soll!

int PinLANC = 4;                // 5V limited input signal from LANC data
int PinCMD = 5;                 // Command to send to LANC

int PinLEDRecord = 11;           // Will be ON when recording
int PinLEDPlay = 10;             // Will be ON when playing
int PinLEDActivity = 13;         // Will be ON anytime there is status different than STOP

//Zoomcommands
int speeds[18] = /*These are the commands sent to the camera. 99 tells the code to send nothing.*/
{
  0x0e,0x0c,0x0a,0x08,0x06,0x04,0x02,0x00, /*Zoom tele, from fastest to slowest*/
  99,99,99, /*Dead zone*/
  0x10,0x12,0x14,0x16,0x18,0x1a,0x1e}; /*Zoom wide, from slowest to fastest*/

int PinSWButton = 12; //Buttonm, der nur zum testen der LANC Funktion drin ist.
int PinSWZoom = 7; //Button, der den Zoom mit der mit dem Poti ausgewählten Geschwindigkeit startet.
int analogPin = 2;
int val = 0; 

//Commands to send to camera (note this is not the same value as coded received on status)
const int eSTOP = 0x30;
const int eRECStart = 0x3A27;
const int ePLAY = 0x34;
const int eRECStop = 0x3C29;

int eBUTTON = eRECStart; //Befehl, der beim drücken des Buttons gesendet werden soll.

int byte0;
int eCommand;                   //Current LANC command to send to video camera
int nDetectedStatus;            //Status returned by LANC bus
byte nCommandTimes;             //LANC requires at least 5 times to repeat the command to video camera. This will count that.
int nFlashCounter;              //Counter to flash leds so they save battery power (as opposed to be always ON)

void setup()                    // run once, when the sketch starts
{ 
  BlinkLong();
  DMXSerial.init(DMXReceiver); // DMX Initialisieren
  pinMode(LEDPin,   OUTPUT);
  pinMode(PinLANC, INPUT);
  pinMode(PinCMD, OUTPUT);
  pinMode(PinLEDRecord, OUTPUT);
  pinMode(PinLEDActivity,OUTPUT);
  pinMode(PinLEDPlay,OUTPUT);

  //set input pins and activate internal weak pullup resistors
  pinMode(PinSWButton,INPUT);
  digitalWrite(PinSWButton,HIGH);
  pinMode(PinSWZoom,INPUT);
  digitalWrite(PinSWZoom,HIGH);

  nFlashCounter=0;
  nCommandTimes=0;
}

void FlashLED()
{
  boolean bLED_ON=false;

  nFlashCounter++;
  if (nFlashCounter>=50)
    nFlashCounter=0;
  else if (nFlashCounter>=45)
    bLED_ON=true;

  if (bLED_ON)
  {
    switch(nDetectedStatus)
    {
    case 0x02: //stop
      digitalWrite(PinLEDPlay,LOW);
      digitalWrite(PinLEDActivity,LOW);
      digitalWrite(PinLEDRecord,LOW);
      break;
    case 0x06: //PLAY
      digitalWrite(PinLEDActivity,HIGH);
      digitalWrite(PinLEDPlay,HIGH);
      break;
    case 0x04: //REC
      digitalWrite(PinLEDActivity,HIGH);
      digitalWrite(PinLEDRecord,HIGH);
      break;
    default: //any other activity except STOP
      digitalWrite(PinLEDActivity,HIGH);
      break;
    }
  }
  else
  {
    digitalWrite(PinLEDPlay,LOW);
    digitalWrite(PinLEDActivity,LOW);
    digitalWrite(PinLEDRecord,LOW);
  }
}


void AfterLongGap()
{
  boolean bLongEnough=false;
  int nInd;


  //search for 4ms gap -at least- being high continuosly.
  //This worked extraordinarily well in my European Sony video camera
  //but it may not work on a NTSC camera, you may need to reduce the 
  //loop limit for that (hopefully not). Please send me details
  //in that case to make it available to the community.

  while (!bLongEnough)
  {
    for (nInd=0; nInd<150; nInd++)
    {
      delayMicroseconds(25);
      if (digitalRead(PinLANC)==LOW)
        break;
    }
    if (nInd==150)
      bLongEnough=true;
  }

  //Now wait till we get the first start bit (low)
  while (digitalRead(PinLANC)==HIGH)
    delayMicroseconds(25);

}

void SendCommand(unsigned char nCommand)
{
  //Note bits are inverted already by the NPN on open collector
  //(when it is switched ON by a vbe>0.7v, the vce will be close to zero thus low state for LANC)
  //This is exactly what we want and how LANC bus works (tie to GND to indicate "1")

  delayMicroseconds(84); //ignore start bit
  digitalWrite(PinCMD,nCommand  & 0x01);
  delayMicroseconds(94); 
  digitalWrite(PinCMD,(nCommand  & 0x02) >> 1);
  delayMicroseconds(94); 
  digitalWrite(PinCMD,(nCommand  & 0x04) >> 2);
  delayMicroseconds(94); 
  digitalWrite(PinCMD,(nCommand  & 0x08) >> 3);
  delayMicroseconds(94); 
  digitalWrite(PinCMD,(nCommand  & 0x10) >> 4);
  delayMicroseconds(94); 
  digitalWrite(PinCMD,(nCommand  & 0x20) >> 5);
  delayMicroseconds(94); 
  digitalWrite(PinCMD,(nCommand  & 0x40) >> 6);
  delayMicroseconds(94); 
  digitalWrite(PinCMD,(nCommand  & 0x80) >> 7);
  delayMicroseconds(94); 
  digitalWrite(PinCMD,LOW); //free the LANC bus after writting the whole command
}

byte GetNextByte()
{
  unsigned char nByte=0;

  delayMicroseconds(104); //ignore start bit
  nByte|= digitalRead(PinLANC);
  delayMicroseconds(104); 
  nByte|= digitalRead(PinLANC) << 1;
  delayMicroseconds(104); 
  nByte|= digitalRead(PinLANC) << 2;
  delayMicroseconds(104); 
  nByte|= digitalRead(PinLANC) << 3;
  delayMicroseconds(104); 
  nByte|= digitalRead(PinLANC) << 4;
  delayMicroseconds(104); 
  nByte|= digitalRead(PinLANC) << 5;
  delayMicroseconds(104); 
  nByte|= digitalRead(PinLANC) << 6;
  delayMicroseconds(104); 
  nByte|= digitalRead(PinLANC) << 7;
  nByte = nByte ^ 255;  //invert bits, we got LANC LOWs for logic HIGHs

  return nByte;
}

void NextStartBit()
{

  //Now wait till we get the first start bit (low)
  while(1)
  {
    //this will look for the first LOW signal with abou 5uS precission
    while (digitalRead(PinLANC)==HIGH)
      delayMicroseconds(5); 

    //And this guarantees it was actually a LOW, to ignore glitches and noise
    delayMicroseconds(5);
    if (digitalRead(PinLANC)==LOW) 
      break;
  }
}

boolean IsSwitchEnabled(int nPin)
{
  if (digitalRead(nPin)==LOW)
  {
    delayMicroseconds(100);
    if (digitalRead(nPin)==LOW)
    {
      nCommandTimes=0; //Push button status change, so think on send command now
      return true;
    }
  }
  return false;
}

void GetCommand()
{
  if (IsSwitchEnabled(PinSWButton)) {
    eCommand=eBUTTON;
    byte0 = 0x18; }
  else if (IsSwitchEnabled(PinSWZoom)) {
    eCommand=speeds[val];
    byte0 = 0x28; }
}

void loop()                     // run over and over again
{
  byte LANC_Frame[8];
  byte nByte;
  int nInd, nInd0;

  eCommand = eSTOP;

  //infinite loop, I do not want to get out of here ever.
  //It is more efficient than let loop() function to do
  //that, as it requires a function call and then a loop
  //like this one. Well, I prefer my own efficient loop
  //instead. This increase chances of AfterLongGap() having
  //time enough for what it needs to be done.

  while (1) 
  {  
     //val = analogRead(analogPin); // Analogpin auslesen und auf die Werte im Array mappen
     //val = map(val, 0, 1023, 0, 17); 
     analogWrite(LEDPin,   DMXSerial.read(1)); //DMX Wert lesen und LED Schalten
    //Which command do I have to send from my push buttons?
    GetCommand();

    //Sinchronize to get start of next frame
    AfterLongGap();

    //I will send the command 8 times, LANC requires at least 5 times
    if (nCommandTimes<8) 
    {
      nCommandTimes++;

      SendCommand(byte0); //0x18 indicates normal command to videocamera.
      //you have to change this for a photo camera.
      NextStartBit();
      SendCommand(eCommand);
    }
    else
    {
      //Command already sent 8 times so, just ignore next 2 bytes
      GetNextByte();
      NextStartBit();
      GetNextByte();
    }
    
    //Get next 6 bytes remaining
    for (nInd=2; nInd<8; nInd++)
    {
      NextStartBit();

      LANC_Frame[nInd]=GetNextByte();
    }
    
    nDetectedStatus=LANC_Frame[4];
    FlashLED();
  }

}

Und dann noch mein Schaltplan im Anhang.
Danke Gruß Daniel

bin gerade hier auf das Thema gestoßen

die Belegung im Layout passt irgendwie nicht zu dem Programm

oder täusche ich mich da ?

THX 4 feedback :slight_smile:

die Belegung im Layout passt irgendwie nicht zu dem Programm

Bis auf die LED am Arduino Pin 9 (PB1) kann ich keine Differenzen feststellen.

  while (1)

Eine Endlos-Schleife in der Endlos-Schleife ist nicht sehr sinnvoll, aber auch nicht wirklich schlimm.

Nach den Informationen in Wikipedia wird DMX mit 250kbaud betrieben. Das wiederum heisst, dass der Arduino 25'000 Mal pro Sekunden kurz unterbrochen wird (Interrupt), um ein Byte aus dem Register in den Puffer zu schreiben, solange Verkehr auf dem DMX Bus ist. Das dauert zwar nur wenige Mikrosekunden, aber es könnte Dein fixes Timing mit den delayMicroseconds() durcheinanderbringen. Ein Ausweg wäre jetzt, Interrupts während dieses Vorgangs einfach zu verbieten (cli()), doch das Empfangen oder Senden eines Bytes auf dem LANC dauert fast 1ms, in dieser Zeit könnten 25 Bytes über den DMX geschickt worden sein.

Je nachdem, wie stark Dein DMX ausgelastet ist, würde ich entweder die delayMicroseconds() eliminieren oder die LANC-Kommunikation auf einen Hardware-Serial (Du müsstest dann auf einen Mega wechseln) legen.

Da war ich aber lange nicht mehr hier... Ich hatte eigentlich nicht mehr mit einer weiteren Antwort gerechnet. Danke für die weiteren Infos. Dann werde ich mal meinen Fortschritt erläutern.
Ich muss zugeben, dass ich nicht der große Arduino programierer bin, aber bisher hats immer ausgereicht :slight_smile:
Ich hätte es auch schon längst einmal mit der software Seriellen Schnittstelle ausprobiert, ich habe mir dazu auch einige Beispiele angesehen, aber es wird immer nur gezeigt wie ich Daten darüber sende. So richtig habe ich auch noch nicht verstanden in welcher Form das Lanc senden die Serielle Schnittstelle benötigt, weil dafür ja andere Pins verwendet werden und wie ich das dann auf die Software Serielle Schnittstelle "umlege".

Im Moment denke ich dann schon über ein Art Master Slave System nach, da inzwischen auch ein Motorshield hinzu gekommen ist, bei dem die Seriellen pins harwareseitig auch nicht belegt sind, welches aber auch nicht zusammen mit DMX funktioniert.

Vielleicht nochmal Projektbezogen: Über DMX soll eine Kamera über Motoren bewegt und über Lanc gesteuert werden. Damit Sie aus der Ferne komplett Ferngesteuert werden kann. Möglich wäre also auch ein Arduino zum DMX Empfang, einer zum Motoren Steuern und einer zum Lanc senden. Da ich dafür später sowiso eine extra Platine anfertigen werde würden die Kosten auch nicht so explodieren. Schöner wäre es trotzdem die Schaltung schön kompakt zu halten.
Alternativ wäre auch eine komplett anderes Steuerungsprotokoll (Alternative zu DMX) möglich. Habt ihr da Vorschläge? Das Senden der Daten soll am anderen Ende der Leitung auch ein Arduino übernehmen.

Danke für eure Hilfe!
Gruß Daniel