Home‎ > ‎Freeware‎ > ‎Decoder Accessori Open Source‎ > ‎

Decodifica Comandi DCC e gestione uscite


Il programma e' ora aggiornato per decodificare i comandi DCC e gestire le uscite in conseguenza a tali comandi. Le routines aggiunte sono le seguenti:

Decodifica del pacchetto DCC in arrivo


Questa routine controlla prima di tutto se il byte di XOR (control o check byte) e' corretto in modo da decodificare solo i pacchetti consistenti. Quindi il controllo vero e proprio viene effettuato dividendo i pacchetti DCC in arrivo a seconda della loro dimensione (escluso il byte di controllo che e' gia' stato controllato):

2 bytes:
  • RESET ( 0000.0000 // 0000.0000 ): questo comando disabilita tutte le uscite in maniera permanente, viene usato per lo stop di emergenza oppure prima dell'ingresso in service mode.
  • IDLE (  1111.1111 // 0000.0000 ): questo pacchetto non ha azioni specifiche serve esclusivamente per inviare un pacchetto generico nel caso che ci siano decoder che non ricevendo piu' pacchetti DCC validi communtino al funzionamento analogico
  • CONTROLLO ACCESSORI ( 10AAAAAA // 1AAACDDD ) con A indirizzo del decoder, D uscita da attivare e C attivazione o disattivazione: questo pacchetto attiva e disattiva le diverse uscite del decoder ed e' quello che la centrale di comando invia quando vogliamo azionare gli scambi o altri accessori.
3 bytes:
  • SERVICE MODE (DIRECT MODE) ( 0111CCAA // AAAAAAAA // DDDDDDDD ) con A indirizzo della CV, D dato da scrivere o controllare e C operazione da svolgere (scrittura o controllo a bytes o bit): questo comando scrive e rilegge le CV del decoder.


Gestione delle uscite

La gestione delle uscite e' molto semplice e puo' essere descritta così:
  • Le uscite che devono essere attivate sono segnalate come bit a "1" nella variabile cmd_set. Questa variabile e' settata 
    • dalla routine di decodifica dei pacchetti DCC come risposta ad un pacchetto di controllo accessori con il campo C=1
    • Una particolarita' nella routine di decodifica e' che se si invia una nuova attivazione su un'uscita gia' attivata questa verra' disattivata in modo da ovviare al problema che molte centrali inviano solo comandi di attivazione e non di disattivazione
  • Le uscite che devono essere disattivate sono segnalate come bit a "1" nella variabile cmd_reset. Questa variabile e' settata sia
    • dalla routine di decodifica dei pacchetti DCC come risposta ad un pacchetto di controllo accessori con il campo C=0
    • Dal controllo temporizzato delle uscite, che al momento della fine del periodo di attivazione dell'uscita stessa, invia questo comando per disattivarla

 
 
Quindi a questo punto il decoder implementa tutte le funzioni di accensione e spegnimento, all'indirizzo fisso 1 e con periodi di attivazione fissi di 0.3 secondi per le uscite 1 e 2, 0.6secondi per le uscite 3 e 4 , 1.2 secondi per le uscite 5 e 6 e indefinito per le uscite 7 e 8.




program OSD


dim  state as byte                                                              ' variabile di stato per la fsm che riconosce il DCC:
                                                                                ' 0:attesa preambolo,
                                                                                ' 1:load byte,
                                                                                ' 2:riconoscimento stop/start bit
                                                                                ' 3:pacchetto arrivato in attesa di decodifica
                                                                               
dim one_count as byte                                                           ' numero di bit "1" nel preambolo
dim bit_count as byte                                                           ' cantatore per gli 8 bit del byte da caricare
dim point as byte                                                               ' punta all'elemento dell'array che contiene l'ultimo byte DCC ricevuto
dim d0,d1,d2,d3 as byte                                                         ' variabili che contengono il pacchetto DCC (interrupt)
dim x0,x1,x2,x3 as byte                                                         ' variabili che contengono il pacchetto DCC (decodifica)
dim pack_len as byte                                                            ' lunghezza del pacchetto durante la decodifica
dim ok as byte                                                                  ' Se OK=0 allora il pacchetto ha il checksum OK
dim i as byte                                                                   ' controllo dei loop
dim ledco as byte                                                               ' controllo del LED
dim address as word                                                             ' indirizzo del decoder ricavato dal pacc. DCC
dim cvadd as word                                                               ' indirizzo del decoder ricavato dalle CV
dim reset_out as byte                                                           ' Flag per resettare le uscite
dim uscite as byte                                                              ' Questo e' il controllo delle stato delle 8 uscite
dim mask as byte                                                                ' Variabile di appoggio
dim service as byte                                                             ' se 1 siamo in Service Mode
dim cmd_set,cmd_reset as byte                                                   ' Set o reset delle singole uscite
dim count1,count2,count3,count4,count5,count6,count7,count8 as byte             ' Conteggio del tempo di attivazione per le uscite
dim count_cv3,count_cv4,count_cv5,count_cv6 as byte                             ' CV con il tempo di attivazione per le diverse uscite



'===============================================================================
'===============================================================================
' ROUTINE DI INTERRUPT per LA DECODIFICA DCC
'===============================================================================
'===============================================================================

sub procedure interrupt

  INTCON.INTF=0                                                                 ' fai ripartire il controllo dell'interrupt sul pin "INT"
 
  if OPTION_REG.INTEDG then                                                     ' se c'e' un fronte in salita allora...
    OPTION_REG.INTEDG=0                                                         ' predisponi per aspettare un fronte in discesa
    TMR0=176                                                                    ' setta il TIMER0 a 176 in modo vada in overflow dopo 80us
    INTCON.T0IF=0                                                               ' resetta il flag di overflow per Timer0
  else
    OPTION_REG.INTEDG=1                                                         ' se c'e' un fronte in discesa allora...
    if INTCON.T0IF=0 then                                                       ' se non c'e' overflow di Timer0 allora e' un "1"...

      select case state                                                         ' macchina a stati finiti

        case 0                                                                  ' STATO 0: attesa di un preambolo. Se arriva un "1"...
          if one_count<>10 then
            inc(one_count)                                                      ' ...allora incrementa il numero di "1" fino max di 10
          end if

        case 1                                                                  ' STATO 1: Shift byte del pacchetto e introducendo un "1"
          select case point
            case 0
              d0=(d0 << 1)+1
            case 1
              d1=(d1 << 1)+1
            case 2
              d2=(d2 << 1)+1
            case 3
              d3=(d3 << 1)+1
          end select
          inc(bit_count)                                                        ' incrementa il numero di bit
          if (bit_count=8) then                                                 ' se e' finito il byte,
            state=2                                                             '  byte intero, controlla se il pacchetto e' finito
          end if
         
        case 2                                                                  ' STATO 2: il byte e' finito, controllo fine pacchetto
          bit_count=0                                                           ' resetta il contatore dei bit...
          state=3                                                               ' se c'e' un "1"  il pacchetto e' finito
      end select
     
    else
                                                                                ' altrimenti se c'e' overflow di Timer0 e' uno "0"
      select case state                                                         ' macchina a stati finiti

        case 0                                                                  ' STATO 0: attesa del bit di start. Se arriva uno "0"...
          if one_count=10 then
            state=1                                                             ' ...arrivati almeno 10 bit a "1" allora inizio pacchetto
          end if
          one_count=0                                                           ' in ogni caso azzera il conteggio degli "1"

        case 1                                                                  ' STATO 1: Shift i byte del pacchetto e introduci uno "0"
          select case point
            case 0
              d0=(d0 << 1)
            case 1
              d1=(d1 << 1)
            case 2
              d2=(d2 << 1)
            case 3
              d3=(d3 << 1)
          end select
          inc(bit_count)                                                        ' incrementa il numero di bit
          if (bit_count=8) then                                                 ' se e' finito il byte,
            state=2                                                             ' , controlla se il pacchetto e' finito
          end if

        case 2                                                                  ' STATO 2: il byte e' finito, controllo fine pacchetto
          bit_count=0                                                           ' resetta il contatore dei bit...
          inc(point)                                                            ' e passa al prossimo byte
          if (point=4) then                                                     ' Se il pacchetto e' troppo lungo, consideralo arrivato
            state=3
          else
            state=1                                                             ' Se non e' troppo lungo allora shifta il prossimo byte
          end if
      end select

    end if
  end if

end sub


'===============================================================================
'===============================================================================
' INIZIALIZZA LE CV   (per ora non serve...)
'===============================================================================
'===============================================================================

sub procedure inizializza_CV

end sub


'===============================================================================
'===============================================================================
' RILEGGI LE CV  (per ora valori fissi...)
'===============================================================================
'===============================================================================

sub procedure leggi_CV
  cvadd=1                                                                       ' indirizzo 1
  count_cv3=30                                                                  ' Uscite 1 e 2 attive per 300msec
  count_cv4=60                                                                  ' Uscite 3 e 4 attive per 600msec
  count_cv5=120                                                                 ' Uscite 5 e 6 attive per 1,2sec
  count_cv6=0                                                                   ' Uscite 7 e 8 attive indefinitamente
end sub


'===============================================================================
'===============================================================================
' DECODIFICA IL PACCHETTO IN ARRIVO
'===============================================================================
'===============================================================================

sub procedure decodifica

  pack_len=point                                                                ' salva la lunghezza del pacchetto
  x0=d0                                                                         ' copia il pacchetto
  x1=d1
  x2=d2
  x3=d3
  point=0                                                                       ' ripristina le variabili per acquisire un nuovo pacchetto
  state=0                                                                       ' riparti per l'acquisizione del prossimo pacchetto

  select case pack_len                                                          ' controllo per il byte di controllo
    case 2
      ok=x0 xor x1 xor x2                                                       ' per pacchetti di 3 byte
    case 3
      ok=x0 xor x1 xor x2 xor x3                                                ' e per pacchetti di 4 byte
    case else
      ok=1                                                                      ' negli altri casi non si decodifica
  end select
 
  if ok=0 then                                                                  ' Se il pacchetto e' corretto allora...
 
    select case pack_len

      case 2                                                                    ' decodifica i pacchetti da 3 bytes====================

        if (x0=0x0) and (x1=0x0) then                                           ' Questo e' il pacchetto di RESET
          reset_out=1                                                           ' "sospendi" tutti gli output
          cmd_reset=0xFF                                                        ' resetta tutte le uscite
          service=0                                                             ' Non siamo in service
          ledco=10                                                              ' spegni il LED per 100msec
        end if

        if (x0=0xFF) and (x1=0x0) then                                          ' Questo e' l'IDLE
          service=0                                                             ' Non siamo in service
        end if

        if ((x0 and 0xC0)=0x80) and ((x1 and 0x80)=0x80) then                   ' Pacchetto per accessori standard
          address=(x0 and 0x3F)+(not(x1) and 0x70) << 2                         ' calcola subito l'address
          if address=cvadd then                                                 ' Se e' indirizzato a questo decoder
            reset_out=0                                                         ' Attiva gli output
            service=0                                                           ' Non siamo in service
            ledco=10                                                            ' spegni il LED per 100msec
            mask=1 << (x1 and 0x7)                                              ' seleziona quale e' il bit giusto su cui agire
            if x1.3=1 then                                                      ' si deve settare o resettare?
              if (uscite and mask)<>0 then                                      ' se l'uscita e' gia' settata...
                cmd_reset=mask                                                  ' ...allora resettala
              else
                cmd_set=mask                                                    ' se non e' settata allora settala
              end if
            else
              cmd_reset=mask                                                    ' agisci qui se si deve resettare
            end if
          end if

        end if

      case 3                                                                    ' decodifica pacchetti da 4 bytes======================

        if (x0 and 0xF0)=0x70 then                                              ' Questo e' un pacchetto di service mode (direct)
          if service=1 then                                                     ' Se e' il secondo pacchetto di service allora...
                                                                                ' decodifica il service per leggere/scrivere le CV
          end if
          if reset_out=1 then                                                   ' Service abilitato solo se e' stato ricevuto un reset
            service=1                                                           ' Il primo pacchetto non e' decodificato
            ledco=20                                                            ' spegni il LED per 200msec
          end if
        end if

    end select
  end if

end sub


'===============================================================================
'===============================================================================
' GESTIONE DELLE USCITE
'===============================================================================
'===============================================================================

sub procedure gestisci_uscite

    if cmd_set<>0 then
      if (cmd_set and 0x01)<>0 then                                             ' Se si deve settare l'uscita...
        count1=count_cv3                                                        ' ...copia il suo periodo di attivazione
        uscite.0=1                                                              ' e attivala
      end if
      if (cmd_set and 0x02)<>0 then                                             ' Lo stesso per l'uscita 2
        count2=count_cv3
        uscite.1=1
      end if
      if (cmd_set and 0x04)<>0 then                                             ' Lo stesso per l'uscita 3
        count3=count_cv4
        uscite.2=1
      end if
      if (cmd_set and 0x08)<>0 then                                             ' Lo stesso per l'uscita 4
        count4=count_cv4
        uscite.3=1
      end if
      if (cmd_set and 0x10)<>0 then                                             ' Lo stesso per l'uscita 5
        count5=count_cv5
        uscite.4=1
      end if
      if (cmd_set and 0x20)<>0 then                                             ' Lo stesso per l'uscita 6
        count6=count_cv5
        uscite.5=1
      end if
      if (cmd_set and 0x40)<>0 then                                             ' Lo stesso per l'uscita 7
        count7=count_cv6
        uscite.6=1
      end if
      if (cmd_set and 0x80)<>0 then                                             ' Lo stesso per l'uscita 8
        count8=count_cv6
        uscite.7=1
      end if
      cmd_set=0
    end if


    if count1<>0 then                                                           ' Controllo se i periodi di attivazione delle diverse
      dec(count1)                                                               ' uscite sono finiti. Se il periodo e' finito...
      if (count1=0) then
        cmd_reset.0=1                                                           ' ...allora resetta l'uscita
      end if
    end if
    if count2<>0 then                                                           ' Lo stesso per l'uscita 2
      dec(count2)
      if (count2=0) then
        cmd_reset.1=1                                                           ' ...allora resetta l'uscita
      end if
    end if
    if count3<>0 then                                                           ' Lo stesso per l'uscita 3
      dec(count3)
      if (count3=0) then
        cmd_reset.2=1                                                           ' ...allora resetta l'uscita
      end if
    end if
    if count4<>0 then                                                           ' Lo stesso per l'uscita 4
      dec(count4)
      if (count4=0) then
        cmd_reset.3=1                                                           ' ...allora resetta l'uscita
      end if
    end if
    if count5<>0 then                                                           ' Lo stesso per l'uscita 5
      dec(count5)
      if (count5=0) then
        cmd_reset.4=1                                                           ' ...allora resetta l'uscita
      end if
    end if
    if count6<>0 then                                                           ' Lo stesso per l'uscita 6
      dec(count6)
      if (count6=0) then
        cmd_reset.5=1                                                           ' ...allora resetta l'uscita
      end if
    end if
    if count7<>0 then                                                           ' Lo stesso per l'uscita 7
      dec(count7)
      if (count7=0) then
        cmd_reset.6=1                                                           ' ...allora resetta l'uscita
      end if
    end if
    if count8<>0 then                                                           ' Lo stesso per l'uscita 8
      dec(count8)
      if (count8=0) then
        cmd_reset.7=1                                                           ' ...allora resetta l'uscita
      end if
    end if


    if cmd_reset<>0 then
      if (cmd_reset and 0x01)<>0 then                                           ' Se si deve resettare l'uscita...
        count1=0                                                                ' azzera il suo periodo di attivazione...
        uscite.0=0                                                              ' e spegnila
      end if
      if (cmd_reset and 0x02)<>0 then                                           ' Lo stesso per l'uscita 2
        count2=0
        uscite.1=0
      end if
      if (cmd_reset and 0x04)<>0 then                                           ' Lo stesso per l'uscita 3
        count3=0
        uscite.2=0
      end if
      if (cmd_reset and 0x08)<>0 then                                           ' Lo stesso per l'uscita 4
        count4=0
        uscite.3=0
      end if
      if (cmd_reset and 0x10)<>0 then                                           ' Lo stesso per l'uscita 5
        count5=0
        uscite.4=0
      end if
      if (cmd_reset and 0x20)<>0 then                                           ' Lo stesso per l'uscita 6
        count6=0
        uscite.5=0
      end if
      if (cmd_reset and 0x40)<>0 then                                           ' Lo stesso per l'uscita 7
        count7=0
        uscite.6=0
      end if
      if (cmd_reset and 0x80)<>0 then                                           ' Lo stesso per l'uscita 8
        count8=0
        uscite.7=0
      end if
      cmd_reset=0
    end if

'===============================================================================
'===============================================================================
' MODIFICARE QUESTO BLOCCO PER CAMBIARE I PIN DEL DECODER
'===============================================================================
'===============================================================================

    PORTA.7=uscite.0                                                            ' Copia l'Uscita 1
    PORTA.6=uscite.1                                                            ' Copia l'Uscita 2
    PORTA.0=uscite.2                                                            ' Copia l'Uscita 3
    PORTA.1=uscite.3                                                            ' Copia l'Uscita 4
    PORTB.4=uscite.4                                                            ' Copia l'Uscita 5
    PORTB.5=uscite.5                                                            ' Copia l'Uscita 6
    PORTB.7=uscite.6                                                            ' Copia l'Uscita 7
    PORTB.6=uscite.7                                                            ' Copia l'Uscita 8
   
end sub


'===============================================================================
'===============================================================================
' PROGRAMMA PRINCIPALE
'===============================================================================
'===============================================================================

main:

  PORTA=0                                                                       ' Resetta le uscite
  PORTB=0

  TRISA=0x20                                                                    ' tutti i pin della porta A output tranne il 5 (MCLR)
  TRISB=0x01                                                                    ' tutti i pin della porta B output tranne lo 0 (INT)

  CMCON=0x7                                                                     ' Comparatori e pin analogici OFF
  PCON.OSCF=1                                                                   ' Frequenza del chip 4MHz
  OPTION_REG=0xC8                                                               ' Pull-up disabilitati, INT triggerato...
  TMR1H=217                                                                     ' il Timer1 va in overflow ogni 65536-217*256=10000 us
  TMR1L=0
  T1CON=0x01                                                                    ' Timer1 conta con un rate di 1us

  one_count=0                                                                   ' nessun "1" arrivato nel preambolo
  bit_count=0                                                                   ' primo bit del byte
  point=0                                                                       ' primo byte del pacchetto
  state=0                                                                       ' partiamo dallo stato di attesa del preambolo
  ledco=0                                                                       ' LED acceso
  service=0                                                                     ' Non siamo in service
  reset_out=0                                                                   ' Uscite abilitate
  cmd_set=0
  cmd_reset=0
  uscite=0                                                                      ' Tutto spento
  count1=0
  count2=0
  count3=0
  count4=0
  count5=0
  count6=0
  count7=0
  count8=0
  INTCON=0x90                                                                   ' interrupt abilitati solo per il pin INT
 
  inizializza_CV                                                                ' Inizializza le CV (solo se alla prima accensione)
  leggi_CV                                                                      ' Rileggile

  while TRUE                                                                    ' ciclo senza fine per il funzionamento decoder

    if state=3 then                                                             ' se un pacchetto e' completo allora...
      decodifica                                                                ' ...decodificalo
    end if
   
    if PIR1.TMR1IF then                                                         ' base dei tempi per le azioni temporizzate ogni 10msec
      T1CON=0x0                                                                 ' disabilita il timer1
      PIR1.TMR1IF=0                                                             ' resetta il flag di overflow
      TMR1H=217                                                                 ' fai ripartire il conteggio per i 10msec
      TMR1L=0
      T1CON=0x01                                                                ' fai ripartire il Timer1
     
      gestisci_uscite                                                           ' Ogni 10msec -> Gestione delle uscite
     
      if ledco<>0 then                                                          ' Gestione del LED ogni 10 msec
        PORTB.3=0                                                               ' Se il contatore e' <>0 allora LED spento
        dec(ledco)                                                              ' Sono passati altri 10 msec
      else
        PORTB.3=1                                                               ' se e' arrivato a 0 riaccendi il LED
      end if

    end if


  wend

end.

ċ
OSD2.zip
(45k)
Davide Fiorini,
13 mar 2010, 03:46
Comments