INDICE

 

Prefazione del consiglio di classe

Introduzione

Abstrac

 

Capitolo 1: Il lavoro nell’insieme

1.1 Logica di funzionamento

1.2 Schema a blocchi

1.3 Protocollo di comunicazione

1.4 I programmi di simulazione

1.4.1 Simulatore PC

       1.4.2 Simulatore insegna

 

Capitolo 2: L’Hardware

2.1 L’Hardware del sistema

2.2 La main board

2.3 Il pannello a led

2.4 La realizzazione dei circuiti stampati

2.5 I circuiti integrati del progetto

2.5.1 Il microprocessore

2.5.2 Gli altri integrati

 

 

Capitolo 3: Il Software ad alto livello

3.1 Presentazione

3.2 Schema a blocchi

3.3 Logica di funzionamento

3.4 Struttura dati

 

Capitolo 4: Il Software nel PIC

4.1 - Descrizione di massima

4.2 – Analisi dei singoli blocchi

4.3 – La gestione della RAM

4.4 – La struttura dati

 

 

Capitolo 5: Approfondimento teorico

5.1 La trasmissione seriale

 

 

 

Appendici:

 

1)     Programma simulatore pannello led

2)     Programma simulatore PC

3)     Firmware insegna

4)     Programma VB di gestione insegna

5)     Schema elettrico main board

6)     Schema elettrico driver led

7)     Pcb main board

8)     Pcb driver led

9)     Data sheet ram 6264

10)   Foto varie


 

Prefazione del Consiglio di Classe

Sempre più negli ultimi anni si è reso necessario avvicinare la scuola al mondo del lavoro.

Per ottenere questo risultato sono percorribili varie strade: una è la partecipazione dei futuri periti a stage aziendali, ma nel caso di corso serale per studenti lavoratori, i candidati partecipano necessariamente alla vita delle aziende dove sono impiegati.

Una seconda strada potrebbe essere quella di far partecipare attivamente gli alunni allo sviluppo di un progetto come se fossero realmente a lavorare in un’azienda. Questa seconda metodologia ha dato come risultato questa  dispensa: il Consiglio di Classe ha individuato un progetto di una certa complessità da sviluppare nell’intero arco di due anni scolastici nell’ambito delle ore di laboratorio, principalmente TDP e sistemi. Per lo sviluppo del lavoro gli studenti hanno dovuto seguire il tipico iter aziendale:

 

·        Analisi delle specifiche

·        Progettazione

·        Realizzazione

·        Documentazione

 

L’impostazione a blocchi dello sviluppo del progetto, ormai pratica comune in qualsiasi attività produttiva, ha permesso di dividere il lavoro tra i vari studenti: ogni singolo “pezzo” dell’intero sistema è stato affidato di volta in volta a uno o più studenti, responsabili “in toto” della loro parte: alcuni si sono occupati del software (fortemente presente come componente immateriale in tutto questo lavoro), alcuni dell’hardware, altri della documentazione, badando comunque che alla fine tutti avessero fatto un po’ di tutto. Questa suddivisione ha permesso ulteriormente di assecondare gli interessi personali degli studenti con il risultato accessorio di una maggior produttività.

Il ruolo dell’insegnante è stato di coordinatore dell’attività; l’intervento diretto è stato volutamente ridotto al minimo, e comunque solo per quelle poche parti che oggettivamente erano fuori della portata degli studenti. Questa scelta ha portato ad ottenere un prodotto che, anche se per alcuni aspetti può essere incompleto o evidentemente perfettibile, nell’insieme è più che apprezzabile.

 

 


Introduzione

 


Il progetto analizzato da questa dispensa, permette la realizzazione di un pannello luminoso a diodi led, per la visualizzazione di figure in movimento.

 


Questo lavoro ci ha permesso di applicare praticamente molti concetti teorici studiati nelle varie materie e di sperimentare dal vivo le varie fasi dello sviluppo di un progetto di una certa complessità.

Il lavoro si è sviluppato secondo i seguenti passi:

1.   Definizione delle specifiche,

2.   Stesura di un progetto di massima,

3.   Sviluppo dei prototipi dell’hardware e del software,

4.   Scrittura della documentazione contestualmente all’avanzamento del lavoro,

5.   Sistemazione definitiva del prototipo e assemblaggio finale.

 

Il lavoro è costituito di componenti hardware e software; l’hardware è costituito prevalentemente dalle schede elettroniche; il software comprende sia il programma ad alto livello (scritto in Visual Basic) per la generazione dei disegni, sia il firmware residente nel sistema di pilotaggio dell’insegna, contenuto nell’insegna stessa. Per la realizzazione del progetto la classe è stata divisa in piccoli gruppi:

 

1.   Sviluppo software,

2.   Sviluppo hardware,

3.   Montaggio hardware,

4.   Stesura documentazione,

5.   Gruppo jolly.

 

In realtà non sono stati veri e propri gruppi rigidi ma gli studenti hanno fatto “un po’ di tutto”, in particolare gli studenti che di volta in volta hanno fatto il jolly.

 

 

 


Abstract

 


 

 


Logic of working

 

We have developed a high level program in Visual Basic able to create a short movie to begin from frames.

This program will send the movie to the bright panel.  For this task, a simple communication protocol has been developed:  for the dialogue with the Pc there is a microchip inside the bright panel, which also manages the electronics for led lighting. To increase the capability of storing frame, we have equipped the bright panel of a RAM memory, protected by a tampon battery to preserve, in case of blackout,  the stored data.

 


 

                    Capitolo 1: Il lavoro nell’insieme

 

 

1.1: Logica di funzionamento

1.2: Schema a blocchi

1.3: Protocollo di comunicazione

1.4: Programmi di simulazione

1.4.1: Simulatore PC

1.4.5: Simulatore insegna

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1.1 – Logica di funzionamento

 

Il programma ad alto livello è in grado di creare un breve filmato a partire dai fotogrammi.

 


 

 

 



Questo filmato verrà poi spedito al pannello luminoso. A questo proposito è stato sviluppato un semplice protocollo di comunicazione.

A bordo del pannello luminoso è presente un microprocessore in grado di dialogare col PC e di pilotare l’elettronica per l’accensione dei led. Per aumentare la capacità di memorizzare fotogrammi, abbiamo dotato il pannello luminoso di una memoria RAM, protetta da una batteria tampone che garantisca la conservazione dei dati anche in assenza di alimentazione.

 

 

1.2 - Schema a blocchi

 

Il PC dotato del programma per il pilotaggio dell'insegna (vedi cap.3), è collegato al pannello con una linea seriale RS-232.

 


 

 

 


L'insegna è composta da 3 blocchi principali:

1) Microprocessore;

2) Pannello a led;

3) Memoria RAM.

 

Nell'insegna il lavoro è coordinato da un microprocessore che ha i seguenti compiti:

1) Dialogo con il pc;

2) Pilotaggio del pannello a led.

3) Lettura e scrittura RAM

 

I disegni inviati dal pc vengono memorizzati in una ram statica dotata di batteria tampone per proteggerla dalla perdita dei dati in caso di mancanza di alimentazione esterna.

 

 

1.3 - Protocollo di comunicazione

 

Il dialogo tra PC e insegna e attuato secondo il seguente protocollo di trasmissione:

·        Cancello tutta la memoria:         $CLS#

·        Inizio trasmissione:                            $START#

·        Numero righe:                                     $NR_ _#

·        Numero colonne:                        $NC_ _#

·        Inizio fotogramma:                      $FOTO# 

·        Invio pixel fotogramma:                vedi sotto

·        Fine fotogramma:                        $ENDFOTO#

·        Fine trasmissione:                      $END#

·        Conferma invio corretto:             $ACK#

·        Errore di comunicazione:                    $NAK#

·        Reset del sistema:                       $RESET#

 

 

Per assicurarci della corretta trasmissione dei comandi, il PIC deve sempre rispondere: con ACK se il comando è stato ricevuto correttamente, con NAK in caso di errore.

 

L’invio dei byte relativi ad un fotogramma avviene con la seguente logica:

 

1° byte             riga 1

2° byte             riga 1

3° byte             riga 1

ecc.

 

1° byte             riga 2

2° byte             riga 2

3° byte             riga 2

ecc.

 

1°byte              ultima riga

.

.   

n° byte             ultima riga

 

Per ogni byte inviato il PIC risponderà con $ACK# che conferma la ricezione e memorizzazione del byte

 

 

 

 

 

ESEMPIO

 

Casella di testo: COMPUTER

 


0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

1

0

0

1

1

1

1

1

0

0

0

0

0

0

0

1

1

0

0

1

0

0

0

1

0

0

0

0

0

0

1

0

1

0

0

1

0

0

0

1

0

0

0

0

0

1

0

0

1

0

0

1

0

0

0

1

0

0

0

0

0

0

0

0

1

0

0

1

1

1

1

1

0

0

0

0

0

0

0

0

1

0

0

0

0

0

0

1

0

0

0

0

0

0

0

0

1

0

0

0

0

0

0

1

0

0

0

0

0

0

0

0

1

0

0

0

0

0

0

1

0

0

0

0

0

0

0

0

1

0

0

1

1

1

1

1

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

 

 

 

Nel caso specifico dell’esempio di figura il flusso dati sarà il seguente:


PC                           PIC

 

$CLS#                     $ACK#    ;inizio trasmissioni

$START#                $ACK#   

$NR16#                    $ACK#   ; 16 righe

$NC16#                          $ACK#    ;16 colonne

$FOTO#                  $ACK#    ;inizio fotogramma

 

00000000               $ACK#    ;1° byte prima riga

00000000              $ACK#    ;2°                 

.

.

.

$ENDFOTO#           $ACK#    ; fine fotogramma                                                                        

 

00000000               $ACK#    ;1° byte seconda riga

00000000               $ACK#    ;2°                 

.

.

$ENDFOTO#           $ACK#    ; fine fotogramma                                                                        

 

00000100                       $ACK#    ;1° byte terza riga

11111000               $ACK#    ;2°                 

.

.

$ENDFOTO#           $ACK#    ; fine fotogramma                                                                        

 

00001100               $ACK#    ;1° byte quarta riga

10001000               $ACK#    ;2°                 

.

.

$ENDFOTO#           $ACK#    ; fine fotogramma                                                                        

  

 

Nota: la configurazione di pixel è inviata come singolo byte.

 

 

1.4 – I programmi di simulazione

 


Per velocizzare lo sviluppo del progetto, abbiamo messo a punto due programmi di simulazione come indicato nella figura seguente.

 

 


Questo ci ha permesso di ovviare alle inevitabili asincronie nello sviluppo dei vari blocchi: non è infatti ragionevole supporre che lo sviluppo dell’hardware proceda con gli stessi tempi di quello del software e con l’utilizzo dei programmi simulatori abbiamo superato il problema. I due programmi simulano il corrispondente oggetto reale solo dal punto di vista del dialogo con il mondo esterno, conoscono cioè il protocollo di trasmissione; in questo modo l’oggetto esterno che comunica con loro vedrà gli stessi comportamenti come se comunicasse con il dispositivo reale. L’uso dei programmi simulatori ci ha anche permesso di testare  situazioni critiche e causa di possibili errori, situazioni non sempre facili da riprendere “dal vivo” con i dispositivi reali. 

 

 

1.4.1 – Dettagli simulatore PC

 

Il simulatore PC, ha un ruolo di MASTER: L’insegna non invia messaggi spontanei, risponde solo a comandi inviatigli. Il programma permette sia di disegnare delle figure a mano


 


che di scegliere tra una serie di figure predeterminate:

 


 

 

 



Il programma permette di inviare dei comandi all’insegna selezionabili da un elenco.

Per inviare il comando si preme un tasto.

Il simulatore invierà il comando e valuterà la risposta dell’insegna.

 

 

1.4.2 - Dettagli simulatore insegna


 

Il programma simulatore dell’insegna è utile per mettere a punto il software grafico che deve gestire l’invio all’insegna dei disegni. Come accennato in precedenza, il processore a bordo dell’insegna ha un ruolo di SLAVE, cioè non prende iniziativa autonoma nei confronti del mondo esterno, ma aspetta dei comandi ai quali deve rispondere.

 

 

 

 

 

Capitolo2: L’Hardware

 

2.1: L’hardware del sistema

2.2: La main board

2.3: Il pannello a led

2.4: La realizzazione dei circuiti stampati

2.5: I circuiti integrati del progetto

2.5.1: Il microprocessore

          2.5.2: Gli altri integrati

 


 

2.1 – Hardware del sistema

 

Lo schema a blocchi ad alto livello è riportato nella figura seguente:

 

 

 


 

 


 Compiti della scheda:

-        Dialoga col il PC centrale;

-        Pilota il pannello a LED.

Per aumentare la capacità di memorizzare fotogrammi, abbiamo dotato il pannello luminoso di una memoria RAM.

 



 

 

 


2.2 – Descrizione Main-board

 

Nucleo del sistema di controllo è il microcontrollore PIC 16F 876 che trova alloggio all’interno della main board assieme a quei componenti che servono a ricevere, memorizzare e inviare i vari fotogrammi alle schede di pilotaggio dei led.  Lo schema a blocchi seguente illustra la struttura della main board.

 

 

 



 

 


Le caratteristiche dei componenti della main board sono riportate nel paragrafo 2.5.

Si nota l’estrema semplicità del sistema dovuta essenzialmente alla notevole dotazione del microcontrollore utilizzato. L’adattatore di livello è necessario per rendere compatibili le tensioni presenti sulla linea RS232 (+12 V;-12 V) con quelle del PIC (0-5 V).  La RAM esterna sopperisce alla modesta dotazione di memoria del PIC (circa 350 bytes) non modesta in assoluto ma, data la peculiarità della nostra applicazione, non sufficiente. In essa infatti, vengono memorizzati tutti i fotogrammi da mostrare sull’insegna. La ram è una 6264 con capacità di 8 KB; con questa dimensione è possibile memorizzare ad esempio:

insegna da 1 modulo (64 led): 1000 fotogrammi; oppure

insegna da 3*3 moduli (976 led):  125 fotogrammi.

 

Valori più che accettabili per le nostre esigenze.

 

 

Adattatore di livello per RS-232

Lo standard RS232 prevede i seguenti livelli di tensione:

                0 logico = +12 V

                1 logico = -12 V

mentre i livelli accettati dal microcontrollore PIC 16F876 sono:

                0 logico = 0 V

                1 logico = 5 V

che sono evidentemente incompatibili tra loro.

In realtà i PC accettano anche livelli logici TTL (0-5 V) ma rimane il problema dell’inversione dei valori logici (RS232 1 logico = tensione bassa; PIC 1 logico = tensione alta) che possono essere risolti a livello software. Pur essendo disponibili in commercio appositi circuiti integrati che eseguono la conversione, (ad esempio il Maxim  MAX 232) abbiamo preferito adottare una soluzione più semplice e didatticamente più valida.


Il BJT ha la funzione di traslare i livelli di ingresso in livelli TTL inoltre inverte il livello logico del segnale:

 


Vin = +12 V------->Vout  = 0 V  (BJT in saturazione)

Vin = - 12 V-------> Vout = 5 V  (BJT in interdizione)

 

Per i dati in uscita dal microcontrollore, il circuito risulta decisamente più semplice; in pratica solo un filo. Si è già detto infatti, che il PC accetta anche livelli TTL, quindi basta convertire il valore logico del segnale in uscita dal PIC (conversione fatta mediante software) e inviare al direttamente al PC.

 

 

 

RAM esterna


Per poter pilotare una RAM è necessario fornirle i segnali indicati in figura:

·        Address = indirizzo della locazione di memoria da leggere o scrivere. 13 linee.

·        Data = Valore del dato da leggere o scrivere. 8 linee

·        CS= Chip select (seleziona il componente) 1 linea

·        R/W = seleziona la modalità lettura o scrittura della RAM 1 linea

·        OE = Output Enable. Abilita le uscite in caso di lettura. 1 linea.

 

In totale le linee da pilotare sono 24.

Il nostro μp non ha a disposizione tutte queste linee di I/O. Per ovviare a questo inconveniente, considerando che in effetti non serve una velocità di accesso alla RAM particolarmente elevata, abbiamo generato i segnali degli address con uno shift-register che praticamente esegue una conversione seriale/parallela.

 


 


Questa soluzione ci ha permesso di ridurre il numero di fili a soli 13 con un risparmio di 10 fili. Da notare che non avendo a disposizione uno shift-register da 13 bit, lo abbiamo realizzato  prendendo in serie 2 shift-register da 8 bit di tipo 4094.        

 

 

Calcolo del tempo di accesso alla RAM.

Supponendo di avere un clock a 1MHZ, il periodo è di 1μsec, quindi per generare i 13 bit degli address servono 13 μsec; ipotizzando ancora 2 μsec per la generazione degli altri segnali e 1 μsec per la lettura (o scrittura) del dato si arriva a 16 μsec. Supponendo ancora di disporre del pannello composto da 3X3 moduli è necessario caricare 72 bytes quali 72X16 μsec = 1152 cioè poco più di 1 msec che, confrontato con il tempo di durata  medio di 1 fotogramma (circa 1/20 sec = 50 msec) è decisamente trascurabile.

Dato quanto sopra, uno schema a blocchi della main-board meno sintetico di quello visto in precedenza, è il seguente:


 


Lo schema seguente evidenzia nel dettaglio il collegamento tra i vari dispositivi, con l’indicazione delle risorse di IO messe a disposizione dal PIC:



 


2.3 - Pannello

 

 


 



Solitamente in simili pannelli a LED, gli elementi luminosi sono alimentati per brevi periodi con correnti impulsive elevate , tipicamente  T<1/20 sec:

 


 


La persistenza dell’immagine sulla retina fa si che il LED si veda sempre acceso.

Un’altra possibilità è di pilotare singolarmente ogni LED con un piccolo buffer dedicato.


La prima soluzione ha in linea di massima una minore complessità circuitale rispetto alla seconda, implica però elevate correnti di picco e quindi un alimentatore studiato appositamente, oltre alla necessità di utilizzare led particolari e una notevole complessità del software di gestione. La seconda, a fronte di una maggior complessità dell’hardware, ci semplifica sensibilmente la gestione del software e la progettazione dell’alimentatore, che non deve avere requisiti particolari ma deve solo erogare una corrente media elevata. In pratica per ogni riga di led si avrà uno schema logico di questo tipo.

 

 


Lo Shift Register trasforma il dato seriale in arrivo dal pic in un dato parallelo a 8 bit, il 374 memorizza il dato e pilota i led.

Questa soluzione logica necessiterebbe di almeno 8 blocchi di Shift Register + 374 + segnali di pilotaggio (Ck, data, load).

E’ evidentemente molto complessa dal punto di vista circuitale, poiché servirebbero 8 Shift Register e 24 segnali di controllo in arrivo dal Pic: 8 load, 8 ck, 8 data.


 

 


Per ovviare a questa articolata complessità circuitale abbiamo studiato una soluzione in grado di semplificare notevolmente l’hardware: a causa della persistenza dell’immagine sulla retina dell’occhio, le immagini molto veloci non vengono percepite dal cervello; è allora possibile accendere molto rapidamente una riga di led alla volta, e alla fine lasciare visualizzata l’immagine così ottenuta. In pratica si usa un solo S.R. che via via conterrà i dati da memorizzare per ogni riga.

 

 

 

 


In questo caso la sequenza di comando sarà la seguente:

 

 

 

 


Riga 1      Pic invia dato seriale a S.R.

                Pic carica il dato sul 374

 

Riga 2      Pic invia dato seriale a S.R.

               Pic carica il dato sul 374

 

Riga n      ……………………………

                …………………………...

 

Riga 8      Pic invia il dato seriale a S.R.

                Pic carica il dato sul 374

 

 

Questa soluzione è abbastanza buona, ma implica che siano disponibili almeno 10 fili di comando con il Pic: 8 Load + Dato + Clock.

Un ulteriore difetto di questa soluzione è che se si volesse aggiungere ulteriori righe di led, sarebbe necessario disporre altrettanti piedini di uscita per il pic. La soluzione che abbiamo adottato risolve del tutto questo problema: anche i segnali di load saranno generati attraverso un S.R.

 

 

 

 

 

 

 

 


 

 

 


Per raggiungere altre righe di led sarà sufficiente porre in cascata altri moduli.


 


L’immagine viene memorizzata riga per riga nei buffer del pannello con la seguente modalità:

Lo Shift Register in alto viene caricato con il dato da visualizzare, questa configurazione diventa quindi disponibile sul bus interno della scheda a led. Un successivo comando di load applicato al buffer interessato memorizzerà il dato. Ripetendo l’operazione per ogni riga, è possibile visualizzare qualsiasi immagine. Per ridurre il numero di fili necessari per pilotare il pannello, anche il comando di load viene generato da uno Shift Register (a sinistra nella figura). La  sequenza di pilotaggio quindi sarà la seguente:

 

1)   DATO SR 2 = 1

2)   Carica contenuto riga sul SR 1

3)   Ck SR 2 = 1, ritardo, Ck SR = 0

4)   DATO SR 2 = 0

5)   GOTO 2)

 

Nella figura seguente è riportato il timing dettagliato relativo al ciclo appena illustrato:

 

 

 


In sostanza lo schema a blocchi dell’elettronica per il pilotaggio del led è il seguente:

 


 

 


2.4 - La realizzazione dei circuiti stampati

 

Visto che la nostra tecnologia non è da grandi industrie, per la creazione di queste basette abbiamo usato molto materia grigia ma soprattutto molta pazienza. Il nostro progetto ha richiesto molto lavoro per lo sviluppo dei circuiti stampati, sia come numero di piste da progettare che complessità degli stessi. Le schede da realizzare sono state:

·        Main board: scheda principale contenente il micro processore

·        scheda led

·        scheda buffer per led

·        scheda con schift register

 

La realizzazione della main board  non ha presentato particolari problemi e siamo riusciti a implementarla con un circuito a singola faccia. La schedina per la parte a led hanno invece imposto parecchio lavoro, in particolare quella con i buffer per i led.


  

 


Come prima cosa abbiamo realizzato gli schemi elettrici con Protel (programma per computer per il disegno di circuiti) dopodiché abbiamo stampato il circuito sopra ad un lucido   progettato appositamente per il foto incisore (macchina ad ultra violetti che incide sopra ad una basetta di rame le piste  disegnate con protel) dopo aver inciso la basetta è stata  messa dentro a un liquido chimico apposta per far andare via il rame e lasciare solamente le piste  da noi disegnate. Una volta  fatto il tutto, la basetta viene forata con un trapano a colonna con la massima precisione possibile). A questo punto si inizia a saldare tutti i componenti.

La prima basetta è il modulo da 64 led (8 righe per 8 colonne)


 

 


Nella figura sono evidenziati i fori per l’inserimento  dei led e i connettori per il collegamento con la

scheda elettronica di controllo. La difficoltà di questa piastra è dovuta al grande numero di connessioni con la sezione Buffer: servono infatti 64 collegamenti (uno per ogni led). Per realizzare questi collegamenti erano percorribili 2 strade: collegare  con fili o realizzare un collegamento fisso. La  realizzazione di uno strato di interconessione tra i due,  pur essendo probabilmente la migliore, implica problemi meccanici di allineamento dei connettori non facilmente risolvibili con la nostra tecnologia;  abbiamo quindi ripiegato sulla soluzione che prevede i fili di collegamento.

 

Strato dei buffer per i LED

 

 

 


 

 

 


Come si nota dalla figura, questa basetta è stata la più complessa da progettare e realizzare. E’ un circuito stampato a doppia faccia, molto denso di integrati e di piste di collegamento, e questo ci ha costretti a utilizzare piste molto sottili. Una delle difficoltà maggiori incontrate nella realizzazione di questo strato è stata la presenza di molti punti di collegamento  tra strato superiore a quello inferiore. Solitamente questo viene realizzato con fori passanti  metallizzati, chiamati via.

Nel nostro caso non è stato possibile metallizzarli in quanto la tecnologia disponibile a scuola non lo consente. Abbiamo risolto con la pazienza e l’impegno. Il collegamento è stato realizzato saldando dei fili sottilissimi tra i due strati.

 

 

La realizzazione dei circuiti stampati

Un circuito stampato è un insieme di piste di rame disegnate su un supporto isolante che servono a collegare tra loro i componenti che costituiscono il circuito elettronico. Il circuito stampato è detto a singola faccia se il rame è dalla parte dove vanno eseguite le saldature e i componenti dall'altra; le connessioni sono realizzate mediante fori passanti. Vi sono poi circuiti a doppia faccia, con le piste sui due lati, e circuiti con piste e componenti dallo stesso lato (componenti SMD o SMT). La realizzazione di circuiti stampati richiede in successione una serie di operazioni alcune delle quali è possibile svolgere in modi diversi, vediamole:

 

Progetto delle tracce

Partendo dallo schema elettrico del circuito che si vuole realizzare si deve decidere come collocare i componenti necessari e la disposizione delle tracce per poter effettuare le connessioni fra di essi. E' evidente che tale processo non è univoco ed ognuno potrà effettuare come meglio crede lo "sbroglio" del circuito a seconda delle circostanze e dell'esperienza personale.

Una volta ottenuta la disposizione delle tracce bisognerà trasferirla sulla basetta, si possono utilizzare due metodi:

 

Trasferimento diretto

E' il metodo più semplice ma permette di realizzare solo circuiti poco complessi e in singolo esemplare. Il materiale occorrente è una basetta ramata delle dimensioni appropriate e un pennarello di inchiostro resistente all'acido. Questi pennarelli sono venduti nei negozi di componenti elettronici ma si possono utilizzare anche inchiostro di china o pennarelli indelebili e resistenti all'acqua. In alternativa sono disponibili appositi trasferibili, con le dimensioni e le piedinature più diffuse, da riportare sul rame.

La basetta deve essere pulita accuratamente in modo da eliminare lo strato di rame ossidato e le impronte, si possono utilizzare una normale spugnetta o paglietta per la cucina e detersivi per superfici ruvide. Al termine lavare bene con acqua corrente e far asciugare evitando di toccare il rame e di farvi depositare polvere. La pulizia deve avvenire poco prima di usare la basetta, il rame infatti si ossiderebbe di nuovo in poco tempo.

Si riporta quindi, disegnandolo direttamente sul rame, il percorso delle piste. Con un punteruolo si possono praticare dei segni in corrispondenza dei fori in modo da avere dei riferimenti durante la fase di disegno. Lo strato di vernice deve essere perfettamente coprente e compatto. In caso di errori questi possono essere corretti utilizzando una lametta per portare via la parte di inchiostro in eccesso. Prima di andare avanti attendere la perfetta asciugatura della vernice.

 

Trasferimento con la fotoincisione

Questo metodo permette di ottenere circuiti anche complessi e di farne in piccola serie, ottenendone di migliore qualità rispetto al metodo precedente, tuttavia il procedimento è più difficile e i materiali necessari più costosi. E’ una procedura non molto diversa da quelle usate per sviluppare le foto: una basetta ramata viene ricoperta da un sottile strato di materiale sensibile ai raggi ultravioletti (il photoresist). Appoggiando sulla basetta un "negativo" opportunamente opacizzato nei punti giusti (il master) ed esponendo il tutto ai raggi ultravioletti, lo strato fotosensibile si "impressionerà" nei punti non coperti dalle parti opache del master. Immergendo poi la basetta così ottenuta in una particolare soluzione di sviluppo, le parti impressionate verranno rimosse e rimarrà impressa soltanto la traccia del circuito stampato. Esistono due diverse tecniche di fotoincisione che si avvalgono di due tipi diversi di photoresist: quello positivo e quello negativo. Il photoresist positivo si impressiona quando è esposto ai raggi ultravioletti, mentre quello negativo è già impressionato normalmente e si "deimpressiona" quando è esposto agli ultravioletti. Nei due casi quindi occorre utilizzare dei master "opposti": con il photoresist positivo occorrerà coprire le porzioni della basetta che si desidera restino (piste, piazzole e così via), mentre con il photoresist negativo si dovrà fare l’esatto contrario. Nella maggior parte dei casi si utilizza photoresist positivo. Occorrono i seguenti passi:

 

Il master

Prima di realizzare la basetta vera e propria bisogna disporre di un master, ovvero di un disegno a grandezza naturale che riproduca fedelmente ciò che si vuole ottenere.

 

La basetta con vernice fotosensibile

E' una normale basetta per circuito stampato su cui è steso il photoresist.

 

L'esposizione
E’ un passaggio molto delicato e importante. Il bromografo è lo strumento che permette di sensibilizzare attraverso i raggi UV il photoresist, stampando l'immagine del master sulla basetta. Illumina con la luce attraverso il master, passando dove esso è trasparente, la basetta, inducendo modificazioni chimiche. I bromografi normalmente in vendita sono costosi essendo dotati di timer, pompe a vuoto e altri accorgimenti, ma è possibile costruirsene uno utilizzando lampade apposite (neon Philips TLDA, lampadine Philips photolita, lampadine vapori di mercurio ecc.) o normali (lampadine a luce solare, lampade alogene senza filtro UV ecc.). In ogni caso i tempi di esposizione variano di molto anche a seconda del supporto utilizzato per il master. Per un master di carta lucida o acetato sono necessari da meno di un minuto (lampade UV apposite) alle decine di minuti (lampade generiche), nel caso si utilizzi per il master la normale carta bianca i tempi salgono di molto. Il tempo di esposizione dipende anche dal photoresist e dal suo spessore e dalla distanza tra lampade e basetta. E' quindi necessario determinare con una prova sperimentale la durata dell'esposizione una volta per tutte. Per fare questo si può approntare un circuito di prova sul quale volendo sono tracciate piste di diverso spessore e distanza.

Per una buona riuscita del processo ricordarsi di far aderire bene il master alla basetta. Per questo si ricorre ad una lastra di vetro non troppo spessa che tiene premuto il master e fa in modo che non si muova, i bromografi commerciali sono a volte dotati di un sistema con pompa a vuoto. Come già detto prima, avendo il foglio del master uno spessore, per rendere nitida l'ombra proiettata è bene poggiarlo con l'inchiostro del disegno a diretto contatto con la basetta, stampare quindi il master al rovescio. Attenzione: i raggi UV non sono visibili ma possono provocare danni alla pelle e agli occhi (soprattutto UVB e UVC) pertanto è necessario tenere le lampade in funzione in una scatola chiusa e comunque evitare di esporsi direttamente e di guardarli per lungo tempo durante il funzionamento, se usate lampade normali le precauzioni naturalmente saranno minori.

 

Lo sviluppo

Al termine dell'esposizione sul photoresist, normalmente di colore blu - verde, sono già leggermente visibili le piste riportate sulla basetta, lo sviluppo porta via la parte di vernice che è stata esposta agli UV, lasciando intatta quella rimasta in ombra. Il prodotto chimico utilizzato è normale soda caustica (NaOH) venduta appositamente nei negozi di elettronica ma acquistabile anche in drogheria o ferramenta e presente nei disgorganti per impianti idraulici venduti ai supermercati. La soluzione basica va preparata sciogliendo indicativamente dai 5 ai 20g di NaOH in un litro di acqua tiepida, se questa è molto calcarea è consigliabile usare quella distillata. Questa soluzione può essere conservata per lungo tempo ed utilizzata fin quando rimane limpida e priva di depositi (tende a precipitare). Quando è ancora in grani è igroscopica tende quindi ad assorbire l'umidità divenendo una poltiglia inutilizzabile. Attenzione: la soda caustica ad elevate concentrazioni corrode molte sostanze ed è pericolosa per gli occhi, conservarla in recipienti chiusi segnalandone il contenuto.
La basetta si immerge nella soluzione in una bacinella di plastica, dopo pochi secondi si nota l'inizio della reazione: il photoresist diventa scuro e si scioglie nella soluzione formando così un liquido nerastro. Continuando ad agitare dopo poco rimarranno sulle basetta solo le piste ricoperte da uno strato scuro di vernice, tutto intorno il rame sarà scoperto. Dopo essersi accertati visivamente che tutta la vernice sensibilizza sia stata asportata, tenendo conto che il rame a volte può sembrare pulito ma in realtà è ricoperto da una patina trasparente la cui presenza può essere riscontrata graffiando leggermente la superficie, lo sviluppo ha termine. La temperatura della soluzione è sufficiente sia quella ambiente. Lavare quindi accuratamente la basetta senza asciugarla e graffiarla in modo da evitare che lo strato protettivo in corrispondenza delle piste si rovini, passare quindi immediatamente alla fase successiva, l’incisione.
 

 

L'incisione

L'incisione è l'operazione che permette di togliere chimicamente il rame in eccesso non protetto dalla vernice resistente alla corrosione che è stata precedentemente stesa attraverso il trasferimento diretto o con la fotoincisione. L'incisione avviene utilizzando sostanze chimiche in grado di corrodere il rame senza intaccare la pellicola protettiva che ricopre le piste; molto comune è il cloruro ferrico (FeCl3): è un sale che corrode la maggior parte dei metalli, si compra nei negozi di elettronica sotto forma si scaglie di colore giallo-bruno o già pronto in soluzione.

 

La foratura

La foratura delle piazzole si effettua con trapano e punte. Preferibilmente utilizzare un piccolo trapano adatto ai lavori di precisione reperibile nei negozi di elettronica e modellismo, l'ideale sarebbe anche avere una colonna per trapano (di costo elevato). In mancanza di strumenti specifici ci si può arrangiare con un trapano a mano o, con un po’ di difficoltà, con quello per uso domestico.

Le punte da utilizzare sono da 0.7 - 0.8mm per la maggior parte dei fori (integrati, transistor, resistori, ecc.), allargare poi quelli di componenti di grandi dimensioni a 1mm o più. I fori destinati ad accogliere viti di fissaggio sono normalmente di 3mm.
La foratura risulta facilitata se le piazzole di rame sono state incise in modo da presentare al centro un piccolo foro che aiuta a centrare la punta e a non farla scivolare quando si comincia a bucare.  Ora si possono saldare i componenti sulla basetta e terminare finalmente la realizzazione.

 

 

2.5– I circuiti integrati del progetto

 

Nel nostro progetto sono stati utilizzati molti tipi di circuiti integrati: il microprocessore, la RAM, gli shift register, i buffer. Nei paragrafi seguenti verranno illustrate le loro caratteristiche principali.

 

 

2.5.1 – Il Microprocessore

 

E’ costituito  come un normale circuito integrato, possedente però all’interno una tecnologia piuttosto complessa. Questo oggetto ha la mansione di gestire tutte le attività del sistema; per operare ha bisogno di una memoria, anch’essa costituita da uno o più circuiti integrati, con il compito di memorizzare tutti i dati necessari alla CPU di operare.

Questi due oggetti da soli, non sono in grado di comunicare con l’esterno, in quanto è necessario qualcosa che li faccia comunicare con le altre periferiche. Ci sono dunque le interfacce di I/O (input/output) in cui sono collegati tutti i dispositivi esterni - le periferiche - fondamentali per l’utilizzo del sistema: Monitor, tastiera, stampante, ecc…

 

 


 

 


Nel caso di microprocessori destinati a sistemi molto potenti, come ad esempio i PC, ogni componente (CPU, RAM, ROM, …) è contenuto in circuiti integrati distinti. Sono però disponibili sul mercato dei microcontrollori adatti ad applicazioni industriali non particolarmente complesse, che contengono al loro interno tutto ciò che è necessario al loro funzionamento, rendendo così decisamente più semplice lo sviluppo di applicazioni.

 

Nel nostro progetto abbiamo utilizzato un PIC16F876 che ha le seguenti caratteristiche principali:

 

·        22 pin di I/O indirizzabili singolarmente;

·        8k flash program memory (word=14 bit);

·        368 Byte di RAM; 256 Byte di EEPROM per dati;

·        Frequenza max = 20MHZ

·        Convertitore A/D a 10 Bit con 5 ingressi multiplexati

·        Gestione integrata delle comunicazione seriali.

 


Lo schema a blocchi semplificato è riportato nella figura seguente:


Convertitore A/D integrato


 

 


Il convertitore è ad approssimazione successiva con tempo minimo di conversione di 19.2 uSec.

 

 

 

2.5.2 – Gli altri integrati

 

Nel nostro progetto sono stati utilizzati anche i seguenti circuiti integrati:

 

1.   Shift Register  4094

2.   74HC374  

3.   Ram    6264   

 

Shift Register 4094

 

Lo Shift Register  è un circuito integrato che attraverso tre fasi è in grado di memorizzare in maniera seriale otto bit uno alla volta e restituire il tutto in una unica soluzione.


 

 


Il 4094 è in realtà un circuito più complesso:

- Il primo stadio è un classico shift register a otto bit;

- Il secondo è un buffer di memoria a otto bit;

- Il terzo stadio, quello di uscita con output enable,  è costituito da otto  porte three state.

 


 

 

 

 


Teoria dello shift register:

 


Ad ogni fronte in salita del clock il dato viene traslato dal flip flop precedente a quello successivo; in pratica il dato va da sinistra a destra. Il risultato è che dopo otto impulsi di clock all’uscita otteniamo otto bit paralleli.

 

 


 

 


Nel circuito da noi realizzato lo shift register ha la funzione di  acquisire tutti i dati originari dal pic e restituiti in una unica soluzione al registro a 8 bit (74HC374). Che poi a sua volta provvede a pilotare i led

 

 

74HC374

E’ un C.I. contenente 8 Flip Flop di tipo D con uscita three-state.

 

                         

 


 


La funzione del 74HC374 è quella di acquisire i dati trasmessi in parallelo dallo Shift Register 4094, memorizzarli e trasmetterli   al pannello led, per il quale ha anche la funzione di driver di potenza.

 

 

RAM 6264

L’ulteriore RAM è indispensabile in quanto la memoria presente nel processore non è in grado di contenere il numero sufficiente  di fotogrammi:

Caratteristiche tecniche:-

-        8 Kbite

-        Alimentazione singola da 5 V con tolleranza del 10%

-        Totalmente statica – non necessita di clock o circuiti di timing;

-        Velocità di accesso: 12, 15, 20, 25 e 35 nano secondi;

-        Stesso tempo di accesso per gli indirizzi e il chip enable ;

-        Bassa corrente assorbita: 110 – 150 mA massimi;

-        Perfettamente compatibile con i livelli TTL.

 

 

 

 

 

TABELLA VERITA’

E1

E2

G

W

Mode

Output

Cycle

H

X

X

X

Not Selected

High-Z

-----

X

L

X

X

Not Selected

High-Z

-----

L

H

H

H

Output Disabled

High-Z

-----

L

H

L

H

Read

Dout

Read Cycle

L

H

X

L

Write

High-Z

Write Cycle

 

 

 

 

 

 

 

Per ridurre al minimo il numero di fili di controllo della RAM abbiamo utilizzato il seguente schema di collegamento:

 


 

 



In pratica il chip è sempre abilitato con l’uscita dati collegata ad una porta del PIC.
 L’uscita dati è abilitata da OE, la direzione  del flusso dei dati dal piedino R/W che pilota correttamente anche la direzione della porta three-state della RAM.

 

 


Diagramma a blocchi:

 

 

 

 


 


 

 

 

 

 

 


Capitolo 3: Il software ad alto livello

 

3.1 Presentazione

3.2 Schema a blocchi

3.3 Logica di funzionamento

3.4 Struttura dati

 

 

 

 

 

 

 

 

 

 

 


3.1: Presentazione

 

Il software ad alto livello "Pannello Led 1.0" è il programma attraverso il quale l'utente è in grado di interagire con l'insegna luminosa creando intere sequenze animate fotogramma per fotogramma; la sua realizzazione effettuata in Visual Basic 6 ha garantito una notevole semplicità nella stesura del codice nonché un'interfaccia user-friendly per chi lo utilizza; Il suo funzionamento e' semplice ed intuitivo. Di seguito verrà descritto nelle sue parti principali.

 

 

 

3.2 - Schema a blocchi

 

Il programma e' sostanzialmente diviso in quattro parti principali:

1) Editor di sequenza animata

2) Modulo di dialogo con l'insegna

3) Modulo di salvataggio e caricamento di sequenze animate.

1)   Modulo di visualizzazione dell'anteprima dell'animazione.

 

L'editor di sequenze animate permette in maniera facile e veloce di creare modificare e cancellare tramite il mouse tutti i fotogrammi che compongono l'animazione. Il dialogo con l'insegna avviene tramite porta seriale RS232, ed e' basato su un semplice protocollo messo a punto da noi con l'obbiettivo di ridurre al minimo errori di comunicazione e nel contempo la progettazione del firmware residente nel microprocessore a bordo dell'insegna; per i particolari sul protocollo rivedere il paragrafo 1.3. Il salvataggio dell'animazione viene effettuato su un file che può essere salvato e richiamato da un qualunque percorso. La visualizzazione dell'anteprima e' utile per stabilire se l'effetto dell'animazione è quello voluto senza necessariamente inviare la sequenza all'insegna.

La figura seguente mostra il programma in esecuzione.


 

 

 

 

 

 

 

 


Lo schema a blocchi di massima del flusso del programma e' riportato nella figura seguente:

 

 

 

 


 

 

 

 

 


Lo schema seguente illustra più dettagliatamente le attività principali.

Essendo il programma scritto in Visual Basic per l’ambiente Windows, e’ basato su “eventi” e non su un flusso vero e proprio; il diagramma quindi rispecchia questa impostazione logica

 

 


 


3.3 Logica di funzionamento

 

Creazione di una sequenza animata

Il  programma presenta una griglia dimensionabile in righe e colonne dall'utente; essa e' formata da quadratini bianchi che rappresentano i led dell'insegna. E' possibile tramite il mouse disegnare la figura voluta annerendo i quadratini della griglia. Il colore nero rappresenta il led acceso, il bianco il led spento. Dopo aver disegnato il fotogramma e' possibile aggiungerne un altro (fino a 10.000) potendo anche usare come base da modificare un qualunque altro fotogramma presente nell'animazione.

 

Salvataggio di un'animazione

Le animazioni create vengono salvate in un file con estensione ".led". In realtà questo file e' un file di testo in formato ASCII. La posizione di salvataggio (directory) viene scelta dall'utente. Il modo in cui viene salvata un'animazione verrà discusso nel  par 3.4.

 

Caricamento di un'animazione

Le animazioni possono essere caricate da un file ".led" e visualizzate immediatamente sul monitor all'interno del programma. La modalità di lettura del file verrà discussa nel  par. 3.4.

 

Invio dati all'insegna

Una volta completata un'animazione e' possibile inviarla immediatamente all'insegna tramite porta seriale. La velocità di trasmissione ed il controllo errori sono impostabili dal programma. A questo punto il software dialoga con il microprocessore a bordo dell'insegna inviandogli l'animazione con le modalità descritte nel  par 3.4.

 

Visualizzazione dell'anteprima

Una volta completata un'animazione e' possibile visualizzarne l'anteprima sul pc senza inviarla all'insegna. Il programma leggera' tutti i fotogrammi immessi dall'utente uno dopo l'altro in ordine di immissione. Data l'elevata velocità di lettura si avrà l'effetto movimento sulla griglia di disegno.

 

 

3.4 Struttura dati

 

Creazione della sequenza animata

Quando viene creata una griglia di n righe e k colonne, in memoria viene creato un array bidimensionale di bytes, delle stesse dimensioni della griglia (array fotogramma). Ogni quadratino annerito (led acceso) corrisponde ad un "1" all'interno di  quell'indice dell'array; i quadratini bianchi (led spenti)

corrispondono ad uno "0" all'interno dell'indice corrispondente, come mostrato nella figura seguente:

 

 

 


 


Ogni fotogramma cosi' creato viene a sua volta immesso nel primo indice libero dell’array.

 

Visualizzazione dell'anteprima

Tutti gli indici (fotogrammi) dell'array sequenza vengono letti sequenzialmente e rappresentati sulla griglia di disegno grazie ad un ciclo che va dal primo all'ultimo indice occupato nell'array sequenza.

 

 

 

 

 

 

 

Salvataggio dell'animazione

All'interno del file di testo contenente l'animazione vengono scritte in successione:

-        numero di righe da cui e' formato un fotogramma

-        numero di colonne da cui e' formato un fotogramma

-        Il numero di fotogrammi da cui e’ composta l’animazione.

-        sequenza di "0" ed "1" da cui e' formato il primo fotogramma.

-        sequenza di "0" ed "1" da cui e' formato il secondo fotogramma.

-        sequenza di "0" ed "1" da cui e' formato il fotogramma n.

 

Il numero di righe, il numero di colonne ed ogni fotogramma sono separati da un ritorno a capo.

L'inizio di un fotogramma è contraddistinto dalla stringa "$inizio", la sua fine  è contraddistinta dalla stringa "&fine". Per semplificare la lettura, nella figura seguente viene mostrato il salvataggio di una sequenza formata da tre fotogrammi composti da 5 righe e 5 colonne (per un totale di 25 bit a fotogramma)

 

 

 

 

Caricamento di un file animazione

Quando viene caricato un file animazione (*.led) il programma legge sequenzialmente il numero di righe, il numero di colonne da cui e' composto un fotogramma e tutte le sequenze di bit da cui e' composto ogni fotogramma. A questo punto viene impostata opportunamente la dimensione della griglia grafica, quella dell'array fotogramma e gli indici dell'array sequenza vengono occupati progressivamente dal contenuto dei fotogrammi nell'ordine in cui vengono letti dal file.

 

 

 

Capitolo 4: Il Software nel PIC

 

4.1 - Descrizione di massima

4.2 – Analisi dei singoli blocchi

4.3 – La gestione della RAM

4.4 – La struttura dati


4.1 – Descrizione di massima

 

Il codice all’interno del PIC e’ il prodotto dello studio del sistema in ogni sua componente e problematica.

Siamo partiti da un’analisi ad alto livello per poi sviluppare a livelli sempre più bassi ogni singolo blocco considerandolo come a sé stante. Questa metodologia ci ha portati ad un’estrema schematizzazione e semplificazione di un sistema complesso altrimenti difficilmente controllabile; pertanto il codice risulta facilmente gestibile in ogni sua parte da chiunque abbia nozioni di programmazione.

Il linguaggio utilizzato è il C.

 

Il Programma è in grado di:

 

·        Ricevere un filmato dal PC tramite la porta RS232

·        Scriverlo in una RAM statica esterna al microcontrollore

·        Leggerlo dalla RAM ed inviarlo all’insegna a matrice di LED

·        Ogni operazione viene effettuata grazie ad un protocollo di comunicazione da noi sviluppato e non visibile a livello utente; esso comprende un set di comandi che verranno descritti nel capitolo 3.

 


 

 


Il protocollo di comunicazione gestisce il dialogo fra il PC ed il PIC;  i comandi implementati permettono la gestione completa dell’insegna (dalla memorizzazione di nuovi fotogrammi al reset del sistema).

Il dialogo tra il PC ed il PIC avviene tramite seriale RS232. La ricezione dei caratteri e’ ad  INTERRUPT: questa scelta garantisce la ricezione di tutti i caratteri senza pericolo di perdita dati.

 

 

4.2 – Analisi dei singoli blocchi

 

I blocchi che costituiscono il nostro software sono i seguenti:

 

·        MAIN

·        VISUALIZZA FOTOGRAMMA

·        PROCESSA COMANDO

·        RICEZIONE SERIALE

·        TRASMISSIONE SERIALE

·        LETTURA E SCRITTURA RAM

Di seguito viene spiegato il funzionamento di ogni blocco.

 

MAIN

E’ il modulo principale del programma; esso gestisce il flusso del programma ed utilizza in modo opportuno tutti gli altri blocchi (sub).

 

VISUALIZZA FOTOGRAMMA

Questo blocco si occupa della visualizzazione di un fotogramma sul pannello led.


 

 

 


Dal diagramma si nota che il dato viene messo a 1 una sola volta (all’inizio del ciclo) e poi fatto scalare lungo tutto lo SHIFT REGISTER. Questo ci permette di selezionare una riga alla volta. Tra un clock e l’altro viene quindi inviato il contenuto della riga allo SHIFT REGISTER del dato colonne. Nella figura seguente il timing dettagliato.


 

 

 


PROCESSA COMANDO

Il blocco si occupa di interpretare ed eseguire i comandi inviati dal PIC.


 


RICEZIONE SERIALE

Questo blocco si occupa della trasmissione e ricezione dei dati seriali tramite la porta RS232.

La ricezione seriale e’ lanciata ad INTERRUPT; si avvia automaticamente ogni volta che il livello logico del piedino RX va a zero (bit di start).

 


 

 

 

 

 

 

 

 

 


TRASMISSIONE SERIALE

 

La routine di trasmissione è stata realizzata nel modo più semplice possibile: invio bit (set valore del pin di IO predefinito), ritardo. Il diagramma successivo non ha bisogno di altri commenti

 


 

 


4.3 – La gestione della RAM

Questo blocco si occupa della lettura e scrittura della RAM esterna collegata al PIC. Il nostro programma prevede la possibilità di memorizzare in una ram un gran numero di fotogrammi. Purtroppo il PIC16F876 non dispone di moltissima ram (solo 380 bytes), e questo ci ha costretti ad utilizzarne una esterna; anche in questo caso le difficoltà non sono mancate non essendo il PIC predisposto a questo scopo. L’interfaccia con la RAM scelta (una 6264) necessitava di almeno 23 fili di collegamento (12 address, 8 bit dati, 2 bit di selezione).


Tutti questi bit di i/o non sono disponibili nel PIC.Abbiamo rimediato utilizzando degli SHIFT REGISTER per gli address.

 


Grazie a questo accorgimento abbiamo ridotto a 12 i fili (I/O bit) necessari. Bisogna prestare una particolare attenzione alla direzione della porta collegata con il bus dati al fine di evitare conflitti che potrebbero danneggiare la RAM ed il PIC: PORTC e’ sempre in input; va in output soltanto per il periodo di scrittura. Nel boot avremo quindi le seguenti impostazioni:

TRISC = 0xFF

R/W = WRITE(0)

OE = 1

 

 

Scrittura:

1)   Preparo gli indirizzi

2) TRISC = 0x00

2) PORTC = dati da scrivere

4)  R / W = WRITE (0)

5)   Delay breve

6)   TRISC = 0xFF            

7)   READ / W =  READ (1)

 

Lettura

1)   So già che TRISC = 0Xff , R/W=R

2) Preparo gli address

3)  OE = LOW

4)  Ritardo breve

5)   DATA_IN = PORTC

6)   OE = HIGH

I diagrammi di temporizzazione risultano quindi i seguenti:

 

 

 


 



4.4 – La strutura dati

Ogni fotogramma dell’animazione e’ formato da 8 bytes (per un pannello 8x8 led).

Ogni byte corrisponde ad una riga del pannello 8x8.

I fotogrammi vengono scritti in ram come se fosse un array. Ogni byte viene letto dalla ram e inviato subito all’insegna.

 


 

Capitolo 5: Approfondimenti teorici

 

 

5.1 La  Trasmissione seriale

In molte occasioni è necessario trasmettere dati da un apparato ad un altro.  Nella maggioranza dei casi i dati da trasmettere vengono codificati con un codice binario come, ad esempio, quello ASCII (American Standard Code for Information Interchange) che associa un blocco di sette bit a ciascuno dei 128 caratteri possibili. In pratica si è poi soliti aggiungere un ottavo bit, detto di  parità, per il controllo degli errori. Ad esempio, con parità dispari, al carattere “A” risulta associata la stringa seguente:

 


 

 

 


Se gli otto bits  vengono trasmessi contempora-neamente, e quindi tramite otto circuiti distinti, si ha una trasmissione di tipo parallelo. Essa è caratterizzata da elevate velocità di informazione, ma i problemi di diafonia e di impianto, legati all’uso di cavi multipolari, ne limitano l’impiego a collegamenti di lunghezza molto ridotta.

A titolo di esempio, si ricorda che l’interfaccia parallela HP IB (IEEE-488) consente velocità di circa 10Mbit/sec su distanze non superiori ai 15 m.

Una trasmissione di tipo seriale si ottiene invece quando gli otto bit che costituiscono un carattere (fig.2) vengono trasmessi sequenzialmente  e tramite un solo circuito.


 

 

 

 


Risulta così possibile l’impiego di linee telefoniche bifilari per collegamenti a grande distanza, naturalmente a velocità inferiori a quelle conseguibili con una trasmissione di tipo parallelo.

 

La porta seriale

RS232 è lo standard  per la trasmissione seriale definito dell’EIA del 1969 che caratterizza l’interfaccia per l’interconessione tra un dispositivo digitale (computer o terminale), identificato  dalla sigla DTE, acronimo di Data Terminal Equipment, e il dispositivo per l’accesso alla rete telefonica (modem), associato alla sigla DCE (Data Communication Equipment).

Questo standard supporta la trasmissione sincrona e asincrona su linee dedicate, affittate, commutate o private, in configurazione punto punto o multipunto, su due o quattro fili, con modalità simplex, half duplex, full duplex tra apparecchiature che hanno un collegamento comune a massa. La velocità massima consentita è 115000 bps (bit per secondo).

 

 


Presa seriale a 9 pin (vista frontale).

 


Pin    Nome     Funzione        Descrizione

          

1      DCD            Input               Data Carrier Detect

2  RD = RX       Input               Received Data

3  SD = TX       Output             Transmitted Data

4 DTR              Output             Data Terminal Ready

5 GND                 -                   Ground (massa)

6 DSR              Input               Data Set Ready

7 RTS                      Output             Request To Send

8 CTS                      Input               Clear To send

9 RI                         Input                       Ring Indicator

 

 

Caratteristiche elettriche

 

Nello standard RS232 ad un livello logico 0 corrisponde un segnale di compreso tra +3 e +15 Volt (la seriale del PC di solito ha +12V) e ad un livello logico 1 corrisponde un segnale compreso tra -15V e –3Volt (la seriale del PC di solito ha –12V) e indicante la linea in riposo (nessun segnale sulla linea). Normalmente nelle porte seriali dei PC una tensione superiore ai 3Volt è considerata un livello logico 0 e una tensione inferiore un livello logico 1.

L’impedenza di uscita di un’apparecchiatura che vuole trasmettere un dato alla seriale deve essere inferiore ai 300ohm. L’impedenza di ingresso della porta seriale è compresa tra 3 e 7 Kohm. La trasmissione e la ricezione (Received Data è il segnale di ricezione, Transmitted Data è il segnale di trasmissione) avvengono con uno standard ben preciso:


 


La linea normalmente a livello logico 1 (-12V) viene portata a livello logico 0 dal bit di start, seguono 8, 9 0 10 bit di dati e un bit di stop. I parametri costituente questo segnale sono:

Baud Rate = Indica la velocità di un modem nello scambio di dati tramite la linea telefonica. Si riferisce a quante volte il modem può cambiare il suo segnale fra “0” ed “1”.

Bps = Indica la velocità di trasmissione in bit al secondo. Ad esempio una velocità di 9600bps indica che ogni bit ha la durata di 1/9600 sec pari a 0,104 msec.

Numero di bit = Indica il numero di bit inviati oltre al bit inviati oltre al bit di start e stop e possono essere 8, 9 o 10.

Parità = Indica l’aggiunta di un bit alla fine del pacchetto dati e vale “1” se nella sequenza  dei dati c’è un numero pari di bit altrimenti vale “0”. Il circuito di ricezione conterà quanti bit sono a “1” e farà una verifica con il bit di parità. Questa è l’unica verifica sulla correttezza dei dati.

Bit di Stop = E’ la durata  del bit di stop (obbligatorio) che indica la fine del pacchetto trasmesso. La sua durata può valere 1, 1.5 oppure 2 volte la durata del bit. Il valore 1.5 o  viene utilizzato quando lo si vuole distinguere nella sequenza dai bit di dati.

 

Collegamento seriale in banda base

Lo schema di principio riprodotto nella  figura seguente, che rappresenta un collegamento seriale unidirezionale in banda base tra una unita’ di elaborazione dati e una stampante, le interfacce sono rappresentate schematicamente da un serializzatore (P/S) e da un parallelizzatore (S/P) .

 


 

 


Collegamento seriale su linea telefonica

 

Un notevole vantaggio offerto dalle comunicazioni seriali è quello di poter sfruttare le linee telefoniche. Si osservi però che la banda passante di un canale telefonico è compresa tra 300Hz e 3400Hz mentre lo spettro S (f) del segnale dati è concentrato attorno allo zero. E’ quindi necessario fare uso di MODEM che provvedano ad una modulazione in trasmissione e alla opportuna demodulazione in ricezione.


                                                                                                            

 

 

Normalmente si fa ricorso ad una modulazione FSK binaria che, come è noto, associa toni a frequenza diversa al mark (“1” logico) e allo SPACE (“0” logico).

La figura seguente mostra lo schema logico di un tipico modem Full-Duplex.

 


 


Si noti che in questo caso sono disponibili due canali distinti (uno centrato attorno a 1170 Hz, l’altro attorno a 2125 Hz) che possono essere usati contemporaneamente , mentre nel caso Half-Duplex si trasmette alternativamente nei due sensi. In questo modo è però possibile una maggiore una maggiore velocità di segnalazione.

 

 

 

 

 

         

 

 

                                                                

Trasmissione seriale asincrona

 

Quando la distanza tra due caratteri consecutivi (o meglio tra i blocchi di bit che le rappresentano) non è costante, la trasmissione seriale è detta di tipo asincrono e per indicare l’inizio e la fine di ciascun carattere si fa uso rispettivamente di uno SPACE, come bit di START , e di un MARK , come bit di STOP


                                                                                  

 


             

Il principale svantaggio di una trasmissione asincrona è nella sua limitata efficienza; infatti almeno il 20% del tempo è dedicato alla trasmissione dei bit di START e STOP . Ad esempio con una velocità di segnalazione di 1200 baud vengono trasmessi 1200/10 = 120 caratteri / sec, mentre eliminando i bit di START e STOP si potrebbe raggiungere la velocità di 1200/8 = 150 caratteri / sec. Quindi, ove si debbano trasferire con continuità rilevanti quantità di dati, può essere conveniente eliminare i bit di START e STOP e fare ricorso ad una trasmissione seriale sincrona .

 

 

Trasmissione seriale sincrona

 


Nel caso di trasmissione sincrona i dati binari vengono trasmessi con continuità e in sincronismo col clock di trasmissione . Pertanto è necessario che all’interfaccia di ricezione siano noti il sincronismo di bit e di carattere.                                     

Il sincronismo di clock viene generalmente fornito all’interfaccia da parte del Modem che, a sua volta, lo estrae dal segnale ricevuto. Invece il sincronismo di carattere viene ricavato direttamente dall’interfaccia servendosi dei caratteri di sincronismo che vengono trasmessi con regolarità, ad esempio ogni 100 caratteri.

Il vantaggio, in termini di efficienza che così si consegue, nei confronti di una trasmissione asincrona, è quindi a spese di una maggiore complessità del Modem e dell’interfaccia.

Nel nostro progetto questo tipo di trasmissione, è utilizzato per la comunicazione della configurazione di LED tra la CPU e il pannello luminoso.

 

 

Collegamenti

La porta seriale gestisce collegamenti sincrono e asincrono, normalmente per risparmiare fili si utilizza quest’ultimo. Il collegamento è di tipo punto a punto tra un DTE e un altro DTE (PC - PC) oppure tra un DTE e un DCE (PC – Modem) con modalità :

·        Simplex = Trasferimento dati unidirezionale.

·        Half Duplex = Trasferimento dati bidirezionale alternato.

·        Full Duplex = Trasferimento dati bidirezionale contemporaneo.

 

 

A seconda dei segnali usati si possono realizzare diversi collegamenti ogni uno con un protocollo di comunicazione differente.

Nella figura seguente un esempio di collegamento tra due DTE (ad esempio due PC), il cavo usato è invertito e si chiama null-modem con spine femmina-femmina su connettore a 9 pin e spine maschio-maschio su connettore a 25 pin.                                                                                


 

 

 

 

 

 


Nel prossimo esempio il collegamento avviene tra un DTE (il PC) e un DCE (ad esempio un modem o un’apparecchiatura) con un cavo di tipo Pin-to-Pin con spine maschio-femmina (prolunga). A seconda dei collegamenti utilizzati si possono utilizzare diverse sincronie nel trasferimento dei dati:

 


 

 

 


Nelle prossime figure altri possibili collegamenti:

 

 

 

 

 

 

 


 


 

 

 

 

 

 

 


 

 


 

 

 

 

 

 

 

 


I segnali del collegamento seriale

 

TD = Transmitted Data (dati trasmessi) : è la linea di uscita dei dati seriali che vanno verso il DCE.

RD = Received Data (dati ricevuti) : è la linea di ingresso dei dati seriali provenienti dal DCE.

DSR = Data Set Ready (unità dati pronta) : quando è attiva, questa linea indica al DTE (al terminale) che il DCE è collegato, acceso e pronto all’uso. Se non è attiva, il DTE dovrebbe restare in attesa ed evitare di trasmettere dati.

DTR = Data Terminal Ready (terminale dati pronto) : svolge la stessa funzione della linea DSR in direzione opposta, indicando al DCE che il DTE è pronto all’uso.

Può accadere che il DTE (PC),per funzionare esiga il DSR attivo. Se il DCE non lo produce o il cavo non lo supporta è sufficiente ponticellare il DSR con il DTR nel connettore che si attacca al computer.

RTS = Request to send (richiesta di trasmettere) : nel protocollo originale, questo segnale serve a comandare il passaggio in trasmissione dei modem Half-Duplex.

CTS = Clear to send (via libera per trasmettere) : in risposta all’RTS, comunica al DTE che il DCE ha eseguito le operazioni necessarie a passare in trasmissione ed è quindi pronto ad accettare il flusso di dati in partenza. Anche a questo segnale viene attribuito di solito un diverso significato  unitamente all’RTS.

DCD = Data  Carrier Detect (portante dati presente) : indica che sul canale trasmissivo è presente una portante dati valida. Se il DCE è un modem telefonico, ciò significa che il modem del corrispondente ha risposto e che la comunicazione è stabilita. Allo stesso modo, in alcuni TNC, il DCD viene attivato quando viene stabilita una connessione, in modo che il pc possa accorgersene senza bisogno di attendere la ricezione della stringa “***CONNECTED TO”.

Nei modem Half-Duplex, quando il DTE ha dati da trasmettere, deve attendere che il canale si liberi, e quindi che il DCD vada in “off” (come fanno i tnc sul canale radio),attivare l’RTS ed attendere che il CTS diventi “on”. Quindi trasmettere i dati e disattivare l’RTS a trasmissione avvenuta.

RI = Ring Indicator (squillo telefonico): i modem telefonici attivano questa linea per segnalare al DTE le chiamate in arrivo. E’ poco usata, perché ormai tutti i modem trasmettono al computer la stringa “ring” ad ogni squillo e sono anche in grado di rispondere di propria iniziativa.

 

 

 

RS-232-C Specifiche elettriche

 

Le specifiche elettriche più importanti sono le seguenti

 

Trasmettitore:

 

Tensione a vuoto:                           |Vo | < 25 V

Corrente di corto circuito:               | Io | < 0.5 A

Massimo valore di slew rate:           30 V /us

Capacità di carico:                          C L < 2500 pF

Ricevitore

 

Impedenza di ingresso:                           3 KW ¸ 7  KW

Livello 0 = SPACE  = CTR ON:         Vi > 3 V

Livello 1 = MARK = CTR OFF:         Vi < - 3 V

 

 

Velocità di trasmissione in Baud

 

 

  50

  300

  4800

  75

  600

  9600

110

1200

19200

 

 

La limitazione sul valore dello slew rate è legata alla necessità di contenere la diafonia.

La massima capacità equivalente del carico limita a circa 15 m la lunghezza del cavo di collegamento tra DTE e DCE (la capacità di un cavo multipolare è dell’ordine di circa 150 pF/m).

Peraltro, accettando una certa degradazione dei segnali (transizioni meno nette, aumenti dei tempi di salita e di discesa, ecc.) e nel caso che l’inquinamento elettromagnetico sia abbastanza contenuto, si possono facilmente raggiungere distanze di un migliaio di metri e 1200 baud senza un apprezzabile peggioramento delle prestazioni .

 

 

 

 

 

 


 

Appendici:

 

1)     Programma simulatore pannello led

2)     Programma simulatore PC

3)     Firmware insegna

4)     Programma VB di gestione insegna

5)     Schema elettrico main board

6)     Schema elettrico driver led

7)     Pcb main board

8)     Pcb driver led

9)     Data sheet ram 6264

10)   Foto varie

 


Appendice 1

Programma simulatore PC


 

'*******************************************************

'* insegna.bas

'* autore: Tornaboni

'* data: 17.10.05

'* descrizione:

'Questo programma trasmette una riga binaria al pic

'usando il nostro protocollo ufficiale. Il pic a sua

'volta la trasmettera' agli shift register incaricati

'di illuminare i led corrispondenti

'*******************************************************

 

COM(2) ON

ON COM(2) GOSUB eventocom

ON ERROR GOTO erroro

 

'===========================================================

'Main

'===========================================================

DIM SHARED buffer$

DIM SHARED char.presente%

 

CLS

 

OPEN "com2:1200,n,8,1,CD0,CS0,DS0" FOR RANDOM AS #1

 

CLS

 

ancora:

CALL print.menu

 

DO

    a$ = INKEY$

    IF (a$ = "R") OR (a$ = "r") THEN

        PRINT ""

        PRINT "Sending $RESET#"

        PRINT #1, "$RESET#";

        IF (wait.for.ack <> 0) THEN

            PRINT "Ok"

        ELSE

            PRINT "Command not processed"

        END IF

        GOTO ancora

    ELSEIF (a$ = "f") OR (a$ = "F") THEN

        CALL disegna.foto(foto$)

        CALL invia.comando.fotogramma

        IF (wait.for.ack <> 0) THEN

            CALL invia.fotogramma(foto$)

        END IF

        foto$ = ""

        GOTO ancora

    ELSEIF (a$ = "c") OR (a$ = "C") THEN

        PRINT ""

        PRINT "Sending $CLS#"

        PRINT #1, "$CLS#";

        IF (wait.for.ack <> 0) THEN

            PRINT "Ok"

        ELSE

            PRINT "Command not processed"

        END IF

        GOTO ancora

    END IF

 

LOOP WHILE a$ <> CHR$(27)

 

PRINT "END OF PROGRAM"

 

END

 

 

'---------------------------

'Gestione interrupt seriale

'---------------------------

eventocom:

a$ = INPUT$(1, 1)

buffer$ = buffer$ + a$

PRINT a$;

char.presente = 1

RETURN

 

 

erroro:

RESUME NEXT

 

SUB disegna.foto (foto.out$)

 

DIM eco$

 

PRINT "0 = Figure automatiche, 1 = disegno a mano: "

DO

    a$ = INKEY$

    IF (a$ <> "") THEN

        i = VAL(a$)

        EXIT DO

    END IF

LOOP

IF (i = 1) THEN GOTO disegna

 

PRINT "0 = "; "0"; ""

PRINT "1 = "; "+"; ""

PRINT "2 = "; "Rombo"; ""

PRINT "3 = "; "/"; ""

PRINT "4 = "; "\"; ""

PRINT "5 = "; "Û"; ""

PRINT "6 = "; "X"; ""

 

PRINT "Seleziona la forma (0 .. 6)"

DO

    a$ = INKEY$

    IF (a$ <> "") THEN

        ii = VAL(a$)

        EXIT DO

    END IF

LOOP

 

foto$ = ""

IF (ii = 0) THEN

    foto$ = foto$ + "11111111"

    foto$ = foto$ + "10000001"

    foto$ = foto$ + "10000001"

    foto$ = foto$ + "10000001"

    foto$ = foto$ + "10000001"

    foto$ = foto$ + "10000001"

    foto$ = foto$ + "10000001"

    foto$ = foto$ + "11111111"

ELSEIF (ii = 1) THEN

    foto$ = foto$ + "00010000"

    foto$ = foto$ + "00010000"

    foto$ = foto$ + "00010000"

    foto$ = foto$ + "11111111"

    foto$ = foto$ + "00010000"

    foto$ = foto$ + "00010000"

    foto$ = foto$ + "00010000"

    foto$ = foto$ + "00010000"

ELSEIF (ii = 2) THEN

    foto$ = foto$ + "00010000"

    foto$ = foto$ + "00101000"

    foto$ = foto$ + "01000100"

    foto$ = foto$ + "10000010"

    foto$ = foto$ + "01000100"

    foto$ = foto$ + "00101000"

    foto$ = foto$ + "00010000"

    foto$ = foto$ + "00000000"

ELSEIF (ii = 3) THEN

    foto$ = foto$ + "00000001"

    foto$ = foto$ + "00000010"

    foto$ = foto$ + "00000100"

    foto$ = foto$ + "00001000"

    foto$ = foto$ + "00010000"

    foto$ = foto$ + "00100000"

    foto$ = foto$ + "01000000"

    foto$ = foto$ + "10000000"

ELSEIF (ii = 4) THEN

    foto$ = foto$ + "10000000"

    foto$ = foto$ + "01000000"

    foto$ = foto$ + "00100000"

    foto$ = foto$ + "00010000"

    foto$ = foto$ + "00001000"

    foto$ = foto$ + "00000100"

    foto$ = foto$ + "00000010"

    foto$ = foto$ + "00000001"

ELSEIF (ii = 5) THEN

    foto$ = foto$ + "11111111"

    foto$ = foto$ + "11111111"

    foto$ = foto$ + "11111111"

    foto$ = foto$ + "11111111"

    foto$ = foto$ + "11111111"

    foto$ = foto$ + "11111111"

    foto$ = foto$ + "11111111"

    foto$ = foto$ + "11111111"

ELSEIF (ii = 6) THEN

    foto$ = foto$ + "10000001"

    foto$ = foto$ + "01000010"

    foto$ = foto$ + "00100100"

    foto$ = foto$ + "00011000"

    foto$ = foto$ + "00011000"

    foto$ = foto$ + "00100100"

    foto$ = foto$ + "01000010"

    foto$ = foto$ + "10000001"

END IF

 

ok:

 

ii = ii + 1

IF (ii > 2) THEN ii = 0

    foto.out$ = ""

    FOR i = 1 TO 8

        risu = 0

        FOR j = 1 TO 8

            c$ = MID$(foto$, (i - 1) * 8 + j, 1)

            IF (c$ = "1") THEN

                risu = risu + 2 ^ (j - 1)

            END IF

        NEXT

        foto.out$ = foto.out$ + CHR$(risu)

    NEXT

EXIT SUB

 

disegna:

    foto.out$ = ""

    eco$ = ""

    FOR i = 1 TO 8

        PRINT "Riga"; i; ":";

        INPUT a$

        a$ = a$ + "00000000"

        a$ = MID$(a$, 1, 8)

        eco$ = eco$ + a$ + CHR$(13)

        risu = 0

        FOR j = 1 TO LEN(a$)

            c$ = MID$(a$, j, 1)

            IF (c$ = "1") THEN

                risu = risu + 2 ^ (j - 1)

            END IF

        NEXT

        foto.out$ = foto.out$ + CHR$(risu)

    NEXT

 

    PRINT eco$

 

END SUB

 

SUB invia.comando.fotogramma

 

   PRINT ""

   PRINT "Sending prefix $FOTO#"

   PRINT #1, "$FOTO#";

 

END SUB

 

 

 

SUB invia.comando.riga

'=================================================

' Invia alla seriale la stringa "$RIGA#"

'=================================================

 

   PRINT ""

   PRINT "Sending prefix $RIGA#"

 

   PRINT #1, "$RIGA#"

 

END SUB

 

SUB invia.fotogramma (fotogramma$)

 

    FOR x = 1 TO LEN(fotogramma$)

        byte$ = MID$(fotogramma$, x, 1)

  

        PRINT #1, byte$;

        PRINT "Sending byte number: "; x

        ok = wait.for.ack

        IF (ok = 0) THEN

            PRINT "ERRORE"

            EXIT SUB

        END IF

    NEXT

 

    PRINT "$ENDFOTO#"

    PRINT #1, "$ENDFOTO#"

    ok = wait.for.ack

 

END SUB

 

SUB invia.riga.binaria (riga$)

'=================================================

' Invia alla seriale il valore binario della riga

' RIGA$ nella forma "00101010"

'=================================================

 

    DIM VALORE%

 

    '---------------------------------------------------

    'Faccio in modo che RIGA$ abbia sicuramene 8 digit

    riga$ = "00000000" + riga$

    riga$ = RIGHT$(riga$, 8)

 

    FOR i = 8 TO 1 STEP -1

        a$ = MID$(riga$, i, 1)

        VALORE = VALORE + VAL(a$) * 2 ^ ((8 - i))

    NEXT

 

    PRINT ""

    PRINT "Sending string: "; riga$

    'PRINT #1, RTRIM$(LTRIM$(riga$))

    PRINT #1, CHR$(VALORE)

END SUB

'=================================================

'=================================================

SUB print.menu

 

    PRINT "R --> Reset"

    PRINT ""

    PRINT "F --> Spedisci fotogramma"

    PRINT ""

    PRINT "C --> Cancella memoria PIC"

    PRINT ""

 

END SUB

 

FUNCTION processa.buffer$ (buffer$)

'=================================================

'Questa function verifica che si sia ricevuto "$ACK#"

'Rende la stringa ricevuta

'=================================================

 

    IF LEN(buffer$) > 5 THEN buffer$ = ""

         

    IF buffer$ = "$ACK#" THEN

        buffer$ = ""

        PRINT ""

        PRINT "$ACK# received..."

        processa.buffer$ = "$ACK#"

    ELSEIF buffer$ = "$NAK#" THEN

        buffer$ = ""

        PRINT ""

        PRINT "$NAK# received..."

        processa.buffer$ = "$NAK#"

    END IF

  

    char.presente = 0

 

END FUNCTION

 

'=================================================

'=================================================

FUNCTION wait.for.ack%

 

    PRINT "Wait for $ACK#.."

    t = TIMER

    DO

        risu$ = processa.buffer(buffer$)

        IF (risu$ <> "") THEN

            IF (risu$ = "$ACK#") OR (risu$ = "$NAK#") THEN EXIT DO

        END IF

        IF ((TIMER - t) > 1) THEN

            PRINT ".";

            c = c + 1

            IF (c > 10) THEN

                risu$ = "Time-out error"

                EXIT DO

            END IF

            t = TIMER

        END IF

        a$ = INKEY$

        IF (a$ <> "") THEN

            IF (a$ = CHR$(27)) THEN

                risu$ = "Break"

                EXIT DO

            END IF

        END IF

    LOOP

 

    IF (risu$ <> "$ACK#") AND (risu$ <> "$NAK#") THEN

        PRINT risu$

    END IF

 

    IF (risu$ = "$ACK#") THEN

        wait.for.ack = 1

    ELSE

        wait.for.ack = 0

    END IF

 

 

END FUNCTION


Appendice 2

Programma simulatore insegna

 


DECLARE SUB processa.buffer (buffer$)

'*******************************************************

'* simu4sir.bas

'* pc. n. 5

'* autore: Freni

'* scopo: simula il pannello a LED

'*******************************************************

 

ON ERROR GOTO errore

 

'OPEN "com1:1200,n,8,1" FOR INPUT AS 1

 

 

DO

    a$ = INKEY$

    PRINT ".";

    IF (a$ <> "") THEN

        IF (ASC(a$) = 27) THEN EXIT DO

    END IF

    'a$ = INPUT$(1, 1)

   

    '--------------------------------------------------------

    'In A$ c'Š l'eventuale carattere arrivato dalla seriale

    IF (a$ <> "") THEN

        'E' arrivato un carattere dalla seriale

        PRINT a$;

        buffer$ = buffer$ + a$

        CALL processa.buffer(buffer$)

    END IF

LOOP

 

END

 

errore:

RESUME NEXT

 

SUB processa.buffer (buffer$)

'=============================================================

'In buffer ci sono i caratteri arrivati dalla seriale

'=============================================================

 

    '------------------------------------------

    'cerco il carattere "$"

    trovatoinizio = 0

    FOR i = 1 TO LEN(buffer$)

        c$ = MID$(buffer$, i, 1) 'Prendo il carattere i-esimo di buffer

        IF (c$ = "$") THEN

            trovatoinizio = 1

            EXIT FOR

        END IF

    NEXT

  

    IF (trovatoinizio = 1) THEN

    'BOH'

        '------------------------------------------

        'Se ho trovato $, allora cerco #

        trovatofine = 0

        FOR j = i + 1 TO LEN(buffer$)

            c$ = MID$(buffer$, j, 1) 'Prendo il carattere i-esimo di buffer

            IF (c$ = "#") THEN

                trovatofine = 1

                EXIT FOR

            END IF

        NEXT

    END IF

     

    IF (trovatoinizio = 0) OR (trovatofine = 0) THEN EXIT SUB

 

    '---------------------------------------------------

    'Se sono arrivato qui, allora ho trovato un comando

    '---------------------------------------------------

 

    'Interpreto il comando

 

    comando$ = MID$(buffer$, i, j - i + 1)

 

  '------------------------------------------------------

  'Se viene riconosciuto un comando, il computer deve

  'visualizzare la scritta "Hallo World"

  '------------------------------------------------------

 

  'Visualizzo la scritta

 

  SELECT CASE UCASE$(comando$)

    CASE "$START#": PRINT "hello start"

    CASE "$FOTO#": PRINT "hello foto"

    CASE "$END#": PRINT "hello end"

    CASE "$ACK#": PRINT "hello ack"

    CASE "$NACK#": PRINT "hello nack"

    CASE ELSE:

  END SELECT

 

END SUB

 


Appendice 3

Firmware insegna


/**************************************************************

 * insegna_int.c

 * pc.n. 3

 * Alunno: Tornaboni

 * Data: 05/11/04

 * Scopo:

 **************************************************************/

 

#include "C:\HT-PIC\include\pic.h"

#include "insegna.h"

#include "rx_tx.h"

#include "gestione_shift_reg.h"

#include "ram.h"

 

 

/*##################################################################

 *

 * MAIN

 *

 *             Pannello led

 *            +---------------------------------------+

              |        Vcc    Vcc                     |

                      |   Strobe|   OE|                       |

              | +-------+-----+----------------+      |

RA2  ck ----->+>| Shift reg. valore colonna    |      |

RA3  dato --->+>|  Lo strobe è sempre a 1      |      |

              | +-------+-+-+-+-+-+-+-+--------+      |

              |         | | | | | | | |               |

              |         v v v v v v v v               |

              |                                       |

              | Shift reg. selezione riga             |

              |  +---+                                |

              |  |   |                                |

RB0 ck ------>+->|   +-->                             |

RB1 dato ---->+->|   +-->                             |

              |  |   +-->                             |

              |  |   +-->                             |

              |  |   +-->                             |

              |  |   +-->                             |

              |  |   +-->                             |

              |  |   +-->      Vcc                    |

              |  |   |          |                     |

              |  |   +-strobe---+

              |  |   +-OE-------+

              |  +---+                                |

              |                                       |

              +---------------------------------------+

 

 * Shift register di selez. colonna

 * Per caricare una dato da 8 bit:

 * Carico il dato sullo SR; non importa dare lo strobe perché è sempre a 1

 *

 

 * Shift register di selez. riga

 * Per caricare una dato da 8 bit:

 * 1) Carico il dato sullo SR

 * 2) Mando strobe a 1

 *

 

 Caricamento dato su un SR:

 

          /----\     /----\      /----\      /----\

     ck -+      +---+      +----+      +----+      +----

          |          |           |           |

          |          |           |           |

dato  /----------\/---------\/-----------\/-----------\

      \----------/\---------/\-----------/\-----------/

 

In corrispondenza del fronte in salita del ck, il dato entra nello sr

 

 

---------------------------------------------

 * Mappa IO Port (rivedere !!!!!!!!!!!!)

 *

 * PORTA     Bit 0 - nc

 *          Bit 1 - nc

 *          Bit 2 - nc

 *          Bit 3 - Tx seriale - OUT

 *          Bit 4 - Rx seriale - IN

 *          Bit 5 - -

 *          Bit 6 - -

 *          Bit 7 - -

 *

 * PORTB     Bit 0 - Data   shift reg. righe   - OUT

 *          Bit 1 - Clock  shift reg. righe   - OUT

 *          Bit 2 - Strobe shift reg. righe   - OUT

 *          Bit 3 - Data   shift reg. colonne - OUT

 *          Bit 4 - Clock  shift reg. colonne - OUT

 *          Bit 5 - nc

 *          Bit 6 - nc

 *          Bit 7 - nc

 *----------------------------------------------

 

Logica di funzionamento per la riproduzione del filmato:

 

1) I fotogrammi in arrivo dal PC vengono memorizzati in GFilmato[]

2) Ad ogni intervallo di cambio fotogramma, carico in GRigaLed[]

   il numero di byte richiesti dalla riga:

              R C

    -Pannello 1x1 = 1 byte

    -Pannello 2x2 = 2 byte

    -Pannello 3x3 = 3 byte

    -Pannello 2x4 = 4 byte

       -ecc

   e lo invio al pannello.

 

**********************************************************************/

int ricevi_fotogramma(void);

int ricevi_e_memorizza(void);

int processa_comando(void);

int confronta_stringa(const char *stringa, const char *modello, char n);

int esegui_comando(char comando);

void spedisci_valore_riga(char dato);

 

 

char Gcomando[15]; //comando ricevuto dal pc

char Gcounter_caratteri_rx;

 

//GFilmato[] contiene l'intera sequenza di fotogrammi

//che vengono copiati, riga dopo riga, in  GRigaLed[]

//bank3 char GFilmato[NBYTES_FILMATO];

bank2 char GRigaLed[NBYTES_RIGA_LED];

 

char Gflag_comando_presente;

int Gcount_fotogrammi_ricevuti;

int Gcount_fotogrammi_inviati;

 

unsigned char Gcarattere_presente;

unsigned char modo;

 

unsigned char GNrighe;

unsigned char GNcolonne; // Una riga di LED è lunga NColonne

 

 

 

#define MODO_MAIN 0

#define MODO_RXRIGA 1

 

#define CMD_START   1

#define CMD_NR             2

#define CMD_NC             3

#define CMD_FOTO    4

#define CMD_RIGA    5

#define CMD_END            6

#define CMD_ACK            7

#define CMD_NAK         8

#define CMD_CLS            9

#define CMD_RESET   10    

 

/*

__EEPROM_DATA(0b00000001,

              0b00000001,

              0b10000100,

              0b10000100,

              0b01001000,

              0b01001000,

              0b00110000,

              0b00110000);

*/

 

__EEPROM_DATA(0x01,0x01,0x84,0x84,0x48,0x48,0x30,0x30);

__EEPROM_DATA(0xff,0x80,0x80,0xff,0x1,0x1,0x1,0xff);

__EEPROM_DATA(0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10);

__EEPROM_DATA(0xff,0x81,0x81,0xff,0x88,0x84,0x82,0x81);

__EEPROM_DATA(0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10);

__EEPROM_DATA(0xff,0x81,0x81,0x81,0x81,0x81,0x81,0xff);

 

 

 

 

void main(void)

{  

      

       int i,ok,timerc;

      

       //----------------------------------------------------------

       //PORTA può essere convertitore AD o IO digitale

       ADCON1=0b00000111;  //Set PORTA come IO digitale

       TRISA = 0x00;

       TRISB = 0x00;

       TRISC = 0xff;

       RAM_RW=1; //read

       RAM_OE=1; //out enable true

      

       /*-------------------------------------------

         Piedini della seriale

       --------------------------------------------*/

       //TRISA = TRISA | PORT_RX;

      

       //------------------------------

       // Scheda definitiva

       TRISB = TRISB | PORT_RX;

       TRISA = TRISA & PORT_TX;

 

       Gcomando[0]=0;

       Gcount_fotogrammi_ricevuti=0;

       Gcount_fotogrammi_inviati=0;

       timerc=0;

 

 

       INTE = 1;           // enable the external interrupt

       GIE = 1;            // Global interrupt enable

       INTEDG = 0;         // falling edge trigger the interrupt

                                  // [fronte di discesa]

 

reset:

       GNrighe=8;    // prova debug

    GNcolonne=8;  // prova debug

 

 

       //--------------------------------------------------

       // Carico i fotogrammi di presentazione memorizzati

       // nella EEPROM

       //--------------------------------------------------

       Gcount_fotogrammi_ricevuti=6;

       for(i=0;i<Gcount_fotogrammi_ricevuti*8;i++)

       {

             //GFilmato[i]=EEPROM_READ(i);

             scrivi_byte_fotogramma(EEPROM_READ(i),i);     

       }   

      

       //--------------------------------------------

       // Visualizzo il filmato di presentazione

       //--------------------------------------------

       modo=MODO_MAIN;

       for(;;)

       {

             if(Gflag_comando_presente) break;

             timerc++;         

             if(timerc>=30000)

             {

                    timerc=0;         

                    invia_fotogramma();

             }

       }

 

 

       for(;;)

       {

             modo=MODO_MAIN;

             if(Gflag_comando_presente)

             {

                    ok=processa_comando();

                    if(ok==CMD_RESET)

                    {

                           send_string("$ACK#");

                           goto reset;

                    }

                                       

                    if(ok)

                    {

                           //Processa comando rende un numero

                           //associato al comando da eseguire

                           ok=esegui_comando(ok);

                    }     

                    else

                    {

                           send_string("$NAK#");      //Non ho riconosciuto il

                                               //comando

                    }

                    modo=MODO_MAIN;

             }

                   

             timerc++;         

             if(timerc>=15000)

             {

                    timerc=0;         

                    if(Gcount_fotogrammi_ricevuti>0)

                    {

                           invia_fotogramma();

                    }

             }

       }

}

 

/* END MAIN */

 

 

 

/*============================================================

       Processa il comando

       Valori resi: numero associato al comando (>0) se ok

                    0=not ok

==============================================================*/

int processa_comando(void)

{

       int r;

      

      

       if(confronta_stringa("$START#",Gcomando,7))

       {

             r=CMD_START;

       }

       else if(confronta_stringa("$NR#",Gcomando,4))

       {

             r=CMD_NR;

       }

       else if(confronta_stringa("$NC#",Gcomando,4))

       {

             r=CMD_NC;

       }

       else if(confronta_stringa("$FOTO#",Gcomando,6))

       {

             r=CMD_FOTO;

       }

       else if(confronta_stringa("$RIGA#",Gcomando,6))

       {

             r=CMD_RIGA;

       }

       else if(confronta_stringa("$END#",Gcomando,5))

       {

             r=CMD_END;

       }

       else if(confronta_stringa("$ACK#",Gcomando,5))

       {

             r=CMD_ACK;

       }

       else if(confronta_stringa("$NAK#",Gcomando,5))

       {

             r=CMD_NAK;

       }

       else if(confronta_stringa("$CLS#",Gcomando,5))

       {

             r=CMD_CLS;

       }

       else if(confronta_stringa("$RESET#",Gcomando,5))

       {

             r=CMD_RESET;

       }

       else

       {

             r=0;

       }

 

       Gflag_comando_presente=0;

       Gcounter_caratteri_rx=0;

       return(r);

 

}

 

 

/*============================================================

   Confronta i primi N caratteri delle due stringhe.

   Se sono uguali, rende 1, altrimenti 0

============================================================*/

int confronta_stringa(const char *stringa, const char *modello, char n)

{

       char i;

 

       for(i=0;i<n;i++)

       {

             if(stringa[i]!= modello[i]) return(0);

 

             //0 è il terminatore di stringa        

             if(modello[i]==0) return(1);

       }

 

       return(1);

      

}

 

/*============================================================

 Esegue un comando e ritorna 1

 ==============================================================*/

int esegui_comando(char comando)

{

       if(comando==CMD_START) 

       {

       }

       else if(comando==CMD_NR)

       {     

             send_string("$ACK#");

       }

       else if(comando==CMD_NC)  

       {     

             send_string("$ACK#");

       }

       else if(comando==CMD_FOTO)

       {

              int ok;

              ok=ricevi_fotogramma();

              if(ok) Gcount_fotogrammi_ricevuti++;

       }   

       else if(comando==CMD_RIGA)

       {

             send_string("$ACK#");

             do

             {

                    if(Gcarattere_presente==1)

                    {

                           PORTB=Gcomando[0];        

                           send_string("$ACK#");

                           break;

                    }

             }while(1);

       }

 

       else if(comando==CMD_END)

       {

       }

       else if(comando==CMD_ACK)

       {

       }

       else if(comando==CMD_NAK)

       {

       }

       else if(comando==CMD_CLS)

       {

             clear_panel();

             send_string("$ACK#");

       }

       else

       {

             //Non ho riconosciuto il comando

             return(0);

       }

 

       return(1);

}

 

 

/*=================================================================

  Riceve un fotogramma e lo memorizza in Gfilmato[].

  Rende: 1 se ok

         0 se not ok

  =================================================================*/

int ricevi_fotogramma()

{

       char i,j;

      

      

//La risposta viene messa qui per non rischiare di perdere

       //il sincronismo della seriale

       // il pc riceve ack e quindi spedisce 8 bytes (poi saranno di piu')  

       send_string("$ACK#");

 

       modo=MODO_RXRIGA;

       i=GNrighe*Gcount_fotogrammi_ricevuti; //i è il puntatore all'indice

                                         //dell'array.

    j=0;

   

    // ricevo i bytes del fotogramma

    do

    {  

       if(Gcarattere_presente)   

             {

                    Gcarattere_presente=0;

                    scrivi_byte_fotogramma(Gcomando[0],i);

                    i++;

                    j++;

                    send_string("$ACK#");

             if(j>(GNcolonne-1)) break; //poi il numero 7 diventerà funzione

                                       //di numero righe e colonne

       }

    }while(1);

 

       //Aspetto $ENDFOTO#

       modo=MODO_MAIN;

       for(;;)

       {      if(Gflag_comando_presente) break;

       }

       modo=MODO_RXRIGA; //Se arriva qualcosa non lo processa

 

       Gcounter_caratteri_rx=0; // per sicurezza

       Gflag_comando_presente=0;

       if(confronta_stringa("$ENDFOTO#",Gcomando,9))

       {  

             send_string("$ACK#");

             return(1);

       }

 

       //Se arriva qui non ha ricevuto $ENDFOTO#

       send_string("$NAK#");

       return(0);

      

}

 

/*=====================================================

  Esportata

  E' chiamata dall'interrupt della seriale ogni volta

  che riceve un carattere.

=======================================================*/

void add_carattere(char c)

{

 

       if(modo==MODO_MAIN)

       {     

             Gcomando[Gcounter_caratteri_rx]=c;     

             Gcounter_caratteri_rx++;

             if (c=='#')

              {

                    Gflag_comando_presente=1;

                    Gcounter_caratteri_rx=0;

              }

       }

       else if(modo==MODO_RXRIGA)

       {

             Gcomando[0]=c;     

             Gcarattere_presente=1;

       }

      

}           

 

/**************************************************************

 * ram.c

 * pc.n. 3

 * Alunno: Tornaboni

 * Data: 19/12/05

 * Scopo: Gestione RAM

 **************************************************************/

 

#include "C:\HT-PIC\include\pic.h"

#include "insegna.h"

#include "gestione_shift_reg.h"

#include "ram.h"

#include "gestione_shift_reg.h"

#include "ritardi.h"

 

 

 

/*============================================================

   Send data adress to RAM'S Shift Registers (low level)

==============================================================*/

void scrivi_adress(int addr)

{

  int maschera,ii;

  int i,uscita;

 

 

  maschera=0b000000000001;

 

  SH_RAM_STROBE=1;

  SH_RAM_CLK=0;

  for(i=0;i<12;i++)

  {

       ii=addr & maschera;

       if (ii==0)

       {

             uscita=0;

       }

       else

       {

             uscita=1;

       }

       SH_RAM_DATA=uscita;

             SH_RAM_CLK=1;      

             ritardo(DTSH);

             SH_RAM_CLK=0;      

             ritardo(DTSH);

             maschera=maschera << 1;

   }  

 

  SH_RAM_CLK=1;

  SH_RAM_STROBE=0;

  ritardo(DTSH);

}

 

/*============================================================

   Write video data content into RAM (low level)

============================================================*/

void scrivi_ram(char data, int address)

{

       scrivi_adress(address);

       TRISC=0x00; //output

       PORTC=data; 

       RAM_RW=0; //write mode

       ritardo(DTSH);

       TRISC=0xff; //input

       RAM_RW=1; // read mode

}

 

/*============================================================

   Read video data content from RAM (low level)

============================================================*/

char leggi_ram(int addr)

{

       char i;

      

       scrivi_adress(addr);

       RAM_OE=0; //output enable true

       ritardo(DTSH);     

       i=PORTC;

       RAM_OE=1; // output enable false

      

       return i;

}

 

/*============================================================

  Legge dalla RAM (o dalla matrice globale) il byte INDIRIZZO.

============================================================*/

char leggi_byte_fotogramma(int indirizzo)

{

       return(leggi_ram(indirizzo));

      

       //return(GFilmato[indirizzo]);

}

 

/*=========================================================

  Scrive nella RAM (o dalla matrice globale) nel byte

  INDIRIZZO il valore VALORE.

===========================================================*/

void scrivi_byte_fotogramma(char data, int address)

{

       scrivi_ram(data,address);

 

       //GFilmato[address]=data;

}


/**********************************************************

 * ritardi.c

 **********************************************************/

 

 

 

/*============================================================

  Ritardo generico di N cicli

==============================================================*/

void ritardo(int n) 

{                                    

       int i;                                

                                      

       for(i=0;i<n;i++);

 

}

 

 


/****************************************************

 * rx_tx.c

 ****************************************************/

#include "C:\HT-PIC\include\pic.h"

#include "insegna.h"

#include "rx_tx.h"

 

 

/*============================================================

   Riceve un carattere dalla seriale.

   Ordine di ricezione bit: dal più basso al più alto.

  

   Rende 1 se ha ricevuto qualcosa

   rende 0 se no.

============================================================*/

/*

unsigned char rx_char(unsigned char *c)

{

       unsigned char bitno,rx;

   

       if(RxData==RXUNO) return(0); //If no start bit, it return

        

       rit_milleduecento_mezzi();

      

       *c = 0;

       for(bitno=0;bitno<7;bitno++)

       {      

       rit_milleduecento_hz();

             if(RxData==RXUNO)

                    rx=0x80;

             else

             rx=0;

 

             *c = (*c | rx);

             *c = *c>>1;

    }

       rit_milleduecento_hz();

    if(RxData==RXUNO)

      rx=0x80;

    else

             rx=0;

 

    *c = (*c | rx);

//     rit_novemilaseicento_hz(); //Stop bit

       rit_milleduecento_hz(); //Stop bit

 

    return(1);

}

*/

 

/*======================================================

  CIN is transmitted on PORTB.

  vel=12 --> Baud rate=1200 bit/sec

  vel=96 --> Baud rate=9600 bit/sec

=========================================================*/

void tx_char(char cin)

{

       char i,ris;

 

       INTE = 0;           // disable the external interrupt

       TxData=TXZERO;            //trasmette il bit di start a livello basso

       rit_seriale();

            

       for(i=0;i<8;i++)            //TRASMETTE 8 BIT

       {

             //spedisco i bit nella sequenza: 0,1,2,..,7

             //Il bit buono è il bit 0.

                    ris= cin & 0x01;

          

             if (ris==0x01)

             {      // Se il bit da trasmettere è 1...

                    TxData=TXUNO;

             }

             else

             {      //Se il bit da trasmettere è 0 ...

             TxData=TXZERO;

             }

             rit_seriale();

       

             cin=cin>>1; //shift a destra del byte da trasmettere

       }

 

       //trasmette il bit di stop a livello alto

       TxData=TXUNO;            

 

       //Metto due ritardi per sicurezza

       rit_seriale();

       rit_seriale();

       INTE = 1;           // enable the external interrupt

}  

 

/*==========================================================

  It send the string S[] at the Falcom

==========================================================*/

void send_string(const char *s)

{

       char i;

      

       for(i=0;;i++)

       {

             if(s[i]==0) break;

             tx_char(s[i]);

       }

}

 

/*============================================================

  Ritardo da 1/1200 sec (quarzo da 5.000 MHz)

==============================================================*/

void rit_seriale(void)

{

       rit_milleduecento_hz();

 

}

/*============================================================

  Ritardo da 1/1200 sec

  (quarzo da 5.000 MHz: i=60)

  (quarzo da 8.000 MHz: i=90)

==============================================================*/

void rit_milleduecento_hz(void)

{                                    

       int i;                                

                                      

       for(i=0;i<92;i++);

 

}

/*============================================================

  Ritardo da 1/2(1/1200 sec )(quarzo da 5.000 MHz)

==============================================================*/

void rit_milleduecento_mezzi(void) 

{                                    

       int i;                                

                                      

       for(i=0;i<30;i++);

 

}

 

//---------------------------------------------------------

// Here be interrupt function - the name is unimportant.

//---------------------------------------------------------

static void interrupt isr(void)               

{

       unsigned c, ii;

       unsigned char bitno,rx;

       #define      N 105

 

       if(INTF)

       {      INTE = 0;           // disable the external interrupt

             Gcarattere_presente=0;

 

             for(ii=0;ii<20;ii++); //rit_milleduecento_mezzi();

              if(RxData==RXUNO)

              {

                    //Error: spike

                    INTF = 0;    // clear the interrupt

                    INTE = 1;    // enable the external interrupt

                    return; //If no start bit, it return

              }

               

             for(ii=0;ii<30;ii++); //rit_milleduecento_mezzi();

              c = 0;

              for(bitno=0;bitno<7;bitno++)

              {      

              for(ii=0;ii<N;ii++); //rit_milleduecento_hz();

                    if(RxData==RXUNO)

                          rx=0x80;

                    else

                    rx=0;

      

                    c = (c | rx);

                    c = c>>1;

           }

              for(ii=0;ii<N;ii++); //rit_milleduecento_hz();

           if(RxData==RXUNO)

             rx=0x80;

           else

                    rx=0;

      

           c = (c | rx);

 

             for(ii=0;ii<N;ii++); //rit_milleduecento_hz(); //Stop bit

       }

       else

       {

             c=0;

       }

 

       //Il carattere ricevuto è in C

 

       add_carattere(c);  

 

       INTF = 0;    // clear the interrupt

       INTE = 1;    // enable the external interrupt

}


/****************************************************

 * gestione_shift_Reg.c

 ****************************************************/

#include "C:\HT-PIC\include\pic.h"

#include "insegna.h"

#include "ritardi.h"

#include "gestione_shift_reg.h"

#include "ram.h"

 

 

 

void memorizza_riga_374(char dato);

void invia_riga_led(char dato);

 

/*==============================================================

  Sub da chiamare ad alto livello.

  Invia un singolo fotogramma all'insegna

  Questa sub lavora con i dati contenuti nella matrice

  globale Gfilmato[]

================================================================*/

void invia_fotogramma(void)

{

       char i,k;

 

 

       Gcount_fotogrammi_inviati++;

       if(Gcount_fotogrammi_inviati>Gcount_fotogrammi_ricevuti)

       {

             Gcount_fotogrammi_inviati=1;

       }

       k=Gcount_fotogrammi_inviati-1;

      

       Data_selrighe=1;

      

       //Copio in GRigaLed la riga attuale

       //Modificare per pannello grosso

      

       GRigaLed[0]=leggi_byte_fotogramma(0+(k*GNcolonne));

       //GRigaLed[0] = GFilmato[0+(k*GNcolonne)];

       memorizza_riga_374(GRigaLed[0]);

       Data_selrighe=0;

       for(i=1;i<GNrighe;i++)

       {     

             //GRigaLed[0] = GFilmato[i+(k*GNcolonne)];

             GRigaLed[0] = leggi_byte_fotogramma(i+(k*GNcolonne));

             memorizza_riga_374(GRigaLed[0]);

       }

}

 

/*==============================================================

  Memorizza una riga nello shift register di selezione riga

//poi dovrà arrivarci un array lungo tanti bytes quanti

//sono i pannelli in orizzontale

  ==============================================================*/

void memorizza_riga_374(char dato)

{

 

//     Strobe_selrighe=1;  

 

       Clock_selrighe=0;

       ritardo(DTSH);

       invia_riga_led(dato);

       Clock_selrighe=1;

       ritardo(DTSH);

       Clock_selrighe=0;

       ritardo(DTSH);

 

//     Strobe_selrighe=0;  

}

 

 

 

/*=====================================================================

  Invia 8 bit del dato allo SR che contiene il dato da mettere

  nel bus dati dell'insegna (SR in alto)

=======================================================================*/

void invia_riga_led(char dato)

{

  char maschera,ii;

  int i,uscita;

 

 

  //maschera=0b00000001;

  maschera=0b10000000;

 

  Clock_valcol=0;

  for(i=0;i<GNcolonne;i++)

  {

       ii=dato & maschera;

       if (ii==0)

       {

             uscita=0;

       }

       else

       {

             uscita=1;

       }

       Data_valcol=uscita;

       Clock_valcol=1;   

       ritardo(DTSH);

       Clock_valcol=0;   

       ritardo(DTSH);

       //maschera=maschera << 1;

       maschera=maschera >> 1;

  }   

}

 

/*==============================================================

   Spegne il pannello e azzera la memoria filmato

================================================================*/

void clear_panel(void)

{

       char i;

      

      

       Gcount_fotogrammi_inviati=0;

       Gcount_fotogrammi_ricevuti=1;

       for(i=0;i<GNcolonne;i++)

       {

             //GFilmato[i]=0;

             scrivi_byte_fotogramma(0,i);

       }

       invia_fotogramma();

      

       Gcount_fotogrammi_inviati=0;

       Gcount_fotogrammi_ricevuti=0;

      

}


/*******************************************************************

 gestione_shift_reg.h

 *******************************************************************/

 

#define DTSH 50

 

void invia_fotogramma(void);

void clear_panel(void);


/******************************************************

 INSEGNA.H

******************************************************/

 

 

//--------------------------------------------------

//Definizione bit shift reg. valore colonna

/*

//--------------------------------------

//Vecchia scheda

#define Clock_valcol       RB4

#define Data_valcol        RB3

#define Clock_selrighe     RB2

#define Data_selrighe      RB1

#define Strobe_selrighe RB4

*/

 

//--------------------------------------

//Nuova scheda

#define Clock_valcol       RA0 //csrc

#define Data_valcol        RB2 //dsrc

#define Clock_selrighe     RA2 //csrr

#define Data_selrighe      RA3 //dsrr

#define Strobe_selrighe RB1

 

#define NBYTES_FILMATO 90

#define NBYTES_RIGA_LED 10

 

 

 

//-----------------------------------------------

// Funzioni pubbliche

//-----------------------------------------------

void add_carattere(char c);

 

 

//-----------------------------------------------

// Variabili globali

//-----------------------------------------------

extern unsigned char Gcarattere_presente;

extern int Gcount_fotogrammi_inviati;

extern int Gcount_fotogrammi_ricevuti;

 

//GFilmato[] contiene l'intera sequenza di fotogrammi

//che vengono copiati, riga dopo riga, in  GRigaLed[]

//extern bank3 char GFilmato[NBYTES_FILMATO];

extern bank2 char GRigaLed[NBYTES_RIGA_LED];

extern char GNrighe;

extern char GNcolonne;

 

 

 

/**************************************************************

 * ram.h

 * pc.n. 3

 * Alunno: Tornaboni

 * Data: 19/12/05

 * Scopo: Headers RAM

 **************************************************************/

 

#define SH_RAM_STROBE   RA4 //Strobe dello sr collegato alla RAM

#define SH_RAM_DATA     RB5 //Data dello sr collegato alla RAM

#define SH_RAM_CLK      RA5 //Clock dello sr collegato alla RAM

#define RAM_RW          RB3 //Read Write della RAM stessa

#define RAM_OE          RB4 //Output enable della RAM stessa

 

void scrivi_adress(int addr);

void scrivi_ram(char data,int address);

char leggi_ram(int addr);

char leggi_byte_fotogramma(int indirizzo);

void scrivi_byte_fotogramma(char data,int address );

 


/******************************************************

 RITARDI.H

******************************************************/

 

 

void ritardo(int n);

 

/******************************************************

 RX_TX.H

******************************************************/

 

 

//-----------------------------------------------

// Valori RX non invertiti perché sulla scheda

// c'è un BJT che inverte

#define RXUNO  1

#define RXZERO 0

 

//-----------------------------------------------

// Valori TX invertiti perché lo standard RS-232

// prevede valori invertiti

#define TXUNO  0

#define TXZERO 1

 

 

 

//--------------------------------------------------

//Definizione bit rs232

//f84

/*

static bit TxData @ (unsigned)&PORTA*8+3;    // bit3 in port A 

static bit RxData @ (unsigned)&PORTA*8+4;    // bit4 in port A       

#define PORT_TX 0xf7 //1111 0111 - bit4 in port A

#define PORT_RX 0x10 //0001 0000 - bit3 in port A

*/

 

//----------------------------------------------

//f876

/*

Sperimentale

#define  TxData RA0  

#define  RxData RA1

#define PORT_TX 0b11111110 

#define PORT_RX 0b00000010

*/

//Definitiva

#define  TxData RA1

#define  RxData RB0

#define PORT_TX 0b11111101 

#define PORT_RX 0b00000001

 

 

 

 

//--------------------------------------------------------------

//Functions protoptypes

//--------------------------------------------------------------

void tx_char(char cin);

unsigned char rx_char(unsigned char *c);

void send_string(const char *s);

 

void rit_novemilaseicento_hz(void);

void rit_novemilaseicentomezzi_hz(void);

void rit_milleduecento_hz(void);

void rit_milleduecento_mezzi(void);

void rit_seriale(void);

 

 


Appendice 4

Codice VB gestione insegna


'***************************************************************

'* Main form progetto insegna

'* principale.frm

'***************************************************************

'* Trasmissione seriale:

'* $FOTO#

'* fotogramma 1

'* $ENDFOTO#

'* $FOTO#

'* fotogramma 2

'* $ENDFOTO#

'* ecc...

'***************************************************************

'* formato file su disco:

'* 32 numero righe

'* 32 numero colonne

'* 4  numero fotogrammi

'* $inizio

'* 000101001010101010110101010 stringa fotogramma 1

 

Dim numfoto As Integer 'contiene il numero di fotogrammi

Dim vettoreseq(10000) As String      'contiene la sequenza di fotogrammi

Dim buffer As String       'contiene la mappa di bit del disegno copiato

Dim buffer_seriale As String 'buffer ricezione seriale

Dim termina As Byte ' flag di interruzione trsmiss. seriale

 

   

'========================================================================

'Questa sub serve ad aggiungere un fotogramma

'========================================================================

Private Sub aggfoto_Click()

 

    Dim mappabit As String  'contiene la mappa di bit del fotogramma corrente

 

    'Questo blocco crea un errore se si tenta di aggiungere il 10001esimo

    ‘fotogramma

    If numfoto > 10000 Then

        MsgBox "Numero massimo di fotogrammi raggiunto!"

        Exit Sub

    End If

 

    'Questo blocco salva il fotogramma corrente prima di aggiungere quello

    ‘nuovo

     For X = 0 To quadretto.Count - 1

        mappabit = mappabit + quadretto(X).Tag

     Next

 

    vettoreseq(numfoto) = mappabit

    numfoto = numfoto + 1

    etichetta.Caption = numfoto

 

    For Y = o To quadretto.Count - 1          'Questo ciclo cancella tutti

        quadretto(Y).BackColor = 16777215     'i quadretti

        quadretto(Y).Tag = 0                  'del nuovo

    Next                                      'fotogramma

 

End Sub

   

'=====================================================

'Questa sub permette di vedere l'anteprima del filmato

'=====================================================

Private Sub anteprima_Click()

 

    Dim mappabit As String 'contiene la mappa bit del fotogramma corrente

    Dim k As Integer 'contatore

 

        If anteprima.Caption <> "Stop" Then

            anteprima.Caption = "Stop"

        Else

            anteprima.Caption = "Anteprima"

        End If

   

    'questo blocco gestisce la velocità dell'anteprima

    If lenta.Value = True Then ritardo.Interval = 500

    If normale.Value = True Then ritardo.Interval = 100

    If veloce.Value = True Then ritardo.Interval = 30

 

'questo blocco salva il fotogramma corrente prima di visualizzare 'anteprima

    For q = 0 To quadretto.Count - 1

        mappabit = mappabit + quadretto(q).Tag

    Next

   

    vettoreseq(etichetta.Caption) = mappabit

 

        Do While anteprima.Caption = "Stop"

            'Questo ciclo va dal primo all'ultimo fotogramma

            For j = 1 To numfoto

                If anteprima.Caption <> "Stop" Then Exit For

                etichetta.Caption = j

                k = 0

 

'questo blocco legge i bit del fotogramma che deve essere   

‘visualizzato

                For X = 0 To quadretto.Count - 1

                    k = k + 1

                    valore = Mid(vettoreseq(j), k, 1)

                   

                        Select Case valore

                            Case "0"

                                quadretto(X).Tag = 0

                                quadretto(X).BackColor = 16777215

                            Case "1"

                                quadretto(X).Tag = 1

                                quadretto(X).BackColor = 0

                        End Select

               

                Next

 

                'questo blocco non visualizza il prossimo fotogramma fino a

                ‘che il timer(ritardo) non viene disabilitato

                ritardo.Enabled = True

                Do While ritardo.Enabled = True

                    DoEvents

                Loop

            Next

        Loop

End Sub

   

'========================================================================

'Questa sub permette vedere il prossimo fotogramma

'========================================================================

Private Sub avanti_Click()

 

    Dim j As Integer 'contiene il numero del fotogramma successivo

    Dim k As Integer 'contatore

    Dim mappabit As String

 

    'se si e' gia' posizionati sull'ultimo fotogramma la sub non viene

    ‘eseguita

    If Val(etichetta.Caption) >= numfoto Then Exit Sub

 

    'questo blocco salva il fotogramma corrente prima di visualizzare il

    ‘successivo

     For X = 0 To quadretto.Count - 1

        mappabit = mappabit + quadretto(X).Tag

     Next

 

    vettoreseq(etichetta.Caption) = mappabit

    j = Val(etichetta.Caption + 1)

    etichetta.Caption = j

 

     'questo ciclo legge i bit del fotogramma che deve essere visualizzato

     For X = 0 To quadretto.Count - 1

         k = k + 1

         valore = Mid(vettoreseq(j), k, 1)

               

             Select Case valore

                 Case "0"

                     quadretto(X).Tag = 0

                     quadretto(X).BackColor = 16777215

                 Case "1"

                     quadretto(X).Tag = 1

                     quadretto(X).BackColor = 0

             End Select

     Next

 

    etichetta.Caption = j

 

End Sub

 

'========================================================================

'Questa sub trasmette il comando $CLS#

'========================================================================

Private Sub btncls_Click()

 

    Call print_txt(frm_invio_sequenza.txtlogging, "Invio comando $CLS# , _

                   aspetto $ACK#..." + vbCrLf)

 

    seriale.Output = "$CLS#"

    Do Until aspetta_ack = True

        DoEvents

    Loop

    Call ritardo_milli(100)

 

    Call print_txt(frm_invio_sequenza.txtlogging, "Invio comando $CLS# , _                

                   aspetto $ACK#..." + vbCrLf)

 

    seriale.Output = "$CLS#"

    Do Until aspetta_ack = True

        DoEvents

    Loop

   

 

End Sub

 

'========================================================================

'Questa sub trasmette il comando $RESET#

'========================================================================

Private Sub btnreset_Click()

 

    frm_invio_sequenza.txtlogging = frm_invio_sequenza.txtlogging & "Invio _

                                    comando $RESET# , aspetto $ACK#..."

       

    If seriale.PortOpen = True Then

        seriale.Output = "$RESET#"

        Do Until aspetta_ack = True

            DoEvents

        Loop

        Exit Sub

    End If

 

    seriale.Output = "$RESET#"

    Do Until aspetta_ack = True

        DoEvents

    Loop

 

End Sub

 

'========================================================================

'Questa sub permette di cancellare il contenuto di un fotogramma

'========================================================================

Private Sub cancdis_Click()

 

    'questo ciclo rende tutti i quadretti bianchi ed imposta il loro bit a

    ‘zero

        For X = 0 To quadretto.Count - 1

            quadretto(X).BackColor = 16777215

            quadretto(X).Tag = 0

        Next

 

End Sub

 

'========================================================================

'Questa sub permette di caricare l'animazione da un file

'========================================================================

Private Sub Carica_Click()

 

    Dim cFile As String 'contiene il nome del file da aprire

    Dim nrighe As String 'contiene il numero di righe della griglia

    Dim ncolonne As String 'contiene il numero di colonne della griglia

    Dim nfoto As String 'contiene il numero di fotogrammi dell'animazione

    Dim dato As String 'contiene la riga letta dal file

    Dim indicevett As Integer 'contiene l'indice del vettore

    Dim valore As String 'contiene il valore (0 o 1) di un quadretto

 

    'questo blocco apre la finestra di caricamento file

    ChDrive App.Path

    ChDir App.Path

       

        With aprisalva

            .DialogTitle = "Carica File"

            .CancelError = False

            .Filter = "File Insegna (*.led)|*.led"

            .ShowOpen

               

                If Len(.FileName) = 0 Then

                    Exit Sub

                End If

           

            cFile = .FileName

        End With

 

    '-------------------------------------------------------------------------

    'questo blocco apre il file selezionato e carica la sequenza

   

    Open cFile For Input As #1

    Line Input #1, nrighe

    Line Input #1, ncolonne

    Line Input #1, nfoto

    righe.Text = nrighe

    colonne.Text = ncolonne

       

    Do Until EOF(1)

        Line Input #1, dato

               

            If dato <> "$inizio" And dato <> "&fine" Then

                indicevett = indicevett + 1

                vettoreseq(indicevett) = dato

            End If

    Loop

    Close

 

    '-------------------------------------------------------------------------

    'questo blocco visualizza sulla griglia l'ultimo fotogramma della sequenza

    'caricata

    numfoto = nfoto

    crea.creagr (numfoto)

       

        For X = 0 To quadretto.Count - 1

            k = k + 1

            valore = Mid(vettoreseq(numfoto), k, 1)

               

                Select Case valore

                    Case "0"

                        quadretto(X).Tag = 0

                        quadretto(X).BackColor = 16777215

                    Case "1"

                        quadretto(X).Tag = 1

                        quadretto(X).BackColor = 0

                End Select

        Next

 

End Sub

 

'========================================================================

'Questa sub permette di modificare il numero di colonne della griglia

'========================================================================

Private Sub colonne_Change()

 

    'se il box colonne e' vuoto la sub non viene eseguita

    If colonne.Text = "" Then Exit Sub

 

        'se il box colonne non e' numerico viene generato un messaggio di

        ‘errore

        If IsNumeric(colonne.Text) = False Then

            colonne.Text = 32

            MsgBox "Sono accettati solo valori numerici!"

        End If

 

        'se il box colonne contiene un numero > di 32 o = a 0 viene generato

        ‘un msg di errore

        If colonne.Text > 32 Or colonne.Text = 0 Then

            colonne.Text = 32

            MsgBox "Sono accettati solo valori maggiori di zero e minori o _

                    uguali a 32!"

        End If

 

End Sub

   

'========================================================================

'Questa sub permette di cancellare il contenuto della griglia

'========================================================================

Private Sub cancella_Click()

 

    righe.Enabled = True: colonne.Enabled = True

    quadretto(0).Visible = False

 

        For X = 1 To quadretto.Count - 1 'questo ciclo cancella la griglia

                                      ‘togliendo dalla

            Unload quadretto(X)          'memoria tutti i quadretti

        Next

 

    creagriglia.Enabled = True

    riempi.Enabled = False

    cancdis.Enabled = False

    cancella.Enabled = False

    aggfoto.Enabled = False

    copia.Enabled = False

    incolla.Enabled = False

    indietro.Enabled = False

    avanti.Enabled = False

    anteprima.Enabled = False

    lenta.Enabled = False

    normale.Enabled = False

    veloce.Enabled = False

    invia.Enabled = False

    salva.Enabled = False

    Carica.Enabled = True

       

        For X = 0 To 9999      'questo ciclo svuota la sequenza di fotogrammi

            vettoreseq(X) = ""

        Next

 

    numfoto = 1

    righe.Text = 32

    colonne.Text = 32

 

End Sub

 

 

 

'========================================================================

'========================================================================

Private Sub Command1_Click()

MsgBox numfoto

End Sub

 

'========================================================================

'Questa sub permette di copiare il contenuto della griglia

'========================================================================

Private Sub copia_Click()

   

    buffer = "" 'svuoto il buffer prima di copiare il nuovo disegno

   

        'questo ciclo riempie il buffer con il fotogramma corrente

        For X = 0 To quadretto.Count - 1

            buffer = buffer + quadretto(X).Tag

        Next

   

End Sub

 

'========================================================================

'========================================================================

Private Sub Form_Unload(Cancel As Integer)

 

    End

   

End Sub

 

'=============================================================================

'Questa sub permette di incollare il contenuto della griglia precedentemente copiato

'=============================================================================

Private Sub incolla_Click()

 

    'questo ciclo legge dal buffer i bit del fotogramma che deve essere

    ‘incollato

        For X = 0 To quadretto.Count - 1

            k = k + 1

            valore = Mid(buffer, k, 1)

               

                Select Case valore

                    Case "0"

                        quadretto(X).Tag = 0

                        quadretto(X).BackColor = 16777215

                    Case "1"

                        quadretto(X).Tag = 1

                        quadretto(X).BackColor = 0

                End Select

        Next

 

End Sub

   

'========================================================================

'Questa sub permette di visualizzare il fotogramma precedente

'========================================================================

Private Sub indietro_Click()

 

    Dim j As Integer 'contiene il numero del fotogramma precedente

    Dim k As Integer 'contatore

    Dim mappabit As String 'contiene la mappa dei bit del fotogramma

 

    'se siamo al fotogramma 1 la sub viene saltata

    If etichetta.Caption = 1 Then Exit Sub

 

        'questo blocco salva il fotogramma corrente prima di visualizzare il

        ‘precedente

        For X = 0 To quadretto.Count - 1

            mappabit = mappabit + quadretto(X).Tag

        Next

   

    vettoreseq(etichetta.Caption) = mappabit

    j = Val(etichetta.Caption - 1)

    etichetta.Caption = j

 

        'questo ciclo legge i bit del fotogramma che deve essere visualizzato

        For X = 0 To quadretto.Count - 1

            k = k + 1

            valore = Mid(vettoreseq(j), k, 1)

               

                Select Case valore

                    Case "0"

                        quadretto(X).Tag = 0

                        quadretto(X).BackColor = 16777215

                    Case "1"

                        quadretto(X).Tag = 1

                        quadretto(X).BackColor = 0

                End Select

        Next

 

etichetta.Caption = j

 

End Sub

 

'========================================================================

'Questa sub richiama il modulo di creazione griglia

'========================================================================

Private Sub creagriglia_Click()

 

    crea.creagr (numfoto)

   

End Sub

'========================================================================

'Caricamento del form principale

'========================================================================

Private Sub Form_Load()

   

    numfoto = 1 'siamo direttamente al primo fotogramma

    seriale.CommPort = 1

    seriale.RThreshold = 1

    seriale.Settings = "1200,N,8,1"

    seriale.PortOpen = True

   

End Sub

 

'========================================================================

'========================================================================

Private Sub opcom1_Click()

 

    If (seriale.PortOpen = True) Then

        seriale.PortOpen = False

    End If

   

    seriale.CommPort = 1

    seriale.RThreshold = 1

    seriale.Settings = "1200,N,8,1"

    seriale.PortOpen = True

 

End Sub

 

'========================================================================

'========================================================================

Private Sub opcom2_Click()

 

    If (seriale.PortOpen = True) Then

        seriale.PortOpen = False

    End If

   

    seriale.CommPort = 2

    seriale.RThreshold = 1

    seriale.Settings = "1200,N,8,1"

    seriale.PortOpen = True

End Sub

'========================================================================

'Questa sub annerisce o sbianca un quadretto se viene cliccato

'========================================================================

Private Sub quadretto_Click(Index As Integer)

 

        Select Case quadretto(Index).Tag

            Case 0

                quadretto(Index).BackColor = 0

                quadretto(Index).Tag = 1

            Case 1

                quadretto(Index).BackColor = 16777215

                quadretto(Index).Tag = 0

        End Select

 

End Sub

 

'========================================================================

'Questa sub annerisce o sbianca un quadretto al passaggio del mouse se si

'tiene premuto shift o ctrl

'========================================================================

Private Sub quadretto_MouseMove(Index As Integer, Button As Integer, Shift As_

                                Integer, X As Single, Y As Single)

 

        If Shift = 1 And quadretto(Index).Tag = 0 Then

            quadretto(Index).BackColor = 0

            quadretto(Index).Tag = 1

        End If

 

        If Shift = 2 And quadretto(Index).Tag = 1 Then

            quadretto(Index).BackColor = 16777215

            quadretto(Index).Tag = 0

        End If

End Sub

 

'========================================================================

'Questa sub annerisce tutti i quadretti della griglia

'========================================================================

Private Sub riempi_Click()

 

        For X = 0 To quadretto.Count - 1

            quadretto(X).BackColor = 0

            quadretto(X).Tag = 1

        Next

End Sub

 

'========================================================================

'Questa sub crea messaggi di errore in caso di dati non validi nelle voci

'righe e cononne

'========================================================================

Private Sub righe_Change()

 

    If righe.Text = "" Then Exit Sub

 

        If IsNumeric(righe.Text) = False Then

            righe.Text = 32

            MsgBox "Sono accettati solo valori numerici!"

        End If

 

        If righe.Text > 32 Or righe.Text = 0 Then

            righe.Text = 32

            MsgBox "Sono accettati solo valori maggiori di zero e minori o _

                    uguali a 32!"

        End If

End Sub

 

'========================================================================

'========================================================================

Private Sub ritardo_Timer()

   

ritardo.Enabled = False 'il timer viene disattivato

   

End Sub

 

'========================================================================

'Questa sub permette di salvare l'animazione creata su un file

'========================================================================

Private Sub salva_Click()

 

    Dim sFile As String 'contiene il nome del file

    Dim mappabit As String 'contiene la mappa di bit del fotogramma corrente

    Dim fotogramma As String

 

        'questo blocco salva il fotogramma corrente nel vettore prima di

       ‘salvare il file

        For X = 0 To quadretto.Count - 1

            mappabit = mappabit + quadretto(X).Tag

        Next

 

       vettoreseq(etichetta.Caption) = mappabit

 

        'Questo blocco carica la finestra di salvataggio

        With aprisalva

            .DialogTitle = "Salva File"

            .CancelError = False

            .Filter = "File Insegna (*.led)|*.led"

            .ShowSave

               

                If Len(.FileName) = 0 Then

                    Exit Sub

                End If

           

            sFile = .FileName

        End With

 

    'Questo blocco salva l'animazione sul file

    Open sFile For Output As #1

    Print #1, righe.Text

    Print #1, colonne.Text

    Print #1, Trim(numfoto)

       

        For X = 1 To numfoto

            fotogramma = vettoreseq(X)

            Print #1, "$inizio"

            Print #1, fotogramma

            Print #1, "&fine"

        Next

   

    Close

    MsgBox "File salvato correttamente"

 

End Sub

 

'========================================================================

'========================================================================

Private Sub seriale_OnComm()

 

    buffer_seriale = buffer_seriale + seriale.Input

 

End Sub

 

'========================================================================

'Questa sub richiama il form dei settaggi

'========================================================================

Private Sub settporta_Click()

 

    settaggi.Visible = True

 

End Sub

 

 

 

 

 

 

'========================================================================

'Questa sub invia l'animazione all'insegna

'========================================================================

Private Sub invia_Click()

   

    Dim fotogramma As String

    Dim i As Integer 'contatore di fotogramma

    Dim valbyte As Byte 'contiene il valore del byte da inviare (0 o 1)

 

    If invia.Caption <> "Interrompi" Then

        termina = 0

        invia.Caption = "Interrompi"

        Call disabilita_controlli

    Else

        termina = 1

        invia.Caption = "Invia al panello"

        frm_invio_sequenza.txtlogging = frm_invio_sequenza.txtlogging & _

                                        "TRASMISSIONE INTERROTTA" & vbCrLf

        Call abilita_controlli

        Exit Sub

    End If

       

    ' salva fotogramma corrente

    For i = 0 To quadretto.Count - 1

        mappabit = mappabit + quadretto(i).Tag

    Next

   

    vettoreseq(etichetta.Caption) = mappabit

    frm_invio_sequenza.txtlogging.Text = ""

    frm_invio_sequenza.Visible = True

       

    'spedizione fotogrammi

    For i = 1 To numfoto

        If termina = 1 Then Exit Sub

        fotogramma = vettoreseq(i)

        frm_invio_sequenza.txtlogging.Text = ""

        Call spedisci_fotogramma(fotogramma, i)

        DoEvents

    Next i

   

   

    frm_invio_sequenza.txtlogging.Text = frm_invio_sequenza.txtlogging.Text &_

                                         "TRASMISSIONE COMPLETATA!" & vbCrLf

    invia.Enabled = True

   

    Exit Sub

 

End Sub

 

'========================================================================

'Questa sub invia un fotogramma all'insegna

'

'ATTENZIONE: FUNZIONA SOLO CON INSEGNA 8 x 8

'========================================================================

Private Sub spedisci_fotogramma(fotogramma As String, n As Integer)

 

    Dim i%, counter%, risu%

    Dim a$, dato$, foto_out$

   

   

    If termina = 1 Then Exit Sub

    frm_invio_sequenza.txtlogging.Text = frm_invio_sequenza.txtlogging.Text &_

                           "Invio comando $FOTO# , attendo $ACK#..." & vbCrLf

 

    seriale.Output = "$FOTO#"

   

    Do Until aspetta_ack = True

        If termina = 1 Then Exit Sub

        DoEvents

    Loop

    'Call ritardo_milli(20)

 

    '------------------------------------------------------

    'Fotogramma nella forma:

    ' 1234567812345678.....

    '"1100100101000111...."

    'Lo converto con la seguente logica:

    '1100 1001 --> &hca

    '0100 0111 --> &h47

    'ecc

    '

    foto_out$ = ""

    For i = 1 To 8

        risu = 0

        For j = 1 To 8

            c$ = Mid$(fotogramma, (i - 1) * 8 + j, 1)

            If (c$ = "1") Then

                risu = risu + 2 ^ (j - 1)

            End If

        Next

        foto_out$ = foto_out$ + Chr$(risu)

    Next

    fotogramma = foto_out

   

    counter = 0

 

    For i = 1 To Len(fotogramma)

        a = CStr(Asc(Mid(fotogramma, i, 1))) & vbCrLf

        Call print_txt(frm_invio_sequenza.txtlogging, a)

    Next

 

    For i = 1 To Len(fotogramma)

        If termina = 1 Then Exit Sub

        dato = Mid(fotogramma, i, 1)

 frm_invio_sequenza.txtlogging.Text = _

 frm_invio_sequenza.txtlogging.Text & "Invio byte " & i & " fotogramma

  " & n & " , attendo $ACK#..." & vbCrLf

        a = "Invio byte " & i & " fotogramma " & n & " , attendo $ACK#..." &

            vbCrLf

 

        Call print_txt(frm_invio_sequenza.txtlogging, a)

        seriale.Output = dato

        

        counter = counter + 1

        principale.lbl_counter.Caption = counter

       

        Do Until aspetta_ack = True

            If termina = 1 Then Exit Sub

            DoEvents

        Loop

        'Call ritardo_milli(20)

        DoEvents

    Next i

       

    frm_invio_sequenza.txtlogging.Text = frm_invio_sequenza.txtlogging.Text &

         "Invio comando $ENDFOTO# , attendo $ACK#..." & vbCrLf

 

    seriale.Output = "$ENDFOTO#"

       

    Do Until aspetta_ack = True

        If termina = 1 Then Exit Sub

        DoEvents

    Loop

 

End Sub

 

'=============================================================================

'Questa sub aspetta l'arrivo di $ACK#

'=============================================================================

Private Function aspetta_ack() As Boolean

 

    Dim risultato As String 'contiene la stringa letta dal buffer_seriale

       

    Do

        If termina = 1 Then Exit Function

        risultato = processa_buffer_seriale()

           

        If risultato = "$ACK#" Then

            buffer_seriale = ""

            aspetta_ack = True

            frm_invio_sequenza.txtlogging = frm_invio_sequenza.txtlogging &

                                            "$ACK# ricevuto!" & vbCrLf

            Exit Do

        End If

 

        If risultato = "$NAK#" Then

            buffer_seriale = ""

            aspetta_ack = True

            frm_invio_sequenza.txtlogging = frm_invio_sequenza.txtlogging &

                                            "$ACK# ricevuto!" & vbCrLf

            Exit Do

        End If

 

        If (risultato <> "") Then

            If (InStr(risultato, "$") <> 0) Then

                If (InStr(risultato, "#") <> 0) Then

                    buffer_seriale = ""

                    aspetta_ack = False

                    frm_invio_sequenza.txtlogging =

                    frm_invio_sequenza.txtlogging & "Errore! Stringa ricevuta:

                    " & risultato & vbCrLf

                    Exit Do

                End If

            End If

        End If

       

        DoEvents

    Loop

 

End Function

 

'========================================================================

'Questa function assume il valore stringa letto sul buffer seriale

'========================================================================

Private Function processa_buffer_seriale() As String

 

    If termina = 1 Then Exit Function

   

    processa_buffer_seriale = buffer_seriale

       

End Function

 

'========================================================================

'Questa sub disabilita tutti i controlli che devono essere disabilitati

'========================================================================

Private Sub disabilita_controlli()

   

    Dim i As Integer

   

        On Error Resume Next

        For i = 0 To principale.Count - 1

            principale.Controls(i).Enabled = False

        Next

    invia.Enabled = True

 

End Sub

 

'========================================================================

'Questa sub abilita tutti i controlli che devono essere abilitati

'========================================================================

Private Sub abilita_controlli()

   

    Dim i As Integer

   

        On Error Resume Next

        For i = 0 To principale.Count - 1

            principale.Controls(i).Enabled = True

        Next

   

    righe.Enabled = False

    colonne.Enabled = False

    creagriglia.Enabled = False

    Carica.Enabled = False

 

End Sub

 

'========================================================================

'========================================================================

Sub print_txt(txt As TextBox, testo$)

 

    If (Len(txt.Text) > 32000) Then txt.Text = ""

    txt.Text = txt.Text + testo

    txt.SelStart = Len(txt.Text)

    txt.Refresh

    DoEvents

   

End Sub

 

 

'***************************************************************

'* progetto insegna

'* settaggi.frm

'***************************************************************

Private Sub Conferma_Click()

   

    Dim impostazioni As String 'contiene le impostazioni per la seriale

    Dim p As String ' contiene il valore della parità

   

        Select Case parita.Text

            Case "Nessuna"

                p = "n"

            Case "Pari"

                p = "e"

            Case "Dispari"

                p = "o"

            Case "Mark"

                p = "m"

            Case "Spazio"

                p = "s"

        End Select

   

    'questo blocco applica le impostazioni alla seriale

    impostazioni = impostazioni + baud.Text + "," + p + "," + bitdati.Text +

                   "," + bitstop.Text

    principale.seriale.Settings = impostazioni

    principale.seriale.Handshaking = flusso.ListIndex

    Me.Visible = False

 

End Sub

 

'========================================================================

'Questa sub setta i parametri di default

'========================================================================

Private Sub default_Click()

   

    baud.ListIndex = 6

    parita.ListIndex = 0

    bitdati.ListIndex = 4

    bitstop.ListIndex = 0

    flusso.ListIndex = 0

 

End Sub

 

'========================================================================

'Questa sub setta i parametri di default appena viene caricato il form

'========================================================================

Private Sub Form_Load()

   

    baud.ListIndex = 3

    parita.ListIndex = 0

    bitdati.ListIndex = 4

    bitstop.ListIndex = 0

    flusso.ListIndex = 0

 

End Sub

 

'***************************************************************

'* progetto insegna

'* crea.bas

'***************************************************************

'

 

 

'========================================================================

'Questa sub serve a creare una nuova griglia

'========================================================================

Sub creagr(numfoto)

 

    Dim numrighe As Integer 'contiene il numero delle righe

    Dim numcolonne As Integer 'contiene il numero delle colonne

    Dim totquad As Integer 'contiene il numero totale di quadretti

    Dim conta As Integer 'conta il numero di quadretti che vengono creati

    Dim l As Integer 'contiene la distanza (da sinistra) dal form

    Dim t As Integer 'contiene la distanza (dall'alto) dal form

   

   

    principale.righe.Enabled = False

    principale.colonne.Enabled = False

   

    If principale.righe.Text = "" And principale.colonne.Text = "" Then

        MsgBox "Hai lasciato i campi RIGHE e COLONNE vuoti!"

        principale.colonne.Text = 32

        principale.righe.Text = 32

        principale.righe.Enabled = True

        principale.colonne.Enabled = True

        Exit Sub

    End If

   

    If principale.righe.Text = "" Then

        principale.righe.Text = 32

        MsgBox "Hai lasciato il campo RIGHE vuoto!"

        principale.righe.Enabled = True

        principale.colonne.Enabled = True

        Exit Sub

    End If

   

    If principale.colonne.Text = "" Then

        principale.colonne.Text = 32

        MsgBox "Hai lasciato il campo COLONNE vuoto!"

        principale.righe.Enabled = True

        principale.colonne.Enabled = True

        Exit Sub

    End If

   

    principale.creagriglia.Enabled = False

    principale.quadretto(0).Visible = True

    principale.quadretto(0).BackColor = 16777215

    totquad = principale.righe.Text * principale.colonne.Text

    numrighe = principale.righe.Text: numcolonne = principale.colonne.Text

   

    For X = 1 To totquad - 1 'il ciclo crea la griglia quadretto per quadretto

        conta = conta + 1

        Select Case conta

            Case Is = numcolonne

                'la distanza (da sinistra) del quadretto successivo è uguale a

                 ‘quella del quadretto

                'precedente + la sua larghezza; la distanza (dall'alto)

                 ‘aumenta di un quadretto se

                'si e'raggiunto il numero corretto di colonne.

                l = principale.quadretto(X - 1).Left - 195 * (numcolonne - 1)

                t = principale.quadretto(X - 1).Top + 195

                conta = 0      'il contatore viene azzerato

            Case Is < numcolonne 'se non si è raggiunto il numero corretto di

                                  ‘colonne la distanza

                l = principale.quadretto(X - 1).Left + 195 'dall'alto e'

                                    ‘uguale al quadretto precedente e la

                t = principale.quadretto(X - 1).Top        'distanza da

                               ‘sinistra è uguale a quella del quadretto

        End Select                      'precedente + la sua larghezza

 

        Load principale.quadretto(X) 'il quadretto viene caricato

        With principale.quadretto(X) 'con le proprietà che seguono il with

            .Left = l

            .Top = t

            .Visible = True

            .Tag = 0

            .BackColor = 16777215

        End With

    Next

   

    principale.riempi.Enabled = True

    principale.cancdis.Enabled = True

    principale.cancella.Enabled = True

    principale.aggfoto.Enabled = True

    principale.etichetta.Caption = numfoto

    principale.indietro.Enabled = True

    principale.avanti.Enabled = True

    principale.anteprima.Enabled = True

    principale.lenta.Enabled = True

    principale.normale.Enabled = True

    principale.veloce.Enabled = True

    principale.copia.Enabled = True

    principale.incolla.Enabled = True

    principale.salva.Enabled = True

    principale.invia.Enabled = True

    principale.Carica.Enabled = False

End Sub

 

 

'========================================================================

'========================================================================

Sub ritardo_milli(r%)

 

    Dim old_t!

    Dim dtsec!

   

    dtsec = r / 1000#

    old_t = Timer

    Do

        DoEvents

    Loop While (Timer < old_t + dtsec)

 

End Sub

 

 


Appendice 5

Schema elettrico main board




Appendice 6

Schema elettrico driver LED

 


 


 



Appendice 7

PCB main-board




Appendice 8

PCB driver led




Appendice 9

Data sheet RAM 6264












Appendice 10

Fotografie