[DMX] Herkennen wanneer geen signaal binnen komt

Anoniem

Ik heb de volgende code geschreven om DMX met een pic16f877a binnen te halen:

code:


#define aantalkanalen 8


unsigned int ch_count=0, offset, i,adres;
unsigned char data[aantalkanalen]={0}, startcode, nutteloos, brk=0;
const unsigned char mask[8]={1,2,4,8,16,32,64,128};

void init_usart()
{
TRISC = 0xFF;

SPBRG = 0x04;
TXSTA.BRGH = 1;

TXSTA.SYNC = 0;
PIE1=0;
PIE1.RCIE = 1;
RCSTA.RX9 = 1;

nutteloos=RCREG;
nutteloos=RCREG;
nutteloos=RCREG;

RCSTA.CREN = 1;
RCSTA.SPEN = 1;


INTCON.PEIE=1;
INTCON.GIE=1;
}




void interrupt()
{

if (PIR1.RCIF)
  {
  if (RCSTA.OERR)
     {
     RCSTA.SPEN=0;
     RCSTA.SPEN=1;
     nutteloos=RCREG;
     nutteloos=RCREG;
     nutteloos=RCREG;
     ch_count=0;
     brk=0;
     }
     
  else
     {
     if (RCSTA.FERR)
        {
        nutteloos=RCREG;
        ch_count=0;
        offset=0;
        brk=0xFF;
        }
     else
        {
        if (brk==0xFF)
           {
           if (ch_count==0) startcode=RCREG;
           else
               {
               if (adres<1)
                  {
                  nutteloos = RCREG;
                  for (i=0; i<aantalkanalen; i++) data[i]=0;
                  }
               else
                   {
                   //------------------------------ Hier adres controleren en evt. uitlezen
                   if (ch_count>=adres & ch_count<adres+aantalkanalen & startcode==0)
                      {
                      data[offset] = RCREG;
                      offset++;
                      }
                  else nutteloos = RCREG;
                  }
               //------------------------------
               }
           ch_count++;
           }
        else
            {
            nutteloos = RCREG;
            ch_count=0;
            }
        }
     }
  PIR1.RCIF=0;
  }
}




void main ()
{

TRISB = 0xFF;
TRISD = 0x00;
init_usart();
PORTD=0;


while(1)
  {
  adres = PORTB;
  for (i=0; i<aantalkanalen; i++)
      {
      if (data[i]>0x80) PORTD = (PORTD&(~mask[i])) + mask[i];
      else PORTD = PORTD&(~mask[i]);
      }
  }
}

De code is geschreven in MikroC. Op de uC zijn op PORTB 8 dipswitches aangesloten. Op PORTD zitten 8 leds. De uC draait overigens op 20Mhz om de informatie even compleet te maken :).

De software haalt 8 kanalen binnen vanaf het ingestelde startadres. Wanneer een kanaal een hogere waarde heeft dan 128 wordt de bijbehorende led aan gezet.

Nu komt het volgende, wanneer het signaal om wat voor reden ook weg valt blijft de laatst gestuurde data in de data-array zitten, met als gevolg dat de uitgang blijft uitsturen.

Ik wil het op een of andere manier afvangen dat zodra het signaal wegvalt alle kanalen naar 0 gezet worden. De kanalen op 0 zetten kan met de volgende regel:

code:


for (i=0; i<aantalkanalen; i++) data[i]=0;

Dit gebruik ik ook wanneer het start-adres op '0' wordt gezet.

Nu is mijn vraag, hoe kan ik het detecteren wanneer er geen signaal binnen komt? Er worden namelijk geen interrupts meer gegenereerd als er geen DMX binnenkomt. Dit heb ik geprobeerd.

Ik weet niet wat dmx is, maar kan je niet een klok zetten en steeds resetten als er signaal binnen komt.

Als er geen signaal meer komt zal de klok aflopen en een interrupt genereren.

Koop hier uw kristallen bol - in 2008 ga ik m'n projecten afmaken, echt waar ....... nouja in 2009 dan ..... ehh 2010 ....

