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

Decodifica del segnale DCC


Una delle parti piu' critiche del decoder e' quella che decodifica il segnale DCC. Per eseguire questa decodifica il segnale DCC verra' inviato al pin di interrupt esterno del PIC in modo da lanciare la routine di interrupt ad ogni fronte in salita e in discesa del segnale stesso. Il tempo trascorso tra un fronte in salita ed uno in discesa permettera' di capire se stanno arrivando degli zeri (semiperiodo del segnale > 95usec) oppure degli uno (semiperiodo del segnale < 65 usec). Per semplificare il codice verra' messa una soglia di decisione tra "0" e "1" esattamente a meta' di questo intervallo, cioe' a 80 usec.

Il segnale "elettrico" da decodificare e' di questo tipo:




Mentre il pacchetto di comunicazione sara' di questo tipo:




Combinando le due parti sopra descritte la macchina a stati finiti che decodifica il segnale sara' di questo tipo:




Ed infine il programma di prova per questa sezione (lo potete trovare anche completo negli allegati, gia' in forma di programma MikroBasic completo pronto per la compilazione o la programmazione). Questo programma ha le seguenti funzioni:

  1. Inizializza tutte le variabili necessarie e registri per funzioni speciali del PIC, accende il LED
  2. Decodifica il segnale DCC (preambolo, bytes del pacchetto,
  3. Memorizza il pacchetto in alcune variabili
  4. Controlla se il checksum del pacchetto e' corretto (cioe' uguale a zero)
  5. Se e' corretto spegne il LED per 20 millisecondi
  6. Continua il loop all'infinito



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


'===============================================================================
'===============================================================================
' 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" (massimo 10)
          end if

        case 1                                                                  ' STATO 1: Shift dei bit del pacchetto e introduci 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                                                             ' se e' un byte intero, check se il pacchetto e' finito
          end if
         
        case 2                                                                  ' STATO 2: il byte e' finito, check della fine pacchetto
          bit_count=0                                                           ' resetta il contatore dei bit...
          state=3                                                               ' se c'e' un "1" dopo la fine del byte -> pacchetto 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                                                             ' ...ed erano arrivati i 10 bit a "1" -> inizio pacchetto
          end if
          one_count=0                                                           ' in ogni caso azzera il conteggio degli "1"

        case 1                                                                  ' STATO 1: Shift del pacchetto introducendo 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                                                             ' se e' un byte intero, check se il pacchetto e' finito
          end if

        case 2                                                                  ' STATO 2: il byte e' finito, check 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

'===============================================================================
'===============================================================================
' 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...
    ledco=2                                                                     ' ...LED OFF per 20msec
  end if

end sub


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

main:

  PORTA=0                                                                       ' Resetta le uscite
  PORTB=0
  TRISA=0x40                                                                    ' tutti i pin della porta A output tranne il 5 (MCLR)
  TRISB=0x01                                                                    ' tutti i pin della porta B output tranne lo 0 (INT)
  PCON.OSCF=1                                                                   ' Frequenza del chip 4MHz
  OPTION_REG=0xC8                                                               ' Pull-up off, INT fronte in salita, prescaler su TIMER 0
  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
  INTCON=0x90                                                                   ' interrupt abilitati solo per il pin INT

  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
     
      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.

ċ
OSD1.zip
(24k)
Davide Fiorini,
06 mar 2010, 11:39
Comments