DMX mág een tijdje (uit m'n hoofd 1 sec mark-between-packets + 1 sec break) "stil" zijn op de lijn. Je moet dus ergens een time-out in bakken.
Wat je kunt doen is inderdaad een timer laten lopen, in je mainloop controleren of hij afloopt en in je interrupt steeds resetten. Of op een andere manier, er zijn vele wegen die naar rome leiden, als je er maar ergens een time-out in stopt.

Sowieso kun je al controleren of je lijn tijdens de mark-between-packets wel hoog is en daarna max 1 sec laag tijdens de break. Langer laag dan dat is nooit goed overigens, dus ook dat zou je in je main-loop kunnen checken door gewoon die input te monitoren en te gebruiken als reset voor (alweer) een timer.

If you want to succeed, double your failure rate.

Overigens vind ik het in de praktijk wel prettig als de boel alleen `stil blijft staan' op het moment dat er even geen sturing is, je zit anders in het donker tijdens het wisselen van userlibrary's e.d. - Maar dat zal ook een kwestie van smaak zijn.

Anoniem

Op 23 mei 2007 10:52:56 schreef Aart:
Overigens vind ik het in de praktijk wel prettig als de boel alleen `stil blijft staan' op het moment dat er even geen sturing is, je zit anders in het donker tijdens het wisselen van userlibrary's e.d. - Maar dat zal ook een kwestie van smaak zijn.

Wat je bedoelt is de 'hold' functie, wat de meeste dimmers hebben. Het is in dit geval geen optie dat er iets wordt uitgestuurd wanneer er geen signaal binnen komt. De bedoeling is dat de schakeling 8 waterkleppen gaat aansturen. Het kan dan niet zo zijn dat wanneer er geen DMX binnen komt een waterklep open blijft.

Ik zal eens proberen om een timer te laten controleren of er een interrupt voor de usart binnen komt.

Ah, ik snap je overweging :)

Bij de bekende `el cheapo' dimmertjes zit in dit soort details in het gedrag overigens nogal wat verschil, sommige doen het wel, andere niet en instellen is niet mogelijk.

Anoniem

Op 23 mei 2007 14:13:52 schreef Aart:
Ah, ik snap je overweging :)

Bij de bekende `el cheapo' dimmertjes zit in dit soort details in het gedrag overigens nogal wat verschil, sommige doen het wel, andere niet en instellen is niet mogelijk.

Ik heb het werkend en het is eigelijk best simpel. Zoals eerder in het topic werdt voorgesteld laat ik een timer lopen. Bij elke interrupt van de usart zet ik de timer terug op de beginwaarde. Wanneer de timer een interrupt veroorzaakt wordt alles in de data array op 0 gezet.

Anoniem

Een klein schopje. Ik heb het programma verder uitgewerkt en altijd getest op een 12ch controller. Dit heeft altijd goed gewerkt.

Later heb ik de schakeling getest op 2 andere lichttafels, namelijk op een Jands Event 408 en een Fatfrog van Zero88. Dit zijn tafels welke alle 512 kanalen uitsturen. Daar kreeg ik te maken met een vreemd probleem. Wanneer ik een kanaal op de lichttafel open zet, gaat de bijbehorende uitgang op een hoog tempo aan en uit.

Hier de code waar het om gaat:

code:


#define aantalkanalen 8


unsigned int ch_count=0, offset, i,adres;
unsigned char data[aantalkanalen]={0}, startcode, nutteloos, brk=0;
const unsigned char mask[8]={1,2,4,8,16,32,64,128};

void init_usart()
{
SPBRG = 0x04;
TXSTA.BRGH = 1;

TXSTA.SYNC = 0;
PIE1=0;
PIE1.RCIE = 1;
RCSTA.RX9 = 1;

nutteloos=RCREG;
nutteloos=RCREG;
nutteloos=RCREG;

RCSTA.CREN = 1;
RCSTA.SPEN = 1;


INTCON.PEIE=1;
INTCON.GIE=1;
}

void init_timer0()
{
OPTION_REG.PSA=0;
OPTION_REG.PS0=1;
OPTION_REG.PS1=1;
OPTION_REG.PS2=1;
OPTION_REG.T0CS = 0;
TMR0 = 0;
INTCON.TMR0IF=0;
INTCON.TMR0IE=1;
INTCON.GIE=1;
}



void interrupt()
{

if (PIR1.RCIF)
  {
  TMR0=0;                 // Hier wordt de timer terug gezet op 0.
  if (RCSTA.OERR)
     {
     RCSTA.SPEN=0;
     RCSTA.SPEN=1;
     nutteloos=RCREG;
     nutteloos=RCREG;
     nutteloos=RCREG;
     ch_count=0;
     brk=0;
     }
     
  else
     {
     if (RCSTA.FERR)
        {
        nutteloos=RCREG;
        ch_count=0;
        offset=0;
        brk=0xFF;
        }
     else
        {
        if (brk==0xFF)
           {
           if (ch_count==0) startcode=RCREG;
           else
               {
               if (adres<1)
                  {
                  nutteloos = RCREG;
                  for (i=0; i<aantalkanalen; i++) data[i]=0;
                  }
               else
                   {
                   //------------------------------ Hier adres controleren en evt. uitlezen
                   if (ch_count>=adres & ch_count<adres+aantalkanalen & startcode==0)
                      {
                      data[offset] = RCREG;
                      offset++;
                      }
                  else nutteloos = RCREG;
                  }
                  //------------------------------
               }
           ch_count++;
           }
        else
            {
            nutteloos = RCREG;
            ch_count=0;
            }
        }
     }
  PIR1.RCIF=0;
  }
  
  else if (INTCON.TMR0IF)           // Indien er geen DMX-signaal meer binnen komt wordt hier de data op 0 gezet.
       {
       for (i=0; i<aantalkanalen; i++) data[i]=0;
       INTCON.TMR0IF=0;
       }
  
}




void main ()
{
TRISA = 0xFF;
TRISB = 0xFF;
TRISC = 0xFE;
TRISD = 0x00;
TRISE = 0x00;
init_usart();
init_timer0();
PORTD=0;


while(1)
  {
  adres = PORTB;
  if (PORTC.F0) adres=adres+256;
  
  for (i=0; i<aantalkanalen; i++)
      {
      if (data[i]>0x80) PORTD = (PORTD&(~mask[i])) + mask[i];
      else PORTD = PORTD&(~mask[i]);
      }
  }
}

Ik verdenk timer0 van het probleem, omdat alleen bij deze interrupt alles in de array 'data' op 0 wordt gezet. Ik heb ook getest met een versie, waarbij timer0 niet was ingeschakeld, met als gevolg dat het zonder problemen werkte.

De prescaler van timer0 staat op 256 ingestelt en de uC loopt op 20Mhz, dus timer0 zou normaal gezien om de 13.1072ms een interrupt moeten veroorzaken:
256*(1/(20.000.000 / 4 / 256)) = 0.0131072 sec.

Om de 44us wordt een interrupt gegenereerd, vanwege data die binnen komt, met uitzondering van de break (88us). Normaal gezien zou timer0 nooit een interrupt mogen veroorzaken, zolang er maar DMX-data binnen komt.

Maar op een of andere manier lijkt het of timer0 toch sneller een interrupt veroorzaakt, dan wat de bedoeling is. Wie kan mij hier bij helpen, want ik zie even niet waar het probleem zit.

Hoi,

ik ben niet zo sterk in programmeren, en C e.d. ken ik niet,
maar de omschrijving van mijn idee kan jou misschien toch
nog iets verderhelpen.

Nl: Is het een idee, om de array direct weer nul te maken,
nadat die is verzonden ?
Dan is die array altijd 0 als er niets meer binnenkomt.

Groeten,

Eddied

Anoniem

In de main wordt de data uit deze array continue gebruikt om PORTD aan te sturen. Dus zodra alles in die array op 0 wordt gezet, merk je dat meteen.

Mag ik je verwijzen naar mijn eerdere post: bij DMX mag het volgens spec een behoorlijk lange tijd 'stil' zijn op de lijn. MTBF, MTBP en de break mogen elk maarliefst 1 seconde (max) duren. De break is altijd minimaal 88 usec, maar dat kan dus VEEL langer zijn. MTBF en MTBP mogen 0 usec zijn, maar kan dus ook langer zijn.

Het kan dus goed zijn dat jouw 12ch controller gewoon door blijft zenden, terwijl die andere controllers bijvoorbeeld 100 msec break hebben: toegestaan volgens DMX spec, maar een stuk meer dan jouw 13 msec. Of bijvoorbeeld een langere MTBP als er geen data veranderd is. Ligt allemaal aan de implementatie in de controller.
Als jij volgens DMX specs wilt werken, zul je er dus altijd vanuit moeten gaan dat het 1 seconde stil kan zijn op de lijn. Dat betekent dan dus ook dat je water (misschien onbedoeld, misschien niet) blijft stromen. Wil je dit strakker afstellen, dan wordt je oplossing specifiek voor een bepaalde controller, dus eigenlijk niet helemaal conform DMX. Wat je wel altijd kunt doen is foutcontrole. Zodra er ergens iets fout gaat (timing errors etc) meteen de boel dicht, totdat je weer iets fatsoenlijks hebt ontvangen.

Dit alles zonder je code bekeken te hebben overigens.

If you want to succeed, double your failure rate.
Anoniem

Dat kan goed kloppen, want ik ben ook verschil tegen gekomen bij wat andere lichttafels. Ik wil het een keer nameten met een scope. De tijd van de timer ga ik iig +/- 1sec van maken. Ik heb het al werkend met een tijd van ongeveer 10ms.

Het is alleen gek dat je nergens terug kunt vinden hoe het protocol nou echt in elkaar zit.

Een andere fout wat ik tegen kwam is dat ie bij kanaal 500 ofzo er af en toe 1 kanaal langs telt. Dat moet ik nog uitzoeken.

[Bericht gewijzigd door Anoniem op zondag 29 juli 2007 04:23:08 (12%)

Je kan bij U.S.S.I.T. de officiele standaard kopen voor 26 USD Klik Dat is hoe het echt in elkaar steekt.

[Bericht gewijzigd door Henry S. op maandag 30 juli 2007 15:36:26 (61%)

Als je het echt zeker wilt weten is dat de enige manier. Voor de hobbyist is googlen op 'dmx timings' ook best een oplossing.

If you want to succeed, double your failure rate